Leetcode53. 最大子序和
题目:
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
题解:
方法一:暴力法
两个for循环
时间复杂度 O(n2),空间复杂度 O(n)
scala代码如下:
def maxSubArray(nums: Array[Int]): Int = {
var sum = nums(0)
for (i <- 0 until nums.length) {
var tmp = 0
for (j <- i until nums.length) {
tmp = tmp + nums(j)
if (tmp > sum) {
sum = tmp
}
}
}
sum
}
方法二:动态规划法
动态规划的是首先对数组进行遍历,当前最大连续子序列和为 sum,结果为 ans
如果 sum > 0,则说明 sum 对结果有增益效果,则 sum 保留并加上当前遍历数字
如果 sum <= 0,则说明 sum 对结果无增益效果,需要舍弃,则 sum 直接更新为当前遍历数字
每次比较 sum 和 ans的大小,将最大值置为ans,遍历结束返回结果
时间复杂度:O(n)
scala代码如下:
def maxSubArray2(nums: Array[Int]): Int = {
var tmp = nums(0)
var sum = tmp
for (j <- 1 until nums.length) {
// 当当前序列加上此时的元素的值大于tmp的值,说明最大序列和可能出现在后续序列中,记录此时的最大值
if (tmp > 0) {
tmp = tmp + nums(j)
sum = Math.max(sum, tmp)
} else {
// 当tmp(当前和)小于下一个元素时,当前最长序列到此为止。以该元素为起点继续找最大子序列,
// 并记录此时的最大值
tmp = nums(j)
sum = Math.max(sum, tmp)
}
}
sum
}
方法三:分治法
java代码如下:
public int maxSubArray(int[] nums) {
//分治法
//每层递归将数组均匀分成两半,三种情况:
//1.最大子序和在左边
//2.最大子序和在右边
//3.最大子序和横跨左右
return maxSubArray1(nums, 0, nums.length - 1);
}
public int maxSubArray1(int[] nums, int l, int r) {
//分解到只有一个数时,返回该值
if (l == r)
return nums[l];
int mid = (l + r) / 2;
//递归求左右最大子序和
int resL = maxSubArray1(nums, l, mid);
int resR = maxSubArray1(nums, mid + 1, r);
/**
从mid向两边求最大子序和maxSumL,maxSumR,第三种情况最大子序和是maxSumL + maxSumR
*/
int maxSumL = nums[mid];
int maxSumR = nums[mid + 1];
int sumL = 0;
int sumR = 0;
//计算mid左边的最大子序和
for (int i = mid; i >= l; i--) {
sumL += nums[i];
if (sumL > maxSumL)
maxSumL = sumL;
}
//计算mid右边的最大子序和
for (int j = mid + 1; j <= r; j++) {
sumR += nums[j];
if (sumR > maxSumR)
maxSumR = sumR;
}
int resM = maxSumL + maxSumR;
//返回resL, resM, resR三者最大值
return Math.max(resM, (resL > resR ? resL : resR));
}