53.最大子序和

题目:53.最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

解题思路

设置两个变量,一个变量用来记录当前最大值,一个用来记录全局最大值
通过循环来遍历数组。以子数组的最后一个位置作为指针。

解法一:暴力算法

用两次for循环来遍历数组
时间复杂度O(n^2)

#C#
class Solution {
    public int maxSubArray(int[] nums) {
        int max = nums[0];   #全局最大
        for (int i = 0; i < nums.length; i++) {
            int temp = 0; #当前最大
            for (int j = i; j < nums.length; j++) {
                temp += nums[j];
                if (temp > max) max = temp;
            }

        }
        return max;
    }
}

解法二:贪心算法

该算法通用且简单:遍历数组并在每个步骤中更新
对于初学者比较难理解的就是curr_sum
curr_sum并不是全局最大值,它比较出来的是截至到这个位置包括这个元素的子序和的最大值,是局部的。

#python
class Solution:
    def maxSubArray(self, nums: 'List[int]') -> 'int':
        n = len(nums)
        curr_sum = max_sum = nums[0]

        for i in range(1, n):
            curr_sum = max(nums[i], curr_sum + nums[i])
            max_sum = max(max_sum, curr_sum)
          #curr_sum比较当前元素及包括当前元素位置的局部最大和
          #max_sum记录全局最大子序和
        return max_sum

时间复杂度:O(N)。只遍历一次数组。
空间复杂度:O(1),只使用了常数空间。

解法三:动态规划(DP)

DP法和贪心算法差不多,DP直接更改原本数组减少内存,相当于把
curr_sum直接储存在nums中,即nums[i]等价于curr_sum.

#python
class Solution:
    def maxSubArray(self, nums: 'List[int]') -> 'int':
        n = len(nums)
        max_sum = nums[0]
        for i in range(1, n):
            if nums[i - 1] > 0:
                nums[i] += nums[i - 1] 
                #沿数组移动并修改数组,令当前元素为局部最大值
            max_sum = max(nums[i], max_sum)

        return max_sum

时间复杂度:O(N)。只遍历一次数组。
空间复杂度:O(1),只使用了常数空间。

解法四:分治法

将一个数组对半分为左子数组和右子数组,则它的最大子序必然是以下情况中的一个:

  • 全部在左子数组
  • 全部在右子数组
  • 穿过左右子数组
    通过维护四个量:
    以 左子数组的最左元素为左端点的最大子段和 【Lsum】
    以 右子数组的最右元素为右端点的最大子段和 【Rsum】
    以 左子数组的最右元素为右端点的最大子段和 【lsum】
    以 右子数组的最左元素为左端点的最大子段和 【rsum】
    其中【Lsum】、【Rsum】、【lsum+rsum】的最大值为原数组的最大子序和

用递归的方法,将原数组分成长度为1的子数组,使得每个元素都是某个子数组的最左元素/最右元素,然后回升的得到原数组的最大子序和。

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 1:
            return nums[0]
        else:
            max_left = self.maxSubArray(nums[0:len(nums) // 2])
            max_right = self.maxSubArray(nums[len(nums) // 2:len(nums)])
       
        #计算穿过中间的最大子序和
        max_l = nums[len(nums) // 2 - 1] #左数组的最右元素
        tmp = 0
        for i in range(len(nums) // 2 - 1, -1, -1):
            tmp += nums[i]
            max_l = max(tmp, max_l) #左数组的包含最右元素的最大子序和
        max_r = nums[len(nums) // 2]
        tmp = 0
        for i in range(len(nums) // 2, len(nums)):
            tmp += nums[i]
            max_r = max(tmp, max_r)
        
        #返回三个中的最大值
        return max(max_right,max_left,max_l+max_r)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值