• 53. 最大子序和


    给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

    示例:

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

    推荐参考:https://blog.csdn.net/zwzsdy/article/details/80029796https://blog.csdn.net/u014472643/article/details/81097672

      1 public class MaxSubArray {
      2     //方法一:扫描法,从头遍历数组,对于数组中每一个元素,要么加入之前的数组(加入其它组),要么自己开始(单开一组)
      3     //如果之前的组结果为负,则应该自己开始一个新的组,因为自己的值比加入后的值还要大。O(N)
      4     public int maxSubArray1(int[] array) {
      5         if(array.length == 0) {
      6             throw new IllegalArgumentException("输入参数错误");
      7         }
      8         if(array.length == 1) {
      9             return array[0];
     10         }
     11         int len = array.length;
     12         int[] res = new int[len];
     13         res[0] = array[0];
     14         int max = res[0];
     15         for(int i=1; i<len; i++) {
     16             //数组res记录连续数组的和,如果大于0,则加入该连续数组,小于0,重新开始新的连续数组
     17             if(res[i-1] > 0) {
     18                 res[i] = res[i-1] + array[i];
     19             }else {
     20                 res[i] = array[i];
     21             }
     22             max = Math.max(res[i], max);
     23         }
     24         return max;        
     25     }
     26     //方法二:暴力法,依次计算每个子数组的和,选择其中最大的子数组,时间复杂度为n^3
     27     public int maxSubArray2(int[] array) {
     28         if(array.length == 0) {
     29             throw new IllegalArgumentException("输入参数错误");
     30         }
     31         int len = array.length;
     32         int sum = 0;
     33         int max = array[0];  //只有一个元素时最大值即为该元素
     34         for(int i=0; i<len; i++) {
     35             for(int j=i; j<len; j++) {  //单个元素也是子数组,需要包括
     36                 for(int k=i; k<=j; k++) {
     37                     sum += array[k];
     38                 }
     39                 if(sum > max) {
     40                     max = sum;
     41                 }
     42                 sum = 0;
     43             }
     44         }
     45         return max;
     46     }
     47     //方法二:暴力法改进,在第三层循环中,每次都要计算上次已经计算的序列,发生了重复计算,所以可以在前一次的计算的基础上
     48     //相加,减少一层循环,时间复杂度为n^2
     49     public int maxSubArray22(int[] array) {
     50         if(array.length == 0) {
     51             throw new IllegalArgumentException("输入参数错误");
     52         }
     53         int len = array.length;
     54         int sum = 0;
     55         int max = array[0];
     56         for(int i=0; i<len; i++) {
     57             for(int j=i; j<len; j++) {
     58                 sum += array[j];
     59                 if(sum > max) {
     60                     max = sum;
     61                 }
     62             }
     63             sum = 0;
     64         }
     65         return max;
     66     }
     67     //方法三:分治法,将整个数组一直拆分至单个元素,从下往上得到最大值。
     68     //把数组分成两个序列,最大连续子序列和要么在左半部分,要么在右半部分,要么是横跨左右部分
     69     public int maxSubArray3(int[] array) {
     70         if(array.length == 0) {
     71             throw new IllegalArgumentException("输入参数错误");
     72         }
     73         return maxSubArrayPart(array, 0, array.length - 1);
     74     }
     75     private int maxSubArrayPart(int[] array, int left, int right) {
     76         //递归出口
     77         if(left == right) {
     78             return array[left];
     79         }
     80         int mid = (left + right) / 2;
     81         //左半部分最大值
     82         int maxLeft = maxSubArrayPart(array, left, mid);
     83         //右半部分最大值
     84         int maxRight = maxSubArrayPart(array, mid+1, right);
     85         
     86         //跨边界最大值,必定包括左半部分的最后一个元素,以及右半部分的第一个元素
     87         //边界以左
     88         int sum = 0;
     89         int maxLeftBorder = array[mid];
     90         for(int i=mid; i>=left; i--) {
     91             sum += array[i];
     92             if(sum > maxLeftBorder) {
     93                 maxLeftBorder = sum;
     94             }
     95         }
     96         //边界以右
     97         sum = 0;
     98         int maxRightBorder = array[mid+1];
     99         for(int i=mid+1; i<=right; i++) {
    100             sum += array[i];
    101             if(sum > maxRightBorder) {
    102                 maxRightBorder = sum;
    103             }
    104         }
    105         int maxBorder = maxLeftBorder + maxRightBorder;
    106 //        return Math.max(Math.max(maxRight, maxLeft), maxBorder);  //两者皆可
    107         return (maxRight>maxLeft) ? (maxRight>maxBorder ? maxRight : maxBorder) 
    108                 : (maxLeft>maxBorder ? maxLeft : maxBorder);
    109     }
    110     
    111     //方法四:动态规划(动态规划三要素:最优子结构(递归方程)、边界条件(终止条件)和状态转移方程(前两者总结))
    112     //对于第i个元素,有两种选择,要么加入已存在的连续子数组,要么只包括自己开启新的连续子数组。判断条件是前面已经
    113     //存在的连续子数组和是否大于0。
    114     //状态转移方程:dp = max[arr[i], arr[i] + sum]
    115     public int maxSubArray4(int[] array) {
    116         //边界条件
    117         int sum = array[0];
    118         
    119         int result = array[0];
    120         for(int i=1; i<array.length; i++) {
    121             if(sum > 0) {
    122                 sum += array[i];
    123             }else {
    124                 sum = array[i];
    125             }
    126             if(sum > result) {
    127                 result = sum;
    128             }
    129         }
    130         return result;
    131     }
    132     
    133 }
    无论有多困难,都坚强的抬头挺胸,人生是一场醒悟,不要昨天,不要明天,只要今天。不一样的你我,不一样的心态,不一样的人生,顺其自然吧
  • 相关阅读:
    unittest框架assert断言
    python logging 总结
    好文章推荐 数据库mysql
    python 日志模块 日志格式
    django admin 后台总结(转载)
    xpath解析html标签
    lua 排序table.sort()用法
    lua 随机数 math.random()和math.randomseed()用法
    三种方法获取 lua时间戳
    crontab调用python脚本新思路
  • 原文地址:https://www.cnblogs.com/xiyangchen/p/10890709.html
Copyright © 2020-2023  润新知