【算法题】最大子序和

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

子数组 是数组中的一个连续部分。

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

示例 2:
输入: nums = [1] 输出: 1

示例 3:
输入: nums = [5,4,-1,7,8] 输出: 23

  • 提示:
    1 <= nums.length <= 105
    -104 <= nums[i] <= 104

解法(js):

1、暴力解法遍历
求出所有子序列的和,然后从中挑选出最大的。

    const nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4];
    const maxSub = (arr) => {
      let maxSum = arr[0];
      for (let i = 0; i < arr.length; i++) {
        let sum = 0;
        for (let j = i; j < arr.length; j++) {
          sum += arr[j];
          maxSum = Math.max(maxSum, sum);
        }
      }
      console.log(maxSum);
      return maxSum;
    };

2、动态规划
对于最大子序和问题的状态转移方程:

dp[i] = max(nums[i], dp[i-1] + nums[i])

为了理解这个方程是如何确保我们总能获得最大分数的和,我们需要领会动态规划这种算法设计方法的核心思想:最优子结构。

最优子结构是什么意思呢?

在动态规划中,最优子结构意味着一个问题的最优解包含着其子问题的最优解。换句话说,你可以通过组合子问题的最优解来得到整个问题的最优解。

在最大子序和问题中,如果你知道了以nums[i-1]结尾的最大分数和(假设叫它最优子结果),并且现在你面对的新选择是nums[i],那么问题就变成了:

如果这个最优子结果是一个负数,加上nums[i]后总和只会变小,所以我们不如直接从nums[i]开始算起。
如果这个最优子结果是一个正数,那么加上nums[i]后总和会增加,所以我们维持当前子序列,将nums[i]纳入进来。

现在回到状态转移方程。通过持续地更新dp[i],我们总是保持了以nums[i]结尾的最大分数和,对于每一个i:

当你选择nums[i]时,你实际上是重置计数器,从当前这个点开始重新计算子序列(因为你认为之前的序列和对你现在是没帮助的,可能是因为它们是负数)。
当你选择dp[i-1] + nums[i]时,你实际上是选择连续的子序列,并且你相信通过保留之前的序列,新的总和会更大。
该方程确保了你总是取了当前罗列所有可能性中的最大值。通过从左到右遍历数组,你保持了每个子序列的最优解,也因此在每个步骤中,都基于之前的最优解做出了决策。

最终,遍历完成后,数组中包含的dp[i]值中的最大值,就是全局的最大子序和。程序实际上会使用一个变量来记录这个过程中遇到的最大值,因此你不必存储所有的dp[i],只需保持当前的子序列最大和即可。

这样,你可以有信心在完成遍历之后,得到的一定是最大的子序和。这就是动态规划设计方法强大的地方,它确保了你在整个过程中每一步都是基于最优结果做出的选择。

js代码:

const maxSubArrSum = (nums)=>{
	const maxAns = arr[0];
	const pre = arr[0]
	nums.forEach((i) =>{
		pre = Math.max(pre+i,i);   // 如果pre+i < i 说明之前的结果肯定是负数,不如从新的子集开始算
		maxAns = Math.max(pre,maxAns);
	} )
	console.log(maxAns);
	return maxAns;
}
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,以下是我为您准备的100道Java算法: 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. 二叉树的层次遍历 II 27. 二叉树的锯齿形层次遍历 28. 二叉树的最近公共祖先 29. 二叉树的路径和 30. 二叉树的路径和 II 31. 二叉树的所有路径 32. 二叉树的所有路径 II 33. 二叉树的最长连续序列 34. 二叉树的最深叶子节点的最近公共祖先 35. 二叉树的最大路径和 36. 二叉树的最小深度 II 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. 最小栈和最大栈的求众数 II 97. 最小栈和最大栈的求众数 III 98. 最小栈和最大栈的求众数 IV 99. 最小栈和最大栈的求众数 V 100. 最小栈和最大栈的求众数 VI 希望这些算法能够对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

godlike-icy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值