python每日一题练习 最大子数组和

我记得我之前应该写过这个题 但是我打算再写一遍 

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

子数组是数组中的一个连续部分。

找到第一个大于0的开始往后计算 并不是只要前面的总和大于0就是好的 比如示例1 从1开始 到-3 前面加起来小于0 抛弃 从4 开始 加上-1 是3 没事 不要为了舍弃-1 而舍弃4 继续 2 1 到 -5 那么要不要这个-5 取决于-5之后的数字 如果-5之后的数字之和加起来大于5 那么就不要舍弃 如果不是 那么就需要舍弃 但是又疑惑的一点是 那么-5之后可能会出现一个更大的子序列吗?那么这个舍弃与不舍弃如何决定呢?(我对比了我跟我之前写的那个帖子 我觉得我的进步就是我一下子会考虑到很多的情况)

然后我发现这个题目只需要输出最大的这个sum 那么这个其实锻炼不够 我们不如既输出最大值 也输出这个最长子数组 但是我们还是先写输出最大的sum 在这个基础上去找子数组怎么求

想一下咋写 其实你要是看加上这个数字 考虑这个数字之后的会觉得晕晕的 因为后面的数字是暂时看不到的 但是如果我们将后面的数字看为当前的数字 或者说当前数字的前一个数字

之前我们的想法是:现在遇到了一个数 如果这个数字是负数 但是这个数字之后的那个正的很大 那么这个数字可以保留  现在的是 如果当前的数组加上我这个数字 还没我这个数字大 那么我就会舍弃前面的数组 选择我当前的这个数字 这个意思就是抛弃前面的数组 重新开始数组的选择  那如果前面的数组加起来我这个数字 比我这个数字大 那我就继续向后面选择 这其实已经包含了所有的情况了 要么是我重新选择·新的数组 要么就是我继续往后选  (这个就是Kadane's Algorithm(卡丹算法))这个算法 其实有些代码不靠学习这些算法自己想真的想不出来 叹气

其实就是我站在当前元素的角度考虑 不看这个数字对数组造成的影响 只看这个数组对数字造成的影响

那么现在这是当前的选择 其实我说了我要抛弃前面的数组 选择新的数组 那么最后的current就是总和最大的数组吗?当前不是 我们确实是会遇到前面数组不理想的情况 但是是因为前面数组的缘故吗?不是的 是因为我们要抛弃的某个数字的缘故 举个例子 

[-2,1,-3,4,-1,2,1,-5,4] 1 -3 4加起来比 1 -3 要大 所以我们会抛弃 1 -3 从4开始 4 -1 2 1 -5 在没到-5的时候 max是6 然后到-5 current是 1 和 -5之间进行选择 那么选择1 因为对-5来说前面的数组是有用的 那还可以往下 到4 继续往下选择 那么按照这种情况其实数组应该是从4开始的 一直到最后的4 但是max_sum并不是 所以我们还要往前走一步 就要记录一下当前是不是最大的 如果是最大的 我就放在这里不动也不加 记录着

那你会不会疑问 会不会max_sum只记录正的 导致数组跳跃了一些数字 不用担心 current在这里就已经是保证每个元素都会参与 要么就是我要现在的数组 要么就是新开 每个数字都不会跳过去 而max是建立在之前记录的数组和可能的新数组的和 

好了来写代码:

class Solution(object):
    def maxSubArray(self, nums):
        if len(nums)==1:
            return nums
        if max(nums)<=0:
            return max(nums)
        current_sum=nums[0]
        max_sum=nums[0]
        for i in range(1,len(nums)):
            #把目光放长远些 不是你这个数组要不要我这个数字 而是我这个数字要不要你这个数组
            current_sum=max(current_sum+nums[i],nums[i])
            #反正我会记录最大值的那个数组
            max_sum=max(max_sum,current_sum)
        return max_sum
solution=Solution()
result=solution.maxSubArray([5,4,-1,7,8])
print(result)

但是我说了 这个只是记录了最大值 我们要的是最大值所对应的数组  但是有了之前的逻辑就很好写了 如果之前的数组做不了主 那么就换起始点 如果现在新的数组比之前的Max要大 那么起始点就是之前说的那个起始点 终点就是当前的位置 我们只要考虑到这点是绝对正确的 那么其他的情况就不要想那么多了

只要当前子数组能更新最大值,就把它的起止位置记录下来;如果不能贡献最大值,就从当前位置重新开始

class Solution(object):
    def maxSubArray(self, nums):
        if len(nums)==1:
            return nums
        if max(nums)<=0:
            return max(nums)
        current_sum=nums[0]
        max_sum=nums[0]
        first=0
        cur_first=0
        last=0
        for i in range(1,len(nums)):
            #把目光放长远些 不是你这个数组要不要我这个数字 而是我这个数字要不要你这个数组
            if current_sum+nums[i]<nums[i]:
                current_sum=nums[i]
                cur_first=i
            else:
                current_sum+=nums[i]
            if current_sum>max_sum:
                max_sum=current_sum
                first=cur_first
                last=i
        return max_sum,nums[first:last+1]
solution=Solution()
result=solution.maxSubArray([5,4,-1,7,8])
print(result)

我觉得这个思想是很重要的 这个算法真的蛮好 包括对于数组的索引的更新方式 我觉得如果一上来就直接求数组 真的难想 这个其实也就是贪心算法 意思是如果我这个数字加上前面的 还没我这个数字大 那么我就舍弃前面的 这个思想一定要掌握 是我舍弃前面的 而不是说 舍弃我这个数字  反正也有记录全局最优的

但是我觉得我并不算是真正的掌握 之后继续学习

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值