PS:腾讯暑期实习二面居然就问了我这个,,,可惜最后还是跪了,唉?
来源于LeetCode第53题:
https://leetcode.com/problems/maximum-subarray/
1.最笨的办法-穷举法
思路就是,取出所有可能的子数组,即找出所有可能的0≤i≤j≤n,然后求出数组从i到j的所有数的和再对比,这样的方法时间复杂度较高,python实现如下:
1 class Solution(object): 2 def maxSubArray(self, nums): 3 """ 4 :type nums: List[int] 5 :rtype: int 6 """ 7 n=len(nums); 8 ans = -100000000000; 9 for i in range(0,n): 10 sums = 0 11 for j in range(i,n): 12 sums += nums[j]; 13 ans=max(ans,sums) 14 return ans
提示超时,最终执行的输入如下:
此时的时间复杂度为O(n^3)
2.第一次优化:
这一步求和的时候,每次没有必要从i到j完整求和,只要存储了上一次求和的结果,之后只要在前面求和的基础上继续累加就可以。
具体方法就是,把sums=0在j循环之前声明,j进行循环时,每次求和是在前一次求和的基础上再加上num[j]:
1 class Solution(object): 2 def maxSubArray(self, nums): 3 """ 4 :type nums: List[int] 5 :rtype: int 6 """ 7 n=len(nums); 8 ans = -100000000000; 9 for i in range(0,n): 10 sums = 0 11 for j in range(i,n): 12 sums += nums[j]; 13 ans=max(ans,sums) 14 return ans
此时超时的结果为,有提升:
时间复杂度此时为O(n^2)
3.第二次优化:贪心算法
计算某串子数组A[i:j],一旦发现sum(A[i:j])<0,那么后面A[i:j+1]之后就无需再计算了,这一组结果一定不满足最大(已经算出了负数,完全可以把这组负数结果抛弃掉,从下一个下标开始算),因此此时应该直接开始算从A[j+1]开始的子数列:
1 class Solution(object): 2 def maxSubArray(self, nums): 3 """ 4 :type nums: List[int] 5 :rtype: int 6 """ 7 n=len(nums); 8 ans = -100000000000; 9 sums = 0; 10 for i in range(0,n): 11 sums = sums+nums[i] 12 ans = max(sums,ans) 13 if sums <= 0 : 14 sums = 0; 15 return ans
结果通过!事实上,此次的时间复杂度只有O(n)