zoukankan      html  css  js  c++  java
  • Leetcode 1477 两个和为目标值且不重合的子数组 滑动窗口

     

      所求子数组是连续的子数组,因此想到求取所有可能连续子数组的和。

      顺序的求取连续子数组的和具有单调性,因此可以考虑通过滑动窗口来避免重复计算。

    public final int minSumOfLengths(int[] arr, int target) {
            int startPoint = 0, endPoint = 0, sum = 0, re = Integer.MAX_VALUE;
            List<Long> nums = new LinkedList<Long>();
            while (startPoint < arr.length && endPoint < arr.length) {
                sum += arr[endPoint];
                if (sum < target) endPoint++;
                else {
                    if (sum == target) {
                        if (endPoint - startPoint == 2) return 2;
                        for (int i = nums.size() - 1; i >= 0; i--) {
                            int preEnd = (int) (long) nums.get(i);
                            if (preEnd >= startPoint) continue;
                            int preBegin = (int) (nums.get(i) >> 32);
                            re = Math.min(re, preEnd - preBegin + endPoint - startPoint + 2);
                        }
                        nums.add(((long) startPoint << 32) | endPoint);
                        endPoint++;
                    } else sum -= arr[endPoint];
                    sum = startPoint == endPoint ? sum : sum - arr[startPoint];
                    startPoint++;
                    if (endPoint < startPoint) endPoint = startPoint;
                }
            }
            return re == Integer.MAX_VALUE ? -1 : re;
        }

      在寻找两个子数组的组合时,采用了遍历查找的方式,该解法超时。考虑采用更合理的数据结构进行符合要求的子数组的查找,这里采用二叉排序树:

    public final int minSumOfLengths0(int[] arr, int target) {
            int startPoint = 0, endPoint = 0, sum = 0, re = Integer.MAX_VALUE;
            TreeMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
            while (startPoint < arr.length && endPoint < arr.length) {
                sum += arr[endPoint];
                if (sum < target) endPoint++;
                else {
                    if (sum == target) {
                        SortedMap<Integer, Integer> pres = map.headMap(startPoint);
                        Iterator<Integer> iterator = pres.keySet().iterator();
                        while (iterator.hasNext()) {
                            int key = iterator.next();
                            re = Math.min(re, key - pres.get(key) + endPoint - startPoint + 2);
                        }
                        map.put(endPoint, startPoint);
                        endPoint++;
                    } else sum -= arr[endPoint];
                    sum = startPoint == endPoint ? sum : sum - arr[startPoint];
                    startPoint++;
                    if (endPoint < startPoint) endPoint = startPoint;
                }
            }
            return re == Integer.MAX_VALUE ? -1 : re;
        }

      依然超时,考虑使用动态规划优化查找。寻找最小的两个子数组的和很难找到合适的状态转移方程,但可以注意到,可以复用 “某个节点之前的和为 target 的最小子数组” 的结果:

    public final int minSumOfLengths1(int[] arr, int target) {
            int sum = 0, len = arr.length, maxRe = Integer.MAX_VALUE / 2, re = maxRe;
            int[] dp = new int[len];
            Arrays.fill(dp, maxRe);
            for (int i = 0, j = 0; j < len; j++) {
                sum += arr[j];
                while (sum > target && i <= j) {
                    sum -= arr[i];
                    i++;
                }
                if (sum == target) {
                    int currentLen = j - i + 1;
                    dp[j] = currentLen;
                    if (i != 0) re = Math.min(re, dp[i - 1] + currentLen);
                }
                if (j > 0) dp[j] = Math.min(dp[j - 1], dp[j]);
            }
            return re == maxRe ? -1 : re;
        }

      JS:

    /**
     * @param {number[]} arr
     * @param {number} target
     * @return {number}
     */
    var minSumOfLengths = function (arr, target) {
        let sum = 0, re = Number.MAX_VALUE, len = arr.length, dp = new Array(len);
        for (let i = 0, j = 0; j < len; j++) {
            sum += arr[j];
            while (sum > target && i <= j) {
                sum -= arr[i];
                i++;
            }
            if (sum == target) {
                dp[j] = j - i + 1;
                if (i != 0) re = Math.min(re, dp[i - 1] + dp[j]);
            }
            if (!dp[j]) dp[j] = Number.MAX_VALUE;
            if (j != 0) dp[j] = Math.min(dp[j - 1], dp[j]);
            console.log(dp[j]);
        }
        return re == Number.MAX_VALUE ? -1 : re;
    };
  • 相关阅读:
    590. N 叉树的后序遍历
    CF605E
    网络流水题题单
    wqs二分的边界
    luoguP6326 Shopping
    【THUWC2020】工资分配
    CF1336简要题解
    「PKUWC2020」最小割
    洛谷P4895 独钓寒江雪
    省选联考2020简要题解
  • 原文地址:https://www.cnblogs.com/niuyourou/p/14123122.html
Copyright © 2011-2022 走看看