zoukankan      html  css  js  c++  java
  • leetcodeF42 连续子数组的最大和

      首先暴力搜索:

        public final int maxSubArray1(int[] nums) {
            int max = Integer.MIN_VALUE;
            for (int i = 0; i < nums.length; i++) {
                for (int j = 0; j < nums.length - i; j++) {
                    int temp = 0;
                    for (int k = i; k <= i + j; k++) {
                        temp += nums[k];
                    }
                    max = Math.max(max, temp);
                }
            }
            return max;
        }

    * @Description nums 的大小决定问题规模,按 nums 大小分割问题
    * 因为求任意子数组,按区间对 nums 进行分段
    * G(start,end) 表示 start 开头, end 结尾的数组的和
    * 尝试列出状态转移方程:
    * G(start,end)=G(start,end-1)+nums[end]
    * start==end 时,以 nums[start] 回归
    * 如果建立缓存,则缓存空间类似线段树,存储了各个区间的区间和
    * 但基于数组长度最大可能达到 10 的 5 次方,因此数组缓存不可取,可用 哈希表 进行缓存

    int max = Integer.MIN_VALUE;
    
    public final int maxSubArray2(int[] nums) {
            Map<String, Integer> cache = new HashMap<String, Integer>();
            for (int i = 0; i < nums.length; i++) {
                maxSubArray(nums, i, nums.length - 1, cache);
            }
            return max;
        }
    
        public int maxSubArray(int[] nums, int start, int end, Map<String, Integer> cache) {
            if (start == end) {
                max = Math.max(nums[start], max);
                return nums[start];
            }
            String key = String.valueOf(start) + "," + String.valueOf(end);
            if (cache.keySet().contains(key)) {
                return cache.get(key);
            }
            int re = maxSubArray(nums, start, end - 1, cache) + nums[end];
            cache.put(key, re);
            max = Math.max(re, max);
            return re;
        }

    * @Description 上述解法还是超时了,我们尝试重新定义子问题,使子问题包含更多的运算逻辑,从而更加高效的查询缓存
    * 子问题包含的运算逻辑越多,则缓存命中时,避免的运算也越多
    * 子问题的定义需要我们可以找出子问题与上层问题间的状态转移关系。
    * 我们可以从状态转移关系判断,该状态转移路径是否可以完整的覆盖解空间,从而回推分治子问题定义的正确性。
    * G(end) 表示 end 结尾的最长子数组。
    * 以 end 结尾,最长子数组有两种可能:G(end-1)+nums[end] , nums[end]
    * 因此状态转移方程为:
    * G(end) = Max( G(end-1)+nums[end],nums[end])
    * 回推一下,最长的子数组一定是以 nums 中某一个元素结尾的
    * 最大值一定在 G(0)...G( length-1 ) 中

    public int maxSubArray(int[] nums) {
            int[] cache = new int[nums.length];
            int max = Integer.MIN_VALUE;
            for (int i = 0; i < nums.length; i++) {
                max = Math.max(dp(nums, i, cache), max);
            }
            return max;
        }
    
        public int dp(int[] nums, int end, int[] cache) {
            if (end == 0) {
                return nums[0];
            }
            if (cache[end] != 0) {
                return cache[end];
            }
            cache[end] = Math.max(dp(nums, end - 1, cache) + nums[end], nums[end]);
            return cache[end];
        }

      转为递推表示:

        public int maxSubArrayDP(int[] nums) {
            int[] cache = new int[nums.length];
            cache[0] = nums[0];
            int re = nums[0];
            for (int i = 1; i < nums.length; i++) {
                cache[i] = cache[i - 1] < 0 ? nums[i] : cache[i - 1] + nums[i];
                re = Math.max(cache[i], re);
            }
            return re;
        }

      最终解法效率:

  • 相关阅读:
    Linux下进程间通信的六种机制详解
    Android HAL实例解析
    socket函数
    Linux 线程浅析
    Android WiFi开发教程(一)——WiFi热点的创建与关闭
    Android蓝牙开发教程(三)——蓝牙设备相互通讯
    python数据分析入门学习笔记儿
    Oracle触发器详解
    电商检索系统总结——功能篇
    Linux内核中等待队列的几种用法
  • 原文地址:https://www.cnblogs.com/niuyourou/p/12892261.html
Copyright © 2011-2022 走看看