leetcode之53最大子序列和Golang

题目描述

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

示例:

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

进阶:

如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。

算法

我的贪心算法

其实这个算法很好理解,但是看起来挺复杂的,所以很垃圾,因为这是我自己写的。。。

主要思想就是遍历数组的时候,我们在什么情况下才会将数组中间的数当作子序列的开头呢?显然,那就是在这个数之前的所有数的和为负数的情况下。遇到这种情况,说明我们叫从下一个数重新开始了,特殊情况就是整个数组都是负数的情况,那么每次都要重新开始,其实就是找出数组中最大的负数。

  • 遍历数组
    • 如果遍历到的数大于0
      • 如果这个数不是数组的最后一个数,那么就将这个数加到当前累加的和上面去
      • 如果这个数是数组的最后一个数,并且当将这个数累加到前面的和之后,那个和比之前最大的和还要大,那么就返回这个累加的和,否则返回之前的最大值
    • 如果遍历到的数小于0
      • 首先判断当前累加的和是不是等于0
        • 如果等于0,这说明了这个数之前的数都不考虑了,可以将这个数当作数组的第一个数开始累加,然后因为这是一个负数,所以直接判断这个数和之前的最大的累加的和谁大,如果这个数大,那么就直接用这个数替换之前累加的最大的和。然后下一个数又要重新被当作数组的第一个数来看待,所以又将当前累加的和重置为0
        • 如果不等于0,先将累加的和与之前的最大值作比较,更新最大值,然后将这个和与当前遍历到的负数相加得到新的累加的和,如果与这个负数累加的和小于0,那么也要将当前的和重置为0,其实这很好理解,就相当于前面是一个负数嘛
  • 最后就得到了最大的和

我的代码

func maxSubArray(nums []int) int {
	maxInt := int(^uint(0) >> 1)
	max, cur := maxInt+1, 0
	for index, value := range nums {
		// 如果当前遍历到的是正数,那么直接加上当前值
		if value > 0 {
			cur += value
			// 如果这是数组最后一个值,那么就要直接计算结果
			if index == len(nums)-1 && cur > max {
				max = cur
			}
		} else {
			if cur == 0 {
				cur = value
				if cur > max {
					max = cur
				}
			}
			// 当前遍历到的是负数,直接先把最大的数据计算保存
			if cur >= max {
				max = cur
			}
			// 如果加上这个负数没有小于0,那么就可以继续加
			if cur+value >= 0 {
				cur += value
			} else {
				// 加上了的当前的数小于0了,那么就重新开始
				cur = 0
			}
		}
	}
	return max
}

官方动态规划

秒啊。。。

其实很简单,就是找出整个数组中,每个元素作为子序列的最后一个数的最大的和

  • 显然第一个元素的和就是它自己本身
  • 第二个元素作为子序列最后一个数的时候,如果第二个元素加上第一个元素对应的最大的子序列的和的和比第二个元素大,那么就第二个元素对应的最大子序列的和就是它与第一个元素对应的最大的子序列的和的,否则就是它自己本身。
  • 然后一直这样循环下去,由前一个元素对应的最大子序列的和可以推导出后一个元素对应的最大子序列的和

官方代码

func maxSubArray(nums []int) int {
    max := nums[0]
    for i := 1; i < len(nums); i++ {
        if nums[i] + nums[i-1] > nums[i] {
            nums[i] += nums[i-1]
        }
        if nums[i] > max {
            max = nums[i]
        }
    }
    return max
}
posted @ 2020-10-13 21:53  胖胖咩  阅读(218)  评论(0)    收藏  举报