LeetCode #53 Maximum Subarray
Posted 大峰子的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode #53 Maximum Subarray相关的知识,希望对你有一定的参考价值。
Description
Find the contiguous subarray within an array (containing at least one number) which has the largest sum. Input [-2,1,-3,4,-1,2,1,-5,4] Output 6 //the contiguous subarray [4,-1,2,1] has the largest sum = 6.
思路
CLRS 第四章练习题 4.1-5,动态规划 5 mins 过,时间复杂度 O(n) 。
未优化空间的版本:
class Solution { public: int maxSubArray(vector<int>& nums) { // dp[i] is a state representing max contiguous sum where // the last element is A[i] vector<int> dp; dp.reserve(nums.size()); dp.push_back(nums[0]); int subarray_max_sum = dp[0]; for (int i = 1; i < nums.size(); ++i) { dp[i] = max(dp[i-1] + nums[i], nums[i]); if (subarray_max_sum < dp[i]) { subarray_max_sum = dp[i]; } } return subarray_max_sum; } };
优化空间的版本:
class Solution { public: int maxSubArray(vector<int>& nums) { int dp, sum; dp = nums[0]; sum = nums[0]; for (int i = 1; i < nums.size(); i++) { if (dp > 0) { dp += nums[i]; } else dp = nums[i]; if (dp > sum) sum = dp; } return sum; } };
用分治法再做了一遍。它的思路是: A[low..high] 的连续子数组A[i..j]的位置必然是下面三种情况之一:
1.完全位于子数组 A[low..mid] 中,low <= i <= j <= mid
2.完全位于子数组 A[mid+1..high] 中,mid+1 <= i <= j <= high
3.跨越了中点 mid ,low <= i <= mid < j <= high
前两个情况仍是最大子数组问题,只不过规模更小,所以可以递归求解。而最后一种情况加入了中点的限制,不易递归求解,所以线性扫描。
算法时间复杂度是 O(n·lgn)
#include <iostream> #include <limits.h> #include <vector> using namespace std; class Solution { public: int maxSubArray(vector<int>& nums) { int res = findMaxSubarray (nums, 0, nums.size()-1); nums.clear(); vector<int>().swap(nums); return res; } private: int findMaxSubarray (vector<int>& nums, const int& low, const int& high) { if (low == high) return nums[low]; //base case: only one element else { int mid =low + (high-low)/2; int left_sum = findMaxSubarray (nums, low, mid); int right_sum = findMaxSubarray (nums, mid + 1, high); int cross_sum = findMaxCrossingSubarray (nums, low, high); // chose the max case of them if (left_sum >= right_sum && left_sum >= cross_sum) return left_sum; else if (right_sum >= left_sum && right_sum >= cross_sum) return right_sum; else return cross_sum; } } int findMaxCrossingSubarray (vector<int>& nums, const int& low, const int& high) { int left_sum = INT_MIN; int sum = 0; int mid = low + (high-low)/2; for (int i = mid; i >= low; --i) { sum += nums[i]; if (left_sum < sum) left_sum = sum; } int right_sum = INT_MIN; sum = 0; for (int i = mid+1; i <= high; ++i) { sum += nums[i]; if (right_sum < sum) right_sum = sum; } return left_sum + right_sum; } };
最后一点是经验之谈。用递归的话写起来很舒服,但是 BUG 不好改,出错的一般都是 segment fault (core dump) 。我发现了一种很好的办法去解决这种问题,由于每次发生段错误系统会产生 .core 文件记录发生的位置,所以我们在 gdb 调试时候把它带上就知道导致段错误的位置在哪、出错的数据是多少了。我的是 Ubuntu 系统,不像 Redhat 可以直接产生 core 文件,所以要先输入 ulimit -c unlimited 打开生成 core 文件的选项。举个例子,如下:
图片来源:博客
以上是关于LeetCode #53 Maximum Subarray的主要内容,如果未能解决你的问题,请参考以下文章