leetcode 学习分享——1 最大子序和
最近焦虑于校招,所以开始刷leetcode,刷到比较有用的心得就记录下来,大家共享~
话不多说直接上题号:53。
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
解题思路:动态规划
动态规划思路分析
其实这是一道很经典的动态规划的题目,只是本人不才,之前只是浅浅了解动态规划的意思,只抓住其形,而不解其神。今日通过此题突然觉得对于动态规划的深层含义有了颠覆式的理解。
对于此题的代码其实就是一个简单的动态规划状态转移方程:
f
(
i
)
=
m
a
x
{
f
(
i
−
1
)
+
n
u
m
[
i
]
,
n
u
m
[
i
]
}
.
f(i) = max\{f(i-1) + num[i], num[i]\}.
f(i)=max{f(i−1)+num[i],num[i]}.
对于动态规划的出现其实就是为了优化暴力破解中出现的重复,对于曾经出现过的解不需要再次访问。而为了能够将重复的解找出来,整理好,通过一定的角度将他们排列起来并通过递归的方式解决掉,我们不能完全按照平时的惯性思维去思考问题。
针对这道题来说,如果说数组为 [ a , b , c , d , e ] [a,b,c,d,e] [a,b,c,d,e] 正常的思维就是从头遍历数组,对于每一位,以他们为头的子序列进行求和,然后取最大值即为结果。但是这样导致时间复杂度会达到 O ( n 2 ) O(n^2) O(n2)。
相反,如果我们换个角度,事情瞬间变化!!!
划重点了!!
从后向前去寻找所有以当前数字为尾的子序列进行求和的话就会得到上述状态转移方程。我们来举例说明:
对于
c
c
c 这个数,以它为尾的子序列有
[
a
,
b
,
c
]
,
[
b
,
c
]
,
[
c
]
[a,b,c],[b,c],[c]
[a,b,c],[b,c],[c]
对于
b
b
b 这个数,以它为尾的子序列有
[
a
,
b
]
,
[
b
]
[a,b], [b]
[a,b],[b]。
写到这里是不是看到一丝端倪了,对, 没错,对于以 i + 1 i + 1 i+1 这个下标的数字为尾的子序列如果记为 L ( i + 1 ) L(i+1) L(i+1) 的话,那 L ( i + 1 ) L(i+1) L(i+1) 就正好等于 L ( i ) L(i) L(i) 所对应的每一个子序列的末尾增加 n u m ( i + 1 ) num(i+1) num(i+1) 这个元素,再加上 n u m ( i + 1 ) num(i+1) num(i+1) 自己构成的单元素序列。
这样就会构成一个很明显的递归关系,也就是
L
(
i
+
1
)
=
L
(
i
)
.
a
p
p
e
n
d
(
n
u
m
[
i
+
1
]
)
+
[
n
u
m
(
i
)
]
L(i+1) = L(i).append(num[i+1]) + [num(i)]
L(i+1)=L(i).append(num[i+1])+[num(i)]
这个递归关系就是这道题动态规划的重点,也是很多数组问题使用动态规划最重要的思想,总结起来就是从后向前,就能够将重复的解空间通过递归的方式表示出来,想通了就会觉得很巧妙。
最大子序列和问题分析
接下来就是对于问题的具体分析了,因为这题找的是最大子序列和,所以如果
f
(
i
)
f(i)
f(i) 表示以
n
u
m
[
i
]
num[i]
num[i] 为尾的子序列和的最大值,那么
f
(
i
)
=
m
a
x
{
f
(
i
−
1
)
+
n
u
m
[
i
]
,
n
u
m
[
i
]
}
.
f(i) = max\{f(i-1) + num[i], num[i]\}.
f(i)=max{f(i−1)+num[i],num[i]}.
这个公式就是类似一个数学归纳法,我只关注当前和上一个状态以及初始状态,就可以将整个问题通过不断推进的方式解决出来。
对于上述例子来说 f ( i ) f(i) f(i) 就是 [ a , b ] , [ b ] [a,b], [b] [a,b],[b] 这两个序列中的最大和,那对于下一个下标得到的所有子序列 [ a , b , c ] , [ b , c ] , [ c ] [a,b,c],[b,c],[c] [a,b,c],[b,c],[c] 来说,除了 [ c ] [c] [c] 剩下的所有序列的最大值其实就是 f ( i ) + c f(i)+c f(i)+c ,因此我们可以得到上述的状态转移方程。
至此,最大子序列和问题得解。
代码
最后上代码:
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
res = nums[0]
t = nums[0]
for i in range(1, len(nums)):
pre = t + nums[i]
t = max(pre, nums[i])
res = max(t, res)
return res
以及结果截图
希望大家有什么意见在评论区多交流,如果在接下来的学习过程中有新的想法也会及时和大家分享。
下期再见喽~