找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 21198|回复: 5

不限语言解决“最大子列和问题”

[复制链接]
发表于 2019-10-30 09:33:36 | 显示全部楼层 |阅读模式
数学符号语言描述:

文字描述:
最大子数列问题的目标是在数列的一维方向找到一个连续的子数列,使该子数列的和最大。例如,对一个数列 −2, 1, −3, 4, −1, 2, 1, −5, 4,其连续子数列中和最大的是 4, −1, 2, 1, 其和为6。
若最大子列和为负,则结果取0。

相关链接:百度百科

附一个分治法的(非最优解法,时间复杂度O(nlogn),已有O(n)的算法;仅作分治思想练习)

Option Explicit
Dim Arr
Arr = Array(4,-3,5,-2,-1,2,6,-2) '为11
WScript.Echo Max(MaxSubseqSum(1,1,UBound(Arr) + 1),0)

Arr = Array(-2,1,-3,4,-1,2,1,-5,4) '为6
WScript.Echo Max(MaxSubseqSum(1,1,UBound(Arr) + 1),0)

Function MaxSubseqSum(ByVal ptrListStart,ByVal ptrListMiddle,ByVal ptrListEnd)
    Dim numMaxLeft,numMaxRight,numMaxUnion
   
    Rem 求左半段最大子列和。
    If ptrListStart = ptrListMiddle Then '只有一个元素
        numMaxLeft = GetItem(Arr,ptrListStart)
    Else
        If (ptrListMiddle - ptrListStart + 1) Mod 2 = 0 Then '有偶数个元素,平均分配
            numMaxLeft = MaxSubseqSum(ptrListStart,(ptrListStart + ptrListMiddle - 1)\2,ptrListMiddle)
        Else '有奇数个元素,左半段分配一个,右半段分配剩下的
            numMaxLeft = MaxSubseqSum(ptrListStart,ptrListStart,ptrListMiddle)
        End If
    End If
   
    Rem 求右半段最大子列和。
    If ptrListEnd - ptrListMiddle = 1 Then '只有一个元素
        numMaxRight  = GetItem(Arr,ptrListEnd)
    Else
        If (ptrListEnd - ptrListMiddle) Mod 2 = 0 Then '偶数个元素
            numMaxRight = MaxSubseqSum(ptrListMiddle + 1,(ptrListMiddle + ptrListEnd)\2,ptrListEnd)
        Else
            numMaxRight = MaxSubseqSum(ptrListMiddle + 1,ptrListMiddle + 1,ptrListEnd)
        End If
    End If
   
    Rem 求左右合并最大子列和。
    Rem 左半边。
    Dim ptrNow,numUnionNow,numMaxUnionLeft,numMaxUnionRight
    numUnionNow = 0
    numMaxUnionLeft = 0
    For ptrNow = ptrListMiddle To ptrListStart Step -1
        numUnionNow = numUnionNow + GetItem(Arr,ptrNow)
        numMaxUnionLeft = Max(numMaxUnionLeft,numUnionNow)
    Next
    Rem 右半边。
    numUnionNow = 0
    numMaxUnionRight = 0
    For ptrNow = ptrListMiddle + 1 To ptrListEnd
        numUnionNow = numUnionNow + GetItem(Arr,ptrNow)
        numMaxUnionRight = Max(numMaxUnionRight,numUnionNow)
    Next
    Rem 求合并。
    numMaxUnion = numMaxUnionLeft + numMaxUnionRight
   
    Rem 左半段、右半段、左右合并取最大。
    MaxSubseqSum = Max(Max(numMaxLeft,numMaxRight),numMaxUnion)
End Function

Function GetItem(Arr,Ptr) '手动构造从1开始的数组
    GetItem = Arr(Ptr - 1)
End Function

Function Max(ByVal Num1,ByVal Num2)
    If Num1 > Num2 Then
        Max = Num1
    Else
        Max = Num2
    End If
End Function
发表于 2019-10-30 13:05:59 | 显示全部楼层
凑个数

  1. Function Get-MaxSum([double[]]$int) {
  2.         $tmp = 0;
  3.         if ($int.Count -eq 1) {
  4.                 if ($int[0] -lt 0) { return 0 }else { return $int[0] }
  5.         }
  6.         for ($i = 0; $i -lt $int.Count - 1; $i++) {
  7.                 $sum = $int[$i];
  8.                 for ($j = $i + 1; $j -lt $int.Count; $j++) {
  9.                         $sum += $int[$j];
  10.                         if ($sum -ge $tmp) { $tmp = $sum }
  11.                 }
  12.         }
  13.         return $tmp;
  14. }
  15. Get-MaxSum 4, -3, 5, -2, -1, 2, 6, -2
  16. Get-MaxSum -2,1,-3,4,-1,2,1,-5,4
复制代码
========说实话 都没弄清题意 ===========

评分

参与人数 1技术 +1 收起 理由
老刘1号 + 1 双循环,时间复杂度O(n2),简单直观

查看全部评分

发表于 2019-10-30 18:08:16 | 显示全部楼层
记得以前做过这道题

  1. pub fn find_max_squence(v: &[i32]) -> i32 {
  2.     let mut max_sum = 0;
  3.     let mut tmp_sum = 0;
  4.     for i in v {
  5.         tmp_sum = (tmp_sum + i).max(0);
  6.         max_sum = max_sum.max(tmp_sum);
  7.     }
  8.     max_sum
  9. }
复制代码
在线体验: https://play.rust-lang.org/?vers ... f4a9e2439dca3ea1117

评分

参与人数 1技术 +1 收起 理由
老刘1号 + 1 O(n),nice

查看全部评分

发表于 2019-10-30 21:58:24 | 显示全部楼层
pub fn find_max_squence(v: &[i32]) -> i32 {
    let mut max_sum = 0;
    let mut tmp_sum = 0;
    for i in v {
        tmp_sum = (tmp_sum + i).max(0);
        max_sum = max_sum.max(tmp_sum);
    }
    max_sum
}


我也来试试代码高亮
话说 Windows 上能识别 monospace 字体么? (上面代码是不是等宽的
 楼主| 发表于 2019-10-30 22:10:25 | 显示全部楼层
回复 4# bailong360


    显示的是等宽的233
发表于 2019-10-30 22:14:58 | 显示全部楼层
以前我也碰到过,印象中是这样?
  1. @echo off & setlocal enabledelayedexpansion
  2. set /a min=0, result=0
  3. for %%i in (-2, 1, -3, 4, -1, 2, 1, -5, 4) do (
  4.     set /a sum+=%%i, tmpSum=sum-min
  5.     if !result! LSS !tmpSum! set "result=!tmpSum!"
  6.     if !min! GTR !sum! set "min=!sum!"
  7. )
  8. if !result! LSS 0 set "result=0"
  9. echo;!result!
  10. pause
复制代码

评分

参与人数 1技术 +1 收起 理由
老刘1号 + 1 这题还真是出名

查看全部评分

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-3-16 19:16 , Processed in 0.023076 second(s), 8 queries , File On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表