zoukankan      html  css  js  c++  java
  • 剑指Offer_#42_连续子数组的最大和

    剑指offer

    Contents

      • 题目
      • 思路分析
        • 方法1:暴力搜索
        • 方法2:分析规律得到启发式的算法
        • 方法3:动态规划
      • 解答
        • 解法1:暴力搜索
        • 解法2:观察规律
        • 解法3:动态规划

     

    题目

    输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
    要求时间复杂度为O(n)。

    示例1:

    输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
    输出: 6
    解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

    提示:

    1 <= arr.length <= 10^5
    -100 <= arr[i] <= 100

     

    思路分析

     

    方法1:暴力搜索

    两层循环,遍历所有可能的连续子数组,比较得出他们当中最大的连续子数组和。时间超限。面试最好别这么写。

     

    方法2:分析规律得到启发式的算法

    可以从头到尾逐渐计算连续和,分析求最大连续和的过程,如下图。
    [图片]
    发现我们可以用两个变量来保存“累加的数组和”及“最大的数组和”两个数字,在遍历数组的过程中不断更新这两个变量。
    循环结束即可得到最大连续子数组和。

     

    方法3:动态规划

    • 状态定义:dp[i]是以nums[i]作为结尾的连续子数组的最大和。
    • 状态转移:
      • dp[i] = dp[i - 1] + nums[i] (dp[i - 1] > 0)
      • dp[i] = nums[i] (dp[i - 1] <= 0)

    其实这个思路跟方法2写出的代码一摸一样,只不过感觉这样分析更符合“套路”,更通用一些。

     

    解答

     

    解法1:暴力搜索

    class Solution {
        public int maxSubArray(int[] nums) {
            int max = nums[0];
            int sum = nums[0];
            for(int i = 0;i <= nums.length - 1;i++){
                //进入第二层循环之前,sum需要重置,因为这时开始算另一个连续子数组了
                sum = 0;
                for(int j = i; j <= nums.length - 1;j++){
                    //计算从nums[i]开始的所有连续和,作为最大值的候选
                    sum += nums[j];
                    max = Math.max(max, sum);//更新max
                }
            }
            return max;
        }
    }

    超出时间限制。

     

    解法2:观察规律

    class Solution {
        public int maxSubArray(int[] nums) {
            int tmpSum = nums[0];//保存当前的连续和(可能是最大连续和)
            int maxSum = nums[0];//保存结果
            for(int num:nums){
                //如果加上之前的连续还没有当前的num大,就可以抛弃前面的tmpSum了
                tmpSum = Math.max(tmpSum + num,num);
                maxSum = Math.max(tmpSum, maxSum);
            }
            return maxSum;
        }
    }

     

    解法3:动态规划

    class Solution {
        public int maxSubArray(int[] nums) {
            int res = nums[0];//存储结果
            int cur = nums[0];//存储dp[i]
            int pre = 0;//存储dp[i-1]
            for(int num:nums){
                //当dp[i-1] > 0:dp[i] = dp[i-1] + num
                //当dp[i-1] <= 0:dp[i] = num
                cur = num + Math.max(pre, 0);
                res = Math.max(res ,cur);
                //状态更新,本轮循环的cur,是下轮循环的cur
                pre = cur;
            }
            return res;
        }
    }
  • 相关阅读:
    基于摸板匹配的目標跟蹤算法
    spoj 2713 Can you answer these queries IV
    zoj 3633 Alice's present
    hdu 3642 Get The Treasury
    poj 1195 Mobile phones
    poj 2760 End of Windless Days
    zoj 3540 Adding New Machine
    spoj 1716 Can you answer these queries III
    spoj 1043 Can you answer these queries I
    spoj 2916 Can you answer these queries V
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13308876.html
Copyright © 2011-2022 走看看