python求解连续子数组的最大和(暴力、动态规划、贪心、分治)
目录
1 问题
2 测试用例
3 求解
3.1 暴力1
3.2 暴力2
3.3 暴力3
3.4 动态规划
3.5 贪心算法
3.6 分治
1 问题
给定一个整数数组 nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组[4,-1,2,1] 的和最大,为6 。示例 2:
输入:nums = [1]
输出:1示例 3:
输入:nums = [0]
输出:0示例 4:
输入:nums = [-1]
输出:-1示例 5:
输入:nums = [-100000]
输出:-100000提示:
1 <= nums.length <= 3 * 104
-105 <= nums[i] <= 105进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。
2 测试用例
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4] # 6
# nums = [0]
# nums = [-1, -2]
# nums = [1]
# nums = [-100000]
# nums = [5, 4, -1, 7, 8] # 23
# nums = [2, -1, 2, 1, 3, -2, 1, 2, 1, -2] # 9
# nums = [9, -4, 2, -5, 8] # 10
# nums = [-1,-2]
3 求解
3.1 暴力1
解析:
分别计算子数组个数为1,2,...n 时最大子数组和。每个子数组和都计算一遍。
代码:
# 我的题解: 暴力方法超时"""举例,不断取最大 max-2 1 -3 4 -1 2 1 -5 4 4-1 -2 1 3 1 3 -4 -1 3-4 2 0 5 2 -2 -8 50 1 2 6 -3 2 6-1 3 3 1 1 31 4 -2 5 52 -1 2 2-3 3 31 1"""def maxSubArray1(self, nums: List[int]):arr = [num for num in nums]max_num = max(nums)if len(nums) == 1:return max_numfor i in range(0, len(nums) - 1):arr.pop(len(arr) - 1)for j in range(len(arr)):arr[j] = arr[j] + nums[j + 1 + i]max_num = max(max_num, max(arr))return max_num
3.2 暴力2
解析:
将数组转化为 正负......正负正 的形式,可以加快 暴力求解速度。
代码:
# 我的题解: 暴力方法 未超时"""1. 两个相邻的数同号可以合并2. 如果两端有负数,去掉,保证正数占段头段尾由此转化成正负数相间的形式""""""执行用时:3048 ms, 在所有 Python3 提交中击败了5.06%的用户内存消耗:15.4 MB, 在所有 Python3 提交中击败了47.65%的用户"""def maxSubArray2(self, nums: List[int]):# 数组中没有正数就没有合并的必要了tag = Falsefor num in nums:if num > 0:tag = Trueif not tag:return max(nums)# 合并相邻同号的数i = 0while i < len(nums) - 1:if nums[i] * nums[i + 1] >= 0: # 有0的话也合并nums[i] += nums[i + 1]nums.pop(i + 1)continuei += 1# 去头尾负数if nums[0] < 0:nums.pop(0)if nums[len(nums) - 1] < 0:nums.pop(len(nums) - 1)# 求最大max_num = 0length = len(nums)for k in range(0, length, 2): # 以偶数的形式迭代, 由nums[k]起始sum_num = nums[k]max_num = max(max_num, sum_num)for i in range(2, length, 2): # nums[k]后的i个数if k + i < length:sum_num += nums[k + i] + nums[k + i - 1]max_num = max(max_num, sum_num)return max_num
3.3 暴力3
解析:
不断在数组中加入一个新数,每加入一个新数,计算一下当前最大的子序和。
代码:
# 我的题解: 暴力方式 超出时间限制, 没有突破到动态规划的方法上是因为,复用了以前数列的最大子序和,而不是以某个数结尾的最大子序和def maxSubArray3(self, nums: List[int]):# 已有数组中加入一个新数后,计算该数组的最大子序和def func(nums, num, max_num):new_max = float("-inf")sum_num = numfor i in range(len(nums) - 1, -1, -1):sum_num += nums[i]new_max = max(new_max, sum_num)return max(max_num, num, new_max)if len(nums) == 1:return nums[0]max_num = nums[0] # 当前数组最大子序和new_nums = []new_nums.append(nums[0])for i in range(1, len(nums)):max_num = func(new_nums, nums[i], max_num)new_nums.append(nums[i])return max_num
3.4 动态规划
解析:
https://leetcode-cn.com/problems/maximum-subarray/solution/zui-da-zi-xu-he-by-leetcode-solution/
代码:
# 动态规划"""执行用时:44 ms, 在所有 Python3 提交中击败了57.49%的用户内存消耗:15.2 MB, 在所有 Python3 提交中击败了92.81%的用户"""def maxSubArray4(self, nums: List[int]):pre = 0 # 以某个数结尾的最大数组和max_nums = nums[0] # 当前数组的最大子序和for num in nums:pre = max(pre + num, num) # 不断迭代 pre 十分关键max_nums = max(max_nums, pre)return max_nums
3.5 贪心算法
解析:
https://leetcode-cn.com/problems/maximum-subarray/solution/hua-jie-suan-fa-53-zui-da-zi-xu-he-by-guanpengchn/
代码:
# 贪心算法"""如果 sum > 0,则说明 sum 对结果有增益效果,则 sum 保留并加上当前遍历数字如果 sum <= 0,则说明 sum 对结果无增益效果,需要舍弃,则 sum 直接更新为当前遍历数字""""""执行用时:36 ms, 在所有 Python3 提交中击败了87.58%的用户内存消耗:15.6 MB, 在所有 Python3 提交中击败了15.76%的用户"""def maxSubArray5(self, nums: List[int]):max_nums = nums[0]sum = 0for num in nums:sum = sum + num if sum > 0 else nummax_nums = max(max_nums, sum)return max_nums
3.6 分治
解析:
https://leetcode-cn.com/problems/maximum-subarray/solution/zui-da-zi-xu-he-by-leetcode-solution/
代码:
# 分治"""lSum 表示 [l,r][l,r] 内以 ll 为左端点的最大子段和rSum 表示 [l,r][l,r] 内以 rr 为右端点的最大子段和mSum 表示 [l,r][l,r] 内的最大子段和iSum 表示 [l,r][l,r] 的区间和""""""执行用时:72 ms, 在所有 Python3 提交中击败了5.01%的用户内存消耗:15.4 MB, 在所有 Python3 提交中击败了42.36%的用户"""def maxSubArray6(self, nums: List[int]):# 查询序列arr[l,r]的最大字段和 左闭右闭def getInfo(arr, l, r):if l == r:return Status(arr[l], arr[l], arr[l], arr[l])mid = int((l + r) / 2)lSub = getInfo(arr, l, mid)rSub = getInfo(arr, mid + 1, r)iSum = lSub.iSum + rSub.iSumlSum = max(lSub.lSum, lSub.iSum + rSub.lSum) # lSum = max(lSub.lSum, lSub.lSum + rSub.lSum)rSum = max(lSub.rSum + rSub.iSum, rSub.rSum)mSum = max(lSub.mSum, rSub.mSum, lSub.rSum + rSub.lSum)return Status(lSum, rSum, mSum, iSum)return getInfo(nums, 0, len(nums) - 1).mSum
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
