题目来源
题目描述
class Solution {
public:
/**
* @param nums: a list of integers
* @return: A integer indicate the sum of minimum subarray
*/
int minSubArray(vector<int> &nums) {
// write your code here
}
};
题目解析
暴力
双层for循环,第一层for设置起始位置,第二层for遍历数组寻址最大值
class Solution {
public:
/**
* @param nums: a list of integers
* @return: A integer indicate the sum of minimum subarray
*/
int minSubArray(vector<int> &nums) {
int result = INT32_MAX;
int count = 0;
for (int i = 0; i < nums.size(); ++i) {
count = 0;
for (int j = i; j < nums.size(); ++j) {
count += nums[j];
result = count < result ? count : result;
}
}
return result;
}
};
动态规划
思路一
(1)状态
dp[i]
:表示以 n u m s [ i ] nums[i] nums[i]结尾的连续子数组的最小和
(2)状态转移方程
- 根据状态的定义:由于
nums[i]
一定会被选取,并且以nums[i]
结尾的连续子数组与以nums[i-1]
结尾的连续子数组只相差一个元素nums[i]
- 假设数组
nums
的值全部严格小于0,那么一定有dp[i] = dp[i - 1] + nums[i]
- 可是
dp[i - 1]
可能是正数,于是分类讨论:- 如果
d
p
[
i
−
1
]
<
=
0
dp[i - 1] <= 0
dp[i−1]<=0,那么(负数 + 负数 --> 值更小)
nums[i]
可以直接接在dp[i - 1]
表示的那个数组的后面,得到和更小的连续子数组: d p [ i ] = d p [ i − 1 ] + n u m s [ i ] dp[i] = dp[i - 1] + nums[i] dp[i]=dp[i−1]+nums[i] - 如果 d p [ i − 1 ] > 0 dp[i - 1] > 0 dp[i−1]>0 ,有两种可能,也就是: d p [ i ] = n u m s [ i ] dp[i] = nums[i] dp[i]=nums[i]
- 如果
d
p
[
i
−
1
]
<
=
0
dp[i - 1] <= 0
dp[i−1]<=0,那么(负数 + 负数 --> 值更小)
(3)初始化数组
- dp[0] = nums[0]
(4)返回值
- 这里状态的定义不是题目中的问题的定义,不能直接将最后一个状态返回回去;
- 这个问题的输出是把所有的 dp[0]、dp[1]、……、dp[n - 1] 都看一遍,取最小值。
class Solution {
public:
/**
* @param nums: a list of integers
* @return: A integer indicate the sum of minimum subarray
*/
int minSubArray(vector<int> & nums){
int len = nums.size();
std::vector<int> dp (len, 0); // dp[i] 表示:以 nums[i] 结尾的连续子数组的最大和
dp[0] = nums[0];
for (int i = 1; i < nums.size(); ++i) {
if(dp[i - 1] < 0 ){ // 要之前的值
dp[i] = dp[i - 1] + nums[i];
}else{
dp[i] = nums[i]; // 不要之前的值
}
}
int res = dp[0];
for (int j = 1; j < dp.size(); ++j) {
if(dp[j] < res){
res = dp[j];
}
}
return res;
}
};
(5)空间优化
思路二
(1)状态
dp[i]
:表示以 n u m s [ i ] nums[i] nums[i]结尾的连续子数组的最小和
(2)推导状态转移方程
- 考虑ni单独成为一段还是加入dp(i - 1)对应的那一段
- 这取决于ni以及dp[i - 1] + ni的大小。因此
dp[i] = std::min(dp[i - 1] + ni, ni)
(3)初始状态
- dp[0] 根据定义,只有 1 个数,一定以 nums[0] 结尾,因此 dp[0] = nums[0]
(4)返回值
- 这里状态的定义不是题目中的问题的定义,不能直接将最后一个状态返回回去;
- 这个问题的输出是把所有的 dp[0]、dp[1]、……、dp[n - 1] 都看一遍,取最小值。
int minSubArray(vector<int> & nums){
if (nums.empty()) return 0;
vector<int> dp(nums.size(), 0); // dp[i]表示包括i之前的最大连续子序列和
dp[0] = nums[0];
int result = dp[0];
for (int i = 1; i < nums.size(); i++) {
dp[i] = min(dp[i - 1] + nums[i], nums[i]); // 状态转移公式
if (dp[i] < result) result = dp[i]; // result 保存dp[i]的最大值
}
return result;
}
贪心算法