Skip to content

1573. Find Two Non Overlapping Sub Arrays Each With Target Sum

Difficulty: Medium

LeetCode Problem View on GitHub


1573. Find Two Non-overlapping Sub-arrays Each With Target Sum

Medium


You are given an array of integers arr and an integer target.

You have to find two non-overlapping sub-arrays of arr each with a sum equal target. There can be multiple answers so you have to find an answer where the sum of the lengths of the two sub-arrays is minimum.

Return the minimum sum of the lengths of the two required sub-arrays, or return -1 if you cannot find such two sub-arrays.

 

Example 1:

Input: arr = [3,2,2,4,3], target = 3
Output: 2
Explanation: Only two sub-arrays have sum = 3 ([3] and [3]). The sum of their lengths is 2.

Example 2:

Input: arr = [7,3,4,7], target = 7
Output: 2
Explanation: Although we have three non-overlapping sub-arrays of sum = 7 ([7], [3,4] and [7]), but we will choose the first and third sub-arrays as the sum of their lengths is 2.

Example 3:

Input: arr = [4,3,2,6,2,3,4], target = 6
Output: -1
Explanation: We have only one sub-array of sum = 6.

 

Constraints:

  • 1 <= arr.length <= 105
  • 1 <= arr[i] <= 1000
  • 1 <= target <= 108

Solution

class Solution {
    static class Pair {
        int idx1, idx2, len;
        public Pair(int idx1, int idx2, int len) {
            this.idx1 = idx1;
            this.idx2 = idx2;
            this.len = len;
        }
        @Override
        public String toString() {
            return "(" + idx1 + " " + idx2 + " "+ len + ")";
        }
    }
    static class custom_sort implements Comparator<Pair> {
        @Override
        public int compare(Pair first, Pair second) {
            int op1 = Integer.compare(first.idx1, second.idx1);
            if (op1 != 0) return op1;
            return Integer.compare(first.idx2, second.idx2);
        }
    }
    public int minSumOfLengths(int[] arr, int target) {
        int n = arr.length;
        ArrayList<Pair> res = new ArrayList<>();
        long sum = 0;
        int left = 0, right = 0;
        while (left < n) {
            while (right < n && sum + arr[right] <= target) {
                sum += arr[right++];
            }
            if (sum == target) res.add(new Pair(left, right - 1, (right - 1) - left + 1));
            sum -= arr[left++];
        }
        if (res.size() < 2) return -1;
        int mini = (int)(1e9);
        Collections.sort(res, new custom_sort());
        int cost[] = new int[res.size()];
        for (int i = 0; i < res.size(); i++) cost[i] = res.get(i).len;
        SegMent_Tree seg = new SegMent_Tree(cost.length, cost);        

        /*
                ........
                      ..........
                                ........
                                         .......    .........

        */

        for (int i = 0; i < res.size(); i++) {
            //binary search for closest j such that !(i , j) intersect --> then we can find the min val from j to res.size() - 1;
            int bs = binary_search(i, i + 1 , res.size() - 1, res);
            if (bs == -1) continue;
            long current = (int)(seg.query(1, 0, cost.length - 1, bs, cost.length - 1).mini);
            current += res.get(i).len;
            mini = (int)(Math.min(mini, current));
        }
        if (mini == (int)(1e9)) return -1;
        return mini;
    }
    private int binary_search(int ind, int low, int high, ArrayList<Pair> res) {
        int n = res.size();
        int ans = -1;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (!Intersect(res.get(ind), res.get(mid))) {
                ans = mid;
                high = mid - 1;
            }
            else low = mid + 1;
        }
        return ans;
    }
    private boolean Intersect(Pair first, Pair second) {
        int l1 = first.idx1, r1 = first.idx2;
        int l2 = second.idx1, r2 = second.idx2;
        if (l2 >= l1 && l2 <= r1) return true;
        if (r2 >= l1 && r2 <= r1) return true;
        return false;
    }
    static class SegMent_Tree {
        static Node seg[];
        static int arr[];
        public SegMent_Tree(int n, int nums[]) {
            arr = new int[n];
            seg = new Node[4 * n + 1];
            for (int i = 0; i < 4 * n + 1; i++) {
                seg[i] = new Node();
            }
            for (int i = 0; i < n; i++) arr[i] = nums[i];
            build(1, 0, n - 1);
        }
        static class Node {
            long sum, gcd, mini, maxi;
            public Node() {
                this.sum = 0;
                this.gcd = 0;
                this.mini = Integer.MAX_VALUE;
                this.maxi = Integer.MIN_VALUE;
            }
        }
        static Node Merge(Node a, Node b) {
            Node res = new Node();
            res.sum = a.sum + b.sum;
            res.mini = Math.min(a.mini, b.mini);
            res.maxi = Math.max(a.maxi, b.maxi);
            res.gcd = GCD(a.gcd, b.gcd);
            return res;
        }
        static void build(int ind, int l, int r) {
            if (l == r) {
                seg[ind].sum = arr[l];
                seg[ind].mini = arr[l];
                seg[ind].maxi = arr[l];
                seg[ind].gcd = arr[l];
                return;
            }
            int mid = (l + r) / 2;
            build(2 * ind, l, mid);
            build(2 * ind + 1, mid + 1, r);
            seg[ind] = Merge(seg[2 * ind], seg[2 * ind + 1]);
        }
        //point update -- > increase the value at index pos by value = val;        
        static void update(int ind, int l, int r, int pos, int val) {
            if (pos < l || pos > r) return;
            if (l == r) {
                seg[ind].sum = val;
                seg[ind].mini = val;
                seg[ind].maxi = val;
                seg[ind].gcd = val;
                return;
            }
            int mid = (l + r) / 2;
            update(2 * ind, l, mid, pos, val);
            update(2 * ind + 1, mid + 1, r, pos, val);
            seg[ind] = Merge(seg[2 * ind], seg[2 * ind + 1]);
        }
        static Node query(int ind, int l, int r, int ql, int qr) {
            if (qr < l || ql > r) return new Node();
            if (l >= ql && r <= qr) return seg[ind];
            int mid = (l + r) / 2;
            Node left = query(2 * ind, l, mid, ql, qr);
            Node right = query(2 * ind + 1, mid + 1, r, ql, qr);
            return Merge(left, right);
        }
    }
    static long GCD(long x, long y) {if(y == 0) return x;return GCD(y, x % y);}
}

Complexity Analysis

  • Time Complexity: O(?)
  • Space Complexity: O(?)

Approach

Detailed explanation of the approach will be added here