4.1最大子数组问题
在这里提出的题目类似如下:
121. 买卖股票的最佳时机
给定一个数组prices,它的第 i个元素 prices[i]表示一支给定股票第i天的价格。
你只能选择某一天买入这只股票,并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回0。
示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。
提示:
- 1 <= prices.length <= 105
- 0 <= prices[i] <= 104
基本简单解答如下:
class Solution {public int maxProfit(int[] prices) {int min = Integer.MAX_VALUE;int max = 0;for (int i=0;i<prices.length;i++) {if (prices[i] < min) {min = prices[i];}else if (prices[i] - min > max){max = prices[i] - min;}}return max;}}
或者这题:
53. 最大子序和
给定一个整数数组nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
示例 3:
输入:nums = [0]
输出:0
示例 4:
输入:nums = [-1]
输出:-1
示例 5:
输入:nums = [-100000]
输出:-100000
提示:
- 1 <= nums.length <= 3 * 104
-105<= nums[i] <= 105
class Solution {public int maxSubArray(int[] nums) {int ans = nums[0];int max = nums[0];for (int i=1;i<nums.length;i++){max = Math.max(nums[i],max+nums[i]);ans = Math.max(max,ans);}return ans;}}
使用书本中的分治策略代码实现如下:
class Solution {public int maxSubArray(int[] nums) {int len = nums.length;int[] ans = findMaxNum(nums,0,len-1);return ans[2];}public int[] findMaxCrossingSubArray(int[] nums,int low,int mid,int high) {int leftSum = Integer.MIN_VALUE;int sum = 0;int maxLeft = 0;for (int i=mid;i>=low;i--) {sum += nums[i];if (sum > leftSum) {leftSum = sum;maxLeft = i;}}sum = 0;int maxRight = 0;int rightSum = Integer.MIN_VALUE;for(int i=mid+1;i<=high;i++) {sum += nums[i];if (sum>rightSum) {rightSum = sum;maxRight = i;}}return new int[]{maxLeft,maxRight,leftSum+rightSum};}public int[] findMaxNum(int[] nums,int low,int high) {if (low == high) return new int[]{low,high,nums[low]};else {int mid = low + (high-low)/2;int[] left = findMaxNum(nums,low,mid);int[] right = findMaxNum(nums,mid+1,high);int[] cross = findMaxCrossingSubArray(nums,low,mid,high);if (left[2] >= right[2] && left[2] >= cross[2]) {// return new int[]{left[0],left[1],left[2]};return left;}else if (right[2] >= left[2] && right[2] >= cross[2]) {// return new int[]{right[0],right[1],right[2]};return right;}else {return cross;}}}}
