Я предполагаю, что ваши вопросы - найти непрерывный подмассив (содержащий хотя бы одно число), который имеет наибольшую сумму.Иначе, проблема довольно тривиальна, так как вы можете просто выбрать все положительные числа.
Есть 3 решения, которые лучше, чем решение с грубой силой O (N ^ 2).N - длина входного массива.
- Динамическое программирование.O (N) время выполнения, O (N) пробел
Поскольку подмассив содержит хотя бы одно число, мы знаем, что существует только N возможных кандидатов: подмассив, заканчивающийся на A [0], A [1] ...... A [N - 1] Для подмассива, заканчивающегося в A [i], мы имеем следующую оптимальную подструктуру: maxSum [i] = max of {maxSum [i - 1] + A [i], A [i]};
class Solution {
public int maxSubArray(int[] nums) {
int max = Integer.MIN_VALUE;
if(nums == null || nums.length == 0) {
return max;
}
int[] maxSum = new int[nums.length + 1];
for(int i = 1; i < maxSum.length; i++) {
maxSum[i] = Math.max(maxSum[i - 1] + nums[i - 1], nums[i - 1]);
}
for(int i = 1; i < maxSum.length; i++) {
max = Math.max(maxSum[i], max);
}
return max;
}
}
Префиксная сумма, O (N) время выполнения, O (1) пробел
Поддерживайте переменную минимальной суммы при выполнении итерации по всему массиву.При посещении каждого числа во входном массиве обновите переменную суммы префикса currSum.Затем обновите максимальную и минимальную суммы, указанные в следующем коде.
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0) {
return 0;
}
int maxSum = Integer.MIN_VALUE, currSum = 0, minSum = 0;
for(int i = 0; i < nums.length; i++) {
currSum += nums[i];
maxSum = Math.max(maxSum, currSum - minSum);
minSum = Math.min(minSum, currSum);
}
return maxSum;
}
}
Разделяй и властвуй, O (N * logN) время выполнения
Разделите исходную задачу на две подзадачи и рекурсивно примените этот принцип, используя следующую формулу.
Пусть A [0, .... midIdx] будет левой половиной A, A [midIdx + 1, ..... A.length - 1] будет правой половиной A. leftSumMax - ответ левой подзадачи, rightSumMax - этоОтвет правильной подзадачи.
Окончательный ответ будет одним из следующих 3: 1. используются только числа из левой половины (решается левой подзадачей) 2. используются только числа из правой половины (решается правой подзадачей) 3. использует числа из левой и правой половин (решается за O (n) раз)
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0)
{
return 0;
}
return maxSubArrayHelper(nums, 0, nums.length - 1);
}
private int maxSubArrayHelper(int[] nums, int startIdx, int endIdx){
if(startIdx == endIdx){
return nums[startIdx];
}
int midIdx = startIdx + (endIdx - startIdx) / 2;
int leftMax = maxSubArrayHelper(nums, startIdx, midIdx);
int rightMax = maxSubArrayHelper(nums, midIdx + 1, endIdx);
int leftIdx = midIdx, rightIdx = midIdx + 1;
int leftSumMax = nums[leftIdx], rightSumMax = nums[rightIdx];
int leftSum = nums[leftIdx], rightSum = nums[rightIdx];
for(int i = leftIdx - 1; i >= startIdx; i--){
leftSum += nums[i];
leftSumMax = Math.max(leftSumMax, leftSum);
}
for(int j = rightIdx + 1; j <= endIdx; j++){
rightSum += nums[j];
rightSumMax = Math.max(rightSumMax, rightSum);
}
return Math.max(Math.max(leftMax, rightMax), leftSumMax + rightSumMax);
}
}