NOTE

连续子数组的最大和

记录《剑指 Offer》“连续子数组的最大和”的原始解题笔记。

Data Structures & Algorithms创建于 更新于 约 1 分钟读完historical

这是历史学习笔记,可能存在过时或不完整的理解。

1. 题目描述

HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)

2. 思路

  • 暴力法
  • 分治
  • 动态规划
  • 试探:如果当前和+当前数<当前数,那么不如从当前数开始继续求和

3. 实现

3.1. 暴力法

//暴力法
//空间:O(1)
//时间:O(N²)
func FindGreatestSumOfSubArray(array []int) int {
	if len(array) == 0 {
		return 0
	}

	max := array[0]
	for i := 0; i < len(array); i++ {
		currentSum := array[i]
		if currentSum > max {
			max = currentSum
		}
		for j := i + 1; j < len(array); j++ {
			currentSum += array[j]
			if currentSum > max {
				max = currentSum
			}
		}
	}

	return max
}

3.2. 分治

//时间复杂度:O(nlogn)
//空间复杂度:O(logn)
func FindGreatestSumOfSubArray4(array []int) int {
	if len(array) == 0 {
		return 0
	}

	return findGreatestSumOfSubArray4(array, 0, len(array)-1)
}

func findGreatestSumOfSubArray4(array []int, begin int, end int) int {
	if end-begin <= 1 {
		return max(array[begin],array[end])
	}

	mid := begin + (end-begin)>>1

	leftMax := array[mid-1]
	leftSum := 0
	for i := mid - 1; i >= begin; i-- {
		leftSum += array[i]
		leftMax = max(leftSum, leftMax)
	}

	rightMax := array[mid]
	rightSum := 0
	for i := mid; i <= end; i++ {
		rightSum += array[i]
		rightMax = max(rightSum, rightMax)
	}
	return max(leftMax+rightMax, findGreatestSumOfSubArray4(array, begin, mid), findGreatestSumOfSubArray4(array, mid, end))
}

func max(data ...int) int {
	max := data[0]
	for i := 1; i < len(data); i++ {
		if data[i] > max {
			max = data[i]
		}
	}
	return max
}

3.3. 动态规划

//动态规划:dp[i] = max(array[i], dp[i-1]+array[i])
//时间复杂度:O(n)
//空间复杂度:O(n)
func FindGreatestSumOfSubArray2(array []int) int {
	if len(array) == 0 {
		return 0
	}

	dp := make([]int, len(array)+1)
	dp[0] = 0
	ret := array[0]
	for i := 1; i <= len(array); i++ {
		dp[i] = Max(array[i-1], dp[i-1]+array[i-1])
		ret = Max(ret, dp[i])
	}
	return ret
}
func Max(a int, b int) int {
	if a < b {
		return b
	}
	return a
}

3.4. 试探

  • java
public class 连续子数组的最大和
{
    public int FindGreatestSumOfSubArray(int[] array)
    {
        //检查参数
        if (array == null || array.length == 0)
        {
            return 0;
        }

        //一个变量记录最大和
        int maxSum = array[0];
        //另一个变量记录当前和
        int currentSum = 0;
        for (int val : array)
        {
            currentSum += val;
            //如果当前和+当前数<当前数,那么不如从当前数开始继续求和
            if (currentSum < val)
            {
                currentSum = val;
            }
            //如果当前和>最大和,替换最大和
            if (currentSum > maxSum)
            {
                maxSum = currentSum;
            }
        }

        return maxSum;
    }
}
  • go
//时间复杂度:O(n)
//空间复杂度:O(1)
func FindGreatestSumOfSubArray3(array []int) int {
	if len(array) == 0 {
		return 0
	}

	max := array[0]
	currentSum := 0
	for i := 0; i < len(array); i++ {
		currentSum += array[i]
		if currentSum < array[i] {
			currentSum = array[i]
		}
		if currentSum > max {
			max = currentSum
		}
	}
	return max
}

func maxSubArray(nums []int) int {
    if len(nums) == 0 {return 0}
    maxSum := nums[0]
    currentSum := 0
    for _, num := range nums {
        currentSum = max(currentSum+num, num)
        maxSum = max(maxSum, currentSum)
    }
    return maxSum
}

func max(a, b int) int {
    if a > b {return a}
    return b
}

4. 参考

讨论

使用 GitHub 账号参与讨论,评论会保存在 GitHub Issues 中。在 GitHub 查看