Постановка задачи
Для целочисленного массива nums найдите непрерывный подмассив (содержащий хотя бы одно число) с наибольшей суммой и верните его сумму.
Описание проблемы взято из: https://leetcode.com/problems/maximum-subarray
Пример 1:
Input: nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
Output: 6
Explanation: [4, -1, 2, 1] has the largest sum = 6.
Пример 2:
Input: nums = [1]
Output: 1
Пример 3:
Input: nums = [5, 4, -1, 7, 8]
Output: 23
Ограничения:
- 1 <= nums.length <= 3 * 10^4 -
-10^5 <= nums[i] <= 10^5
Объяснение
Грубая сила
Подход грубой силы состоит в том, чтобы сгенерировать все подмассивы и распечатать тот подмассив, который имеет максимальную сумму.
Фрагмент приведенной выше логики на C ++ выглядит следующим образом:
for (int i = 0; i < n; i++){
for (int j = i; j < n; j++){
for (int k = i; k <= j; k++){
// calculate sum of all the elements
}
}
}
Временная сложность описанного выше подхода составляет O (N³). Мы можем улучшить приведенную выше логику с помощью алгоритма Кадане.
Алгоритм Кадане
Простая идея алгоритма Кадане состоит в том, чтобы искать все положительные смежные сегменты массива (для этого используется max_sum
). И отслеживайте максимальную сумму смежных сегментов среди всех положительных сегментов (для этого используется max_sum_so_far
). Каждый раз, когда мы получаем положительную сумму, сравниваем ее с max_sum
и обновляем max_sum
, если она больше max_sum_so_far
.
Давайте проверим алгоритм ниже:
- set max_sum_so_far = 0, max_sum = INT_MIN
- Loop for i = 0; i < nums.length; i++
- add max_sum_so_far = max_sum_so_far + nums[i]
- if max_sum < max_sum_so_far
- set max_sum = max_sum_so_far
- if max_sum_so_far < 0
- set max_sum_so_far = 0
- return max_sum
Временная сложность описанного выше подхода составляет O (N), а пространственная сложность - O (1).
Решение C ++
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int max_sum = INT_MIN;
int max_sum_so_far = 0;
for(int i = 0; i < nums.size(); i++){
max_sum_so_far += nums[i];
if(max_sum < max_sum_so_far){
max_sum = max_sum_so_far;
}
if(max_sum_so_far < 0){
max_sum_so_far = 0;
}
}
return max_sum;
}
};
Решение Golang
func maxSubArray(nums []int) int {
maxSum := math.MinInt32
maxSumSoFar := 0
for i := 0; i < len(nums); i++ {
maxSumSoFar += nums[i]
if maxSum < maxSumSoFar {
maxSum = maxSumSoFar
}
if maxSumSoFar < 0 {
maxSumSoFar = 0
}
}
return maxSum
}
Решение Javascript
var maxSubArray = function(nums) {
let maxSumSoFar = 0;
let maxSum = -Infinity;
if(nums.length === 0) return 0;
if(nums.length === 1) return nums[0]
for( let i = 0; i<nums.length; i++) {
maxSumSoFar += nums[i];
maxSum = Math.max(maxSum, maxSumSoFar);
if(maxSumSoFar < 0) {
maxSumSoFar = 0;
}
}
return maxSum;
};
Давайте проверим наш алгоритм, чтобы увидеть, как работает решение.
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
Step 1: max_sum_so_far = 0
max_sum = INT_MIN
Step 2: for i = 0; i < nums.length
0 < 9
true
max_sum_so_far += nums[0]
max_sum_so_far = 0 + -2
max_sum_so_far = -2
max_sum < max_sum_so_far
-2^31 - 1 < -2
true
max_sum = max_sum_so_far
max_sum = -2
max_sum_so_far < 0
-2 < 0
true
max_sum_so_far = 0
i++
i = 1
Step 3: i < nums.length
1 < 9
true
max_sum_so_far += nums[1]
max_sum_so_far = 0 + 1
max_sum_so_far = 1
max_sum < max_sum_so_far
-2 < 1
true
max_sum = max_sum_so_far
max_sum = 1
max_sum_so_far < 0
1 < 0
false
i++
i = 2
Step 4: i < nums.length
2 < 9
true
max_sum_so_far += nums[2]
max_sum_so_far = 1 + -3
max_sum_so_far = -2
max_sum < max_sum_so_far
1 < -2
false
max_sum_so_far < 0
-2 < 0
true
max_sum_so_far = 0
i++
i = 3
Step 5: i < nums.length
3 < 9
true
max_sum_so_far += nums[3]
max_sum_so_far = 0 + 4
max_sum_so_far = 4
max_sum < max_sum_so_far
1 < 4
true
max_sum = max_sum_so_far
max_sum = 4
max_sum_so_far < 0
false
i++
i = 4
Step 6: i < nums.length
4 < 9
true
max_sum_so_far += nums[4]
max_sum_so_far = 4 + -1
max_sum_so_far = 3
max_sum < max_sum_so_far
4 < 3
false
max_sum_so_far < 0
false
i++
i = 5
Step 7: i < nums.length
5 < 9
true
max_sum_so_far += nums[5]
max_sum_so_far = 3 + 2
max_sum_so_far = 5
max_sum < 5
4 < 5
true
max_sum = max_sum_so_far
max_sum = 5
max_sum_so_far < 0
false
i++
i = 6
Step 8: i < nums.length
6 < 9
true
max_sum_so_far += nums[6]
max_sum_so_far = 5 + 1
max_sum_so_far = 6
max_sum < 6
5 < 6
true
max_sum = max_sum_so_far
max_sum = 6
max_sum_so_far < 0
false
i++
i = 7
Step 9: i < nums.length
7 < 9
true
max_sum_so_far += nums[7]
max_sum_so_far = 6 + -5
max_sum_so_far = 1
max_sum < 6
6 < 1
false
max_sum_so_far < 0
false
i++
i = 8
Step 10: i < nums.length
8 < 9
true
max_sum_so_far += nums[8]
max_sum_so_far = 1 + 4
max_sum_so_far = 5
max_sum < 6
6 < 5
false
max_sum_so_far < 0
false
i++
i = 9
Step 11: i < nums.length
9 < 9
false
Step 12: return max_sum
Answer is 6
Первоначально опубликовано на https://alkeshghorpade.me.