LeetCode 53. 最大子序和 Maximum Subarray(C語言)
阿新 • • 發佈:2018-12-27
題目描述:
給定一個整數陣列 nums ,找到一個具有最大和的連續子陣列(子陣列最少包含一個元素),返回其最大和。
示例:
輸入: [-2,1,-3,4,-1,2,1,-5,4],
輸出: 6
解釋: 連續子陣列 [4,-1,2,1] 的和最大,為 6。
進階:
如果你已經實現複雜度為 O(n) 的解法,嘗試使用更為精妙的分治法求解。
題目解答:
方法1:暴力法
求每個數字到其後每個數字的連續和,求出最大值。
執行時間200ms左右,程式碼如下。
int maxSubArray(int* nums, int numsSize) {
int i = 0, j = 0;
int max = nums[0];
for(i = 1; i < numsSize; i++) {
nums[i] = nums[i] + nums[i - 1];
if(max < nums[i])
max = nums[i];
}
for(i = 0; i < numsSize; i++) {
for(j = i + 1; j < numsSize; j++) {
if(nums[j] - nums[ i] > max)
max = nums[j] - nums[i];
}
}
return max;
}
方法2:動態規劃
sum
儲存使用上一個數字的連續和,sum
加上當前位置數字,如果和大於0,則說明可以繼續向後;小於0則說明,當前位置是一個負數,應該從下一個數字重新開始。同時也要不斷更新max
。
執行時間4ms,程式碼如下。
int maxSubArray(int* nums, int numsSize) {
int i = 0, sum = 0;
int max = nums[0];
for (i = 0; i < numsSize; i++) {
sum += nums[i];
if(max < sum)
max = sum;
if(sum < 0)
sum = 0;
}
return max;
}
方法3:貪心法
尋找從開始位置的最小和,開始位置到當前位置連續和與其前邊的最小值差值sum - min
,即為到當前位置前邊的最大連續和。
執行時間4ms,程式碼如下。
int maxSubArray(int* nums, int numsSize) {
int i = 0, sum = 0, min = 0;
int max = nums[0];
for(i = 0; i < numsSize; i++) {
sum += nums[i];
if(sum - min > max)
max = sum - min;
if(sum < min)
min = sum;
}
return max;
}
方法4:分治法
分成子問題解決。結構體中l
表示陣列中以最左側數字起的連續最大值,max
表示陣列中的連續最大值,r
表示陣列中以最右側數字為終點的連續最大值,sum
表示陣列之和。
執行時間4ms,程式碼如下。
struct val {
int l;
int max;
int r;
int sum;
};
#define max(a, b) (a > b ? a : b)
#define min(a, b) (a > b ? b : a)
struct val maxSub(int* nums, int n) {
if(n == 1) {
struct val t = {nums[0], nums[0], nums[0], nums[0]};
return t;
}
struct val v1 = maxSub(nums, n / 2);
struct val v2 = maxSub(nums + n / 2, n - n / 2);
int l = max(v1.l, v1.sum + v2. l);
int max = max(max(v1.max, v2.max), v1.r + v2.l);
int r = max(v2.r, v1.r + v2.sum);
int sum = v1.sum + v2.sum;
struct val t = {l, max, r, sum};
return t;
}
int maxSubArray(int* nums, int numsSize) {
struct val v = maxSub(nums, numsSize);
return v.max;
}