From e8c4dd0b846bf1dcfea5af3e8776d0ae155acfff Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 17 Sep 2026 05:07:53 +0000 Subject: [PATCH] feat: add solution for 1477. Find Two Non-overlapping Sub-arrays Each With Target Sum --- .../analysis.md | 65 +++++++++++++++++++ .../problem.md | 61 +++++++++++++++++ .../solution_daily_20260917.go | 62 ++++++++++++++++++ .../solution_daily_20260917_test.go | 34 ++++++++++ 4 files changed, 222 insertions(+) create mode 100644 problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/analysis.md create mode 100644 problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/problem.md create mode 100644 problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/solution_daily_20260917.go create mode 100644 problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/solution_daily_20260917_test.go diff --git a/problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/analysis.md b/problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/analysis.md new file mode 100644 index 0000000..1bcf047 --- /dev/null +++ b/problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/analysis.md @@ -0,0 +1,65 @@ +# 1477. Find Two Non-overlapping Sub-arrays Each With Target Sum + +[LeetCode Link](https://leetcode.com/problems/find-two-non-overlapping-sub-arrays-each-with-target-sum/) + +Difficulty: Medium +Topics: Array, Hash Table, Binary Search, Dynamic Programming, Sliding Window +Acceptance Rate: 40.4% + +## Hints + +### Hint 1 + +Read the constraints carefully: `1 <= arr[i] <= 1000`. Every element is strictly positive, which means the prefix sums are strictly increasing. That single fact unlocks a much cheaper tool than a hash map of prefix sums — as the right end of a window moves forward, the left end that keeps the window sum at `target` can only move forward too. What technique does a monotone window enable? + +### Hint 2 + +Start by solving the easier half of the problem: enumerate *every* sub-array whose sum equals `target`. With a two-pointer window you can do this in one pass, and there are at most `n` of them (one per right endpoint). Now the real question is how to pair two of them without overlap. Pairing every candidate with every other candidate is O(n²) — too slow. Think about fixing one of the two sub-arrays and asking a question about "everything before it". + +### Hint 3 + +Fix the *second* sub-array. If it occupies `arr[l..r]`, the first one must live entirely inside `arr[0..l-1]`, and to minimize the total you want the shortest valid sub-array anywhere in that prefix. So precompute (or maintain on the fly) `best[i]` = the length of the shortest valid sub-array contained in `arr[0..i-1]`, with `best[i] = min(best[i-1], length of a window ending exactly at i-1)`. Since `best` is a running prefix minimum, it can be filled in the *same* sweep as the sliding window: when the window `[l..r]` hits `target`, the answer candidate is `(r-l+1) + best[l]`. One pass, no nested loop, no binary search needed. + +## Approach + +The problem has two independent pieces: *find* the candidate sub-arrays, and *combine* two of them optimally. + +**Finding candidates.** Because all elements are positive, a sliding window works. Keep `left`, `right`, and the running `sum` of `arr[left..right]`. Extend `right` by one element at a time and add it to `sum`. While `sum > target`, shrink from the left (`sum -= arr[left]; left++`). Shrinking is safe because dropping a positive element can only decrease the sum, and once the sum drops to or below `target` no further left position for this `right` can reach `target` again. After the shrink loop, `sum == target` exactly when the window `arr[left..right]` is a valid sub-array — and it is the *only* valid one ending at `right`, again because prefix sums are strictly increasing. So the sweep yields at most one candidate per right endpoint, i.e. at most `n` candidates, in O(n) total. + +**Combining candidates.** Define `best[i]` as the length of the shortest valid sub-array that fits entirely within the prefix `arr[0..i-1]` (so `best[0]` is "impossible", represented by a sentinel infinity). This array is a running minimum: + +``` +best[i] = min(best[i-1], len of the window ending at index i-1, if one exists) +``` + +Now suppose the *second* chosen sub-array is the window `arr[left..right]`. Non-overlap means the first sub-array ends at index `left-1` or earlier — exactly the prefix `arr[0..left-1]`, whose shortest valid sub-array has length `best[left]`. So the best total with this window as the second piece is `(right-left+1) + best[left]`. Because every valid pair has a well-defined "second" sub-array, iterating over all candidates as the second piece covers every pair, and taking the minimum over all of them is the answer. + +The key scheduling detail is that `best[left]` only refers to indices strictly less than `left`, and `left <= right`, so by the time we process right endpoint `right` we have already computed `best` up to index `right` — the two computations interleave in a single pass. Concretely, at each step we first copy `best[right+1] = best[right]`, then, if the current window is valid, use `best[left]` for the answer candidate and only afterwards fold the current window's length into `best[right+1]`. Folding *after* reading is what prevents the same window being used as both halves of the pair. + +**Worked example** on `arr = [7,3,4,7]`, `target = 7` (`∞` marks "no candidate yet"): + +| right | window after shrink | sum | valid? | `best[left]` | candidate | `best[right+1]` | +|-------|--------------------|-----|--------|--------------|-----------|-----------------| +| 0 | `[7]` (left=0) | 7 | yes | `best[0]=∞` | — | 1 | +| 1 | `[3]` (left=1) | 3 | no | — | — | 1 | +| 2 | `[3,4]` (left=1) | 7 | yes | `best[1]=1` | 1+2 = 3 | 1 | +| 3 | `[7]` (left=3) | 7 | yes | `best[3]=1` | 1+1 = **2** | 1 | + +The minimum candidate is 2, matching the expected output: the sub-arrays `[7]` and `[7]` at the two ends. + +If no candidate pair is ever formed, the running answer stays at the sentinel and we return `-1`. + +## Complexity Analysis + +Time Complexity: O(n) — each of `left` and `right` advances at most `n` times across the whole sweep, so the inner shrink loop is amortized O(1) per step. +Space Complexity: O(n) for the `best` prefix-minimum array. This can be reduced to O(1) extra space by noticing that only `best[left]` and the running minimum are ever read, but keeping the array is clearer and still comfortably within limits. + +## Edge Cases + +- **No valid sub-array at all, or exactly one** (`arr = [4,3,2,6,2,3,4]`, `target = 6`). The answer must be `-1`, not the length of the single sub-array. Guarding with a sentinel "infinity" and checking `best[left] != inf` before forming a candidate handles both. +- **Two valid sub-arrays that overlap** (e.g. `[1,2,1]` with `target = 3`: `[1,2]` and `[2,1]` share index 1). Reading `best[left]` — strictly the prefix *before* the window — rejects these automatically, and the answer is `-1`. +- **Array shorter than two sub-arrays** (`len(arr) == 1`). The loop runs once, `best[0]` is infinity, and no candidate is ever formed, so `-1` falls out naturally with no special-case code. +- **Adjacent sub-arrays** (`arr = [2,2,2]`, `target = 2`). Touching but not overlapping is legal; the boundary must be `best[left]`, not `best[left-1]`, or you would wrongly exclude a sub-array ending at exactly `left-1`. +- **Order of update vs. read.** If you fold the current window's length into `best` *before* reading `best[left]`, a single sub-array can pair with itself when `left == 0`-ish situations arise. Always read first, then update. +- **`target` larger than the total sum.** The window sum never reaches `target`, the shrink loop can empty the window (`left` passes `right`), and the code must not index out of range — the `sum > target` condition combined with positive elements guarantees `left <= right+1` at all times. +- **Overflow is not a concern here** (`n <= 1e5`, `arr[i] <= 1000` gives a max total of 1e8, and `target <= 1e8` fits in an `int`), but the sentinel must be chosen so that sentinel-plus-length comparisons never wrap; guarding explicitly against the sentinel avoids the question entirely. diff --git a/problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/problem.md b/problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/problem.md new file mode 100644 index 0000000..eaf6002 --- /dev/null +++ b/problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/problem.md @@ -0,0 +1,61 @@ +--- +number: "1477" +frontend_id: "1477" +title: "Find Two Non-overlapping Sub-arrays Each With Target Sum" +slug: "find-two-non-overlapping-sub-arrays-each-with-target-sum" +difficulty: "Medium" +topics: + - "Array" + - "Hash Table" + - "Binary Search" + - "Dynamic Programming" + - "Sliding Window" +acceptance_rate: 4035.5 +is_premium: false +created_at: "2026-09-17T05:05:26.204142+00:00" +fetched_at: "2026-09-17T05:05:26.204142+00:00" +link: "https://leetcode.com/problems/find-two-non-overlapping-sub-arrays-each-with-target-sum/" +date: "2026-09-17" +--- + +# 1477. Find Two Non-overlapping Sub-arrays Each With Target Sum + +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` diff --git a/problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/solution_daily_20260917.go b/problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/solution_daily_20260917.go new file mode 100644 index 0000000..83ca773 --- /dev/null +++ b/problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/solution_daily_20260917.go @@ -0,0 +1,62 @@ +package main + +// 1477. Find Two Non-overlapping Sub-arrays Each With Target Sum +// +// All elements are positive, so prefix sums are strictly increasing and a +// sliding window finds every sub-array summing to target in one pass (at most +// one per right endpoint). +// +// To pair two of them without overlap, fix the window [left..right] as the +// *second* sub-array: the first must then fit entirely in arr[0..left-1]. So we +// maintain best[i] = length of the shortest valid sub-array contained in the +// prefix arr[0..i-1], a running prefix minimum filled during the same sweep. +// The candidate answer for each window is (right-left+1) + best[left]; reading +// best[left] before folding the current window into best keeps a sub-array from +// pairing with itself. +// +// Time: O(n), Space: O(n). + +// minLengthInf is the "no valid sub-array" sentinel. It is compared against +// explicitly before any addition, so it never participates in arithmetic. +const minLengthInf = 1<<31 - 1 + +func minSumOfLengthsDaily20260917(arr []int, target int) int { + n := len(arr) + + // best[i] = shortest valid sub-array length within arr[0..i-1]. + best := make([]int, n+1) + best[0] = minLengthInf + + answer := minLengthInf + sum, left := 0, 0 + + for right := 0; right < n; right++ { + sum += arr[right] + + // Elements are positive, so shrinking strictly decreases the sum. + for sum > target { + sum -= arr[left] + left++ + } + + best[right+1] = best[right] + + if sum == target { + length := right - left + 1 + + // Pair with the shortest sub-array ending before index left. + if best[left] != minLengthInf && best[left]+length < answer { + answer = best[left] + length + } + + if length < best[right+1] { + best[right+1] = length + } + } + } + + if answer == minLengthInf { + return -1 + } + return answer +} diff --git a/problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/solution_daily_20260917_test.go b/problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/solution_daily_20260917_test.go new file mode 100644 index 0000000..c7f940e --- /dev/null +++ b/problems/1477-find-two-non-overlapping-sub-arrays-each-with-target-sum/solution_daily_20260917_test.go @@ -0,0 +1,34 @@ +package main + +import "testing" + +func TestMinSumOfLengthsDaily20260917(t *testing.T) { + tests := []struct { + name string + arr []int + target int + expected int + }{ + {"example 1: only two valid sub-arrays, both length 1", []int{3, 2, 2, 4, 3}, 3, 2}, + {"example 2: three candidates, pick the two shortest non-overlapping", []int{7, 3, 4, 7}, 7, 2}, + {"example 3: only one valid sub-array", []int{4, 3, 2, 6, 2, 3, 4}, 6, -1}, + {"edge case: single element equal to target", []int{1}, 1, -1}, + {"edge case: two candidates that overlap", []int{1, 2, 1}, 3, -1}, + {"edge case: adjacent sub-arrays are allowed", []int{2, 2, 2}, 2, 2}, + {"edge case: whole array is the only candidate", []int{1, 1, 1, 1}, 4, -1}, + {"edge case: target exceeds the total sum", []int{1, 2, 3}, 100, -1}, + {"edge case: shortest overall must pair with a longer one", []int{1, 1, 1, 2, 1}, 2, 3}, + {"edge case: candidates overlap pairwise, best pair is disjoint", []int{2, 1, 2, 1, 2}, 3, 4}, + {"edge case: best pair sits at both ends", []int{5, 1, 1, 1, 5}, 5, 2}, + {"edge case: short prefix candidate plus later candidate", []int{3, 1, 1, 1, 5, 1, 2, 1}, 3, 3}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := minSumOfLengthsDaily20260917(tt.arr, tt.target) + if result != tt.expected { + t.Errorf("minSumOfLengthsDaily20260917(%v, %d) = %v, want %v", tt.arr, tt.target, result, tt.expected) + } + }) + } +}