|
| 1 | +/* |
| 2 | + * @Author: Chacha |
| 3 | + * @Date: 2022-04-18 14:53:00 |
| 4 | + * @Last Modified by: Chacha |
| 5 | + * @Last Modified time: 2022-04-18 15:19:30 |
| 6 | + */ |
| 7 | + |
| 8 | +/** |
| 9 | + * 来源:https://leetcode-cn.com/problems/maximum-subarray/ |
| 10 | + * |
| 11 | + * 53. 最大子数组和 |
| 12 | + * 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 |
| 13 | + * 子数组 是数组中的一个连续部分。 |
| 14 | + * |
| 15 | + * 示例 1: |
| 16 | + * 输入:nums = [-2,1,-3,4,-1,2,1,-5,4] |
| 17 | + * 输出:6 |
| 18 | + * 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。 |
| 19 | + * |
| 20 | + * 示例 2: |
| 21 | + * 输入:nums = [1] |
| 22 | + * 输出:1 |
| 23 | + * |
| 24 | + * 示例 3: |
| 25 | + * 输入:nums = [5,4,-1,7,8] |
| 26 | + * 输出:23 |
| 27 | + * |
| 28 | + * 提示: |
| 29 | + * 1 <= nums.length <= 10^5 |
| 30 | + * -10^4 <= nums[i] <= 10 |
| 31 | + * |
| 32 | + */ |
| 33 | + |
| 34 | +#include <iostream> |
| 35 | +#include <vector> |
| 36 | + |
| 37 | +using namespace std; |
| 38 | + |
| 39 | +class Solution |
| 40 | +{ |
| 41 | +private: |
| 42 | + /* data */ |
| 43 | +public: |
| 44 | + int maxSubArray(vector<int> &nums); |
| 45 | +}; |
| 46 | + |
| 47 | +/** |
| 48 | + * 贪心解法 |
| 49 | + * |
| 50 | + * 贪心贪的是哪里呢?如果 -2 1 在一起,计算起点的时候,一定是从 1 开始计算,因为负数只会拉低总和,这就是贪心贪的地方。 |
| 51 | + * |
| 52 | + * 局部最优解:当前"连续和"为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上一个元素“连续和”只会越来越小。 |
| 53 | + * 全局最优:选取最大“连续和” |
| 54 | + * |
| 55 | + * 从代码角度上来讲:遍历 nums,从头开始用 count 累积,如果 count 一旦加上 nums[i] 变为附属,那么就应该从 nums[i + 1] 开始 |
| 56 | + * 从 0 累积 count 了,因为已经变为负数的 count,只会拖累总和。 |
| 57 | + * |
| 58 | + * 这相当于是暴力解法中的不断调整最大子序和区间的起始位置。如何才能得到最大“连续和”呢? |
| 59 | + * 区间的终止位置,其实就是如果count取到最大值了,及时记录下来了。例如如下代码: |
| 60 | + * if (count > result) result = count; |
| 61 | + * 这样相当于是用result记录最大子序和区间和(变相的算是调整了终止位置)。 |
| 62 | + * |
| 63 | + */ |
| 64 | +int Solution::maxSubArray(vector<int> &nums) |
| 65 | +{ |
| 66 | + int result = INT32_MIN; |
| 67 | + int count = 0; |
| 68 | + |
| 69 | + for (int i = 0; i < nums.size(); i++) |
| 70 | + { |
| 71 | + count += nums[i]; |
| 72 | + |
| 73 | + if (count > result) |
| 74 | + { |
| 75 | + // 取区间累计的最大值(相当于不断确定最大子序终止位置) |
| 76 | + result = count; |
| 77 | + } |
| 78 | + |
| 79 | + if (count <= 0) |
| 80 | + { |
| 81 | + // 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和 |
| 82 | + count = 0; |
| 83 | + } |
| 84 | + } |
| 85 | + |
| 86 | + return result; |
| 87 | +}; |
| 88 | + |
| 89 | +int main(int argc, char const *argv[]) |
| 90 | +{ |
| 91 | + Solution s; |
| 92 | + vector<int> nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4}; |
| 93 | + vector<int> nums1 = {5, 4, -1, 7, 8}; |
| 94 | + |
| 95 | + std::cout << "[-2, 1, -3, 4, -1, 2, 1, -5, 4]最大子数组和: " << s.maxSubArray(nums) << std::endl; |
| 96 | + std::cout << "[5, 4, -1, 7, 8]最大子数组和: " << s.maxSubArray(nums1) << std::endl; |
| 97 | + |
| 98 | + return 0; |
| 99 | +} |
0 commit comments