算法初探LeetCode-找两个和为目标值且不重叠的子数组

92 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情

LeetCode1477:找两个和为目标值且不重叠的子数组

给你一个整数数组 arr 和一个整数值 target 。

请你在 arr 中找 两个互不重叠的子数组 且它们的和都等于 target 。可能会有多种方案,请你返回满足要求的两个子数组长度和的 最小值 。

请返回满足要求的最小长度和,如果无法找到这样的两个子数组,请返回 -1 。

 

示例 1:

输入: arr = [3,2,2,4,3], target = 3
输出: 2
解释: 只有两个子数组和为 3 ([3][3])。它们的长度和为 2 。

示例 2:

输入: arr = [7,3,4,7], target = 7
输出: 2
解释: 尽管我们有 3 个互不重叠的子数组和为 7 ([7], [3,4][7]),但我们会选择第一个和第三个子数组,因为它们的长度和 2 是最小值。

示例 3:

输入: arr = [4,3,2,6,2,3,4], target = 6
输出: -1
解释: 我们只有一个和为 6 的子数组。

示例 4:

输入: arr = [5,5,4,4,5], target = 3
输出: -1
解释: 我们无法找到和为 3 的子数组。

示例 5:

输入: arr = [3,1,1,1,5,1,2,1], target = 3
输出: 3
解释: 注意子数组 [1,2][2,1] 不能成为一个方案因为它们重叠了。

提示:

  • 1<=arr.length<=1051 <= arr.length <= 10^5
  • 1 <= arr[i] <= 1000
  • 1<=target<=1081 <= target <= 10^8

思路分析

寻找两个和为目标值且不重叠的连续子数组,注意得是连续的子数组哈 2、当明白是寻找连续的子数组和,那么首先想到这应该是滑动窗口来解决,我们先通过滑动窗口找到所有可能的数组,使用列表来存放这些数组(注意存放的数据结构得设计一下,key为数组长度,value为窗口的左值索引); 3、对列表进行排序,将长度从小到大进行排序,为什么这么排序,其实这是贪心,因为我们要找两个数组和最小的值 4、两次for遍历,去掉重叠的数组,找出两个和最小的数组

算法代码

    public static int minSumOfLengths(int[] arr, int target) {
        List < int[] > list = new ArrayList <> ();
        int l = 0;
        int r = 0;
        int sum = 0;
        while (r < arr.length) {
            sum += arr[r];
            while (sum >= target && l <= r) {
                if (sum == target) {
                    list.add(new int[] {
                        l - r + 1, l
                    });
                }
                sum -= arr[l];
                l++;
            }
            r++;
        }
        if (list.size() < 2) {
            return -1;
        }
        Collections.sort(
            list, ((o1, o2) - > {
                return o1[0] - o2[0];
            }));
        int res = Integer.MAX_VALUE;
        for (int i = 0; i < list.size() - 1; i++) {
            int[] node = list.get(i);
            // 剪枝1
            if (node[0] * 2 >= res) {
                break;
            }
            for (int j = i + 1; j < list.size(); j++) {
                int[] element = list.get(j);
                int bigger = node[1] <= element[1] ? 0 : -1;
                if (bigger == 0 && element[1] <= (node[1] + node[0] - 1)) {
                    continue;
                }
                if (bigger == -1 && node[1] <= (element[1] + element[0] - 1)) {
                    continue;
                }
                res = Math.min(res, node[0] + element[0]);
                // 剪枝2
                break;
            }
        }

        return res == Integer.MAX_VALUE ? -1 : res;
    }

结果详情

Snipaste_2023-02-09_22-13-29.png

算法复杂度

  • 空间复杂度:O(1)O(1)
  • 时间复杂度:O(n)O(n)

掘金(JUEJIN)一起进步,一起成长!