风雨雾凇 风雨雾凇
首页
  • 服务端

    • golang
  • 其他

    • leetcode
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

风雨雾凇

技术小渣渣
首页
  • 服务端

    • golang
  • 其他

    • leetcode
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • golang

  • 技术文档

  • GitHub技巧

  • Nodejs

  • 博客搭建

  • leetcode

    • 两数之和-1
    • 无重复字符的最长子串-3
    • 整数翻转-7
    • 回文数-9
    • 13-罗马数字转整数
    • 最长公共前缀
    • 3Sum
    • Valid Parentheses
    • Merge Two Sorted Lists
    • Remove Duplicates from Sorted Array
    • Remove Element
    • Implement strStr()
    • Search Insert Position
    • Count and Say
    • 字符串相乘
    • Maximum Subarray
      • Length of Last Word
      • Plus One
      • Add Binary
      • Sqrt(x)
      • 翻转字符串里的单词
      • 字符串的排列
    • 机器学习

    • 技术
    • leetcode
    风雨雾凇
    2020-02-22
    目录

    Maximum Subarray

    # 题目

    Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
    
    Example:
    
    Input: [-2,1,-3,4,-1,2,1,-5,4],
    Output: 6
    Explanation: [4,-1,2,1] has the largest sum = 6.
    Follow up:
    
    If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
    
    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/maximum-subarray
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    # 解答思路

    求最大子序列和。

    # 1. 暴力法

    双层for循环遍历所有子序列求和。时间复杂度O(n^2)

    # 2. 动态规划

    动态规划重点在于写出隐含的推导公式。dp指当前索引的最大值。时间复杂度O(n)。

    # 当前节点最大值 = max(上一节点最大值 + 当前节点值, 当前节点值)
    Dp[i] = max(dp[i-1] +num[i], num[i])
    
    1
    2

    即当上一节点最大值为负数时,放弃之前节点,从当前节点开始。

    # 3. 贪心法

    翻版动态规划,使用max变量记录最大值则无需dp数组。

    # 4. 分治法

    时间复杂度O(nlog(n))

    将数组分为左右中三部分,左右分别可以通过递归到单个元素解决。重点在于求中间数组的子序列最大值。

    其值等于左边部分的最右边开始的最大值 + 右边部分的最左边开始的最大值(与单独贪心不同,求和值必须是连续的,因为计算的是中间开始的子串的最大值)。

    # 注意项

    建壮性编写

    • 当数据为空时返回0
    • 数组全是负数返回最小负数,初始化max使用负无穷或数组第一个元素。

    # 代码

    package easy
    
    import (
    	"fmt"
    	"testing"
    )
    
    /**
    Given an integer array nums, find the contiguous subarray (containing at least one number)
    which has the largest sum and return its sum.
    
    Example:
    
    Input: [-2,1,-3,4,-1,2,1,-5,4],
    Output: 6
    Explanation: [4,-1,2,1] has the largest sum = 6.
    Follow up:
    
    If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
    
    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/maximum-subarray
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    */
    
    func maxInt(a, b int) int {
    	if a > b {
    		return a
    	}
    	return b
    }
    
    // 动态规划 重点为推导式 dp[i] = max(nums[i], dp[i-1] + nums[i]) dp为在每个位置上的最大子串和
    func maxSubArray(nums []int) int {
    	if len(nums) == 0 {
    		return 0
    	}
    	dp := make([]int, len(nums))
    	dp[0] = nums[0]
    	for i := 1; i < len(nums); i++ {
    		dp[i] = maxInt(nums[i], dp[i-1]+nums[i])
    	}
    	// 遍历dp数组查找遍历到那个节点中值最大
    	max := dp[0]
    	for _, d := range dp {
    		max = maxInt(max, d)
    	}
    	return max
    }
    
    // 贪心法 实际为动态规划 使用max记录数组中最大值
    func maxSubArray2(nums []int) int {
    	if len(nums) == 0 {
    		return 0
    	}
    	sum, max := nums[0], nums[0]
    	for i := 1; i < len(nums); i++ {
    		sum = maxInt(nums[i], nums[i]+sum)
    		max = maxInt(sum, max)
    	}
    	return max
    }
    
    // 分治法
    func maxSubArray3(nums []int) int {
    	// 递归出口
    	numsLen := len(nums)
    	if numsLen == 0 {
    		return 0
    	}
    	if numsLen == 1 {
    		return nums[0]
    	}
    	// 递归处理左边最大值
    	leftMax := maxSubArray3(nums[:numsLen/2])
    	// 递归处理右边最大值
    	rightMax := maxSubArray3(nums[numsLen/2:])
    
    	// 使用贪心法处理中间最大值 分别从 中心向左右拓张查找最大值 符合分治思路
    	// 中心往左最大值
    	leftStart := numsLen/2 - 1
    	lSum, lMax := nums[leftStart], nums[leftStart]
    	for i := leftStart - 1; i >= 0; i-- {
    		lSum = nums[i] + lSum // 此处应该直接相加 因为不能再从单前节点开始 中间往外拓展应是连续的
    		lMax = maxInt(lSum, lMax)
    	}
    
    	// 中心往右最大值
    	rightStart := numsLen / 2
    	rSum, rMax := nums[rightStart], nums[rightStart]
    	for i := rightStart + 1; i < len(nums); i++ {
    		rSum = nums[i] + rSum
    		rMax = maxInt(rSum, rMax)
    	}
    	return maxInt(maxInt(leftMax, rightMax), lMax+rMax)
    }
    
    func TestMaxSubArray(t *testing.T) {
    	fmt.Println(maxSubArray([]int{-2, 1, -3, 4, -1, 2, 1, -5, 4}))
    	fmt.Println(maxSubArray([]int{-1}))
    
    	fmt.Println(maxSubArray2([]int{-2, 1, -3, 4, -1, 2, 1, -5, 4}))
    
    	fmt.Println(maxSubArray3([]int{-2, 1, -3, 4, -1, 2, 1, -5, 4}))
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    编辑 (opens new window)
    #面试#学习笔记#leetcode
    上次更新: 2023/02/17, 16:53:03
    字符串相乘
    Length of Last Word

    ← 字符串相乘 Length of Last Word→

    最近更新
    01
    builtin
    02-12
    02
    导读
    02-12
    03
    13-罗马数字转整数
    01-30
    更多文章>
    Theme by Vdoing | Copyright © 2017-2023 风雨雾凇 | 粤ICP备16018321号-2
    博客内容遵循署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式