本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
输入: [-2,1,-3,4,-1,2,1,-5,4]输出: 6解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。进阶:
方法1 暴力法:
思路: (略)
时间复杂度: O(n^2)
空间复杂度: O(1)
// 暴力法:
int maxSubArray(vector<int>& nums) {
int max = INT_MIN; // 初始值一定要定义成理论上的最小最大值
int numsSize = nums.size(); // 不用每次计算长度,效率更高,耗时更少
for (int i = 0; i < numsSize/*nums.size()*/; i++)
{
int sum = 0;
for (int j = i; j < numsSize/*nums.size()*/; j++)
{
sum += nums[j];
max = max > sum ? max : sum;
}
}
return max;
}
方法2 动态规划:
思路:
dp[i]表示nums中以nums[i]结尾的最大子序和,dp[i]有两种可能的情况,取较大者:
(1)要么是当前数字numsi,
(2)要么是每一轮循环中的前n项和更大(每一轮循环中的前n项和大于当前数nums[i],注意外循环起点不同)
时间复杂度: O(n)
空间复杂度: O(1) 空间复杂度可优化至O(1),因为只需要知道dp的前一项,可以用int代替一维数组
// dp(内存优化版,一位数组代替):
int maxSubArray(vector<int>& nums) {
int dp = nums[0]; // 如果输入是[1]的话,则返回nums[0]
int maxVul = dp;
for (int i = 1; i < nums.size(); i++)
{ // dp[i]表示nums中以nums[i]结尾的最大子序和
dp = max(nums[i], nums[i] + dp); // 因为只需要知道dp的前一项,可以用int代替一维数组
maxVul = max(maxVul, dp);
}
return maxVul;
}
// 使用dp数组(相对于上面方式,浪费内存空间)
int maxSubArray(vector<int>& nums) {
int maxVul = 0;
//dp[i]表示nums中以nums[i]结尾的最大子序和
vector<int> dp(nums.size()); // 一定要分配大小才行
dp[0] = nums[0]; // 如果输入是[1]的话,则返回nums[0]
maxVul = dp[0];
for (int i = 1; i < nums.size(); i++) // i从1开始才能有前一项dp[i - 1],且dp[0]已经定义过了
{
dp[i] = max(dp[i - 1] + nums[i], nums[i]);
maxVul = max(maxVul, dp[i]);
}
return maxVul;
}
编辑
方法3 分治法和贪心法(贪心法感觉类似于dp):
以后有时间研究~