diff --git a/problems/3499-maximize-active-section-with-trade-i/analysis.md b/problems/3499-maximize-active-section-with-trade-i/analysis.md new file mode 100644 index 0000000..3e0e77d --- /dev/null +++ b/problems/3499-maximize-active-section-with-trade-i/analysis.md @@ -0,0 +1,64 @@ +# 3499. Maximize Active Section with Trade I + +[LeetCode Link](https://leetcode.com/problems/maximize-active-section-with-trade-i/) + +Difficulty: Medium +Topics: String, Enumeration + +Acceptance Rate: 41.1% + +## Hints + +### Hint 1 + +The described trade sounds complicated, but start by asking: what does a single trade *actually change* in the string? Try writing out a small example like `"1000100"` and physically applying the two steps. Notice how the region you touch changes shape — this is a classic case where compressing the string into **runs of equal characters** (run-length encoding) makes the structure obvious. + +### Hint 2 + +A trade always operates on a `1`-block that is **surrounded by `0`-blocks on both sides**, i.e. a pattern `[0s][1s][0s]`. Step one turns the middle `1`s into `0`s (merging the three runs into one big `0`-block), and step two turns that merged `0`-block back into `1`s. So really you are enumerating every `1`-run that sits between two `0`-runs. What is the *change* in the number of active sections for each such choice? + +### Hint 3 + +For a region `[a zeros][m ones][b zeros]`, after the trade it becomes `a + m + b` ones. It used to contribute `m` ones, so the **net gain is exactly `a + b`** — the middle `m` cancels out. That means the answer is simply `totalOnes + max(a + b)` over all valid sandwiches, and if no `1`-run is surrounded by two `0`-runs, no trade helps and the answer is just `totalOnes`. + +## Approach + +The key realization is that the number of active sections can never drop below the original count of `'1'`s (you can always choose to do nothing). So the base of the answer is `totalOnes`. + +A valid trade requires a block of `'1'`s that is surrounded by `'0'`s on both sides. The augmentation note (`t = '1' + s + '1'`) only affects whether `0`-blocks at the ends count as "surrounded by `1`s" — it never creates a new `1`-block sandwich, so we can reason directly about the original string's runs. + +Consider any region shaped like `[a zeros][m ones][b zeros]`: + +1. Convert the `m` ones (surrounded by zeros) to zeros → the three runs merge into one block of `a + m + b` zeros. +2. Convert that merged zero block (now surrounded by ones) to ones → `a + m + b` active sections. + +Before the trade this region held `m` ones; after, it holds `a + m + b`. The **net gain** is `(a + m + b) - m = a + b`. The middle `1`-block size is irrelevant to the gain — only the two neighboring `0`-block sizes matter. + +So the algorithm is: + +1. Count `totalOnes`. +2. Scan the string as consecutive runs. Whenever a `0`-run is preceded (two runs back) by another `0`-run — meaning there is a `1`-run sandwiched between them — record the sum of the two `0`-run lengths as a candidate gain. +3. Answer = `totalOnes + max candidate gain` (or `totalOnes` if no sandwich exists). + +Because runs strictly alternate between `0` and `1`, tracking just the length of the *previous* `0`-run is enough: when we reach a new `0`-run and a previous `0`-run exists, there is guaranteed to be exactly one `1`-run between them. + +**Worked example** — `"1000100"`: +- Runs: `1`(len 1), `000`(len 3), `1`(len 1), `00`(len 2). +- `totalOnes = 2`. +- The `00` run is preceded by the `000` run (with a `1` in between): candidate gain `3 + 2 = 5`. +- Answer `= 2 + 5 = 7`. ✔ + +## Complexity Analysis + +Time Complexity: O(n) — a single pass to count ones plus a single pass over the runs. +Space Complexity: O(1) — only a few counters are kept; no extra structure proportional to the input. + +## Edge Cases + +- **All `'1'`s (e.g. `"111"`)**: no `0`-runs, so no trade is possible; answer is `totalOnes`. +- **All `'0'`s (e.g. `"0000"`)**: only one `0`-run and no `1`-run to sandwich; gain is 0; answer is 0. +- **Single character (`"0"` or `"1"`)**: too short for any sandwich; answer is `totalOnes`. +- **No valid sandwich with ones at the ends (e.g. `"1001"`)**: the `0`-block is surrounded by `1`s but there is no `1`-block surrounded by `0`s, so no trade applies; answer is `totalOnes`. +- **Multiple candidate sandwiches (e.g. `"01010"`)**: must take the maximum `a + b`, not just the first one found. + +Don't be discouraged if the phrasing of the trade felt intimidating at first — the whole puzzle collapses into "add the two 0-runs around a 1-run" once you compress the string into runs. That reframing is the real skill this problem is training. diff --git a/problems/3499-maximize-active-section-with-trade-i/problem.md b/problems/3499-maximize-active-section-with-trade-i/problem.md new file mode 100644 index 0000000..b08ce0a --- /dev/null +++ b/problems/3499-maximize-active-section-with-trade-i/problem.md @@ -0,0 +1,97 @@ +--- +number: "3499" +frontend_id: "3499" +title: "Maximize Active Section with Trade I" +slug: "maximize-active-section-with-trade-i" +difficulty: "Medium" +topics: + - "String" + - "Enumeration" +acceptance_rate: 4105.7 +is_premium: false +created_at: "2026-07-21T03:54:07.204031+00:00" +fetched_at: "2026-07-21T03:54:07.204031+00:00" +link: "https://leetcode.com/problems/maximize-active-section-with-trade-i/" +date: "2026-07-21" +--- + +# 3499. Maximize Active Section with Trade I + +You are given a binary string `s` of length `n`, where: + + * `'1'` represents an **active** section. + * `'0'` represents an **inactive** section. + + + +You can perform **at most one trade** to maximize the number of active sections in `s`. In a trade, you: + + * Convert a contiguous block of `'1'`s that is surrounded by `'0'`s to all `'0'`s. + * Afterward, convert a contiguous block of `'0'`s that is surrounded by `'1'`s to all `'1'`s. + + + +Return the **maximum** number of active sections in `s` after making the optimal trade. + +**Note:** Treat `s` as if it is **augmented** with a `'1'` at both ends, forming `t = '1' + s + '1'`. The augmented `'1'`s **do not** contribute to the final count. + + + +**Example 1:** + +**Input:** s = "01" + +**Output:** 1 + +**Explanation:** + +Because there is no block of `'1'`s surrounded by `'0'`s, no valid trade is possible. The maximum number of active sections is 1. + +**Example 2:** + +**Input:** s = "0100" + +**Output:** 4 + +**Explanation:** + + * String `"0100"` -> Augmented to `"101001"`. + * Choose `"0100"`, convert `"10 _**1**_ 001"` -> `"1 _**0000**_ 1"` -> `"1 _**1111**_ 1"`. + * The final string without augmentation is `"1111"`. The maximum number of active sections is 4. + + + +**Example 3:** + +**Input:** s = "1000100" + +**Output:** 7 + +**Explanation:** + + * String `"1000100"` -> Augmented to `"110001001"`. + * Choose `"000100"`, convert `"11000 _**1**_ 001"` -> `"11 _**000000**_ 1"` -> `"11 _**111111**_ 1"`. + * The final string without augmentation is `"1111111"`. The maximum number of active sections is 7. + + + +**Example 4:** + +**Input:** s = "01010" + +**Output:** 4 + +**Explanation:** + + * String `"01010"` -> Augmented to `"1010101"`. + * Choose `"010"`, convert `"10 _**1**_ 0101"` -> `"1 _**000**_ 101"` -> `"1 _**111**_ 101"`. + * The final string without augmentation is `"11110"`. The maximum number of active sections is 4. + + + + + +**Constraints:** + + * `1 <= n == s.length <= 105` + * `s[i]` is either `'0'` or `'1'` diff --git a/problems/3499-maximize-active-section-with-trade-i/solution.go b/problems/3499-maximize-active-section-with-trade-i/solution.go new file mode 100644 index 0000000..6a824fc --- /dev/null +++ b/problems/3499-maximize-active-section-with-trade-i/solution.go @@ -0,0 +1,51 @@ +package main + +// Approach: Run-length grouping. +// +// The number of 1s never decreases below the original count, so the base +// answer is the total number of '1's in s. A single trade can only help by +// picking a block of 1s that is surrounded by 0-blocks on both sides. When we +// zero out that middle 1-block of size m and then fill the merged 0-run, a +// region [a zeros][m ones][b zeros] becomes (a+m+b) ones. It previously held m +// ones, so the net gain is exactly a+b — the sizes of the two neighboring +// 0-blocks. Treating s as augmented with '1' at both ends means a 0-block that +// touches an end is still "surrounded" by a 1. +// +// So the answer is: totalOnes + max over every 1-block sandwiched between two +// 0-blocks of (leftZeros + rightZeros). If no such sandwich exists, no trade +// helps and the answer is just totalOnes. +// +// Time: O(n), Space: O(1). +func maxActiveSectionsAfterTrade(s string) int { + n := len(s) + + totalOnes := 0 + for i := 0; i < n; i++ { + if s[i] == '1' { + totalOnes++ + } + } + + best := 0 + i := 0 + prevZeros := -1 // length of the zero-block immediately before the current run; -1 means none + for i < n { + j := i + for j < n && s[j] == s[i] { + j++ + } + runLen := j - i + if s[i] == '0' { + // If this zero-block was preceded by (a 1-block preceded by) a + // zero-block, we have a valid sandwich; capture the gain. + if prevZeros >= 0 && prevZeros+runLen > best { + best = prevZeros + runLen + } + prevZeros = runLen + } + // A run of '1's keeps prevZeros so the next '0' run can pair with it. + i = j + } + + return totalOnes + best +} diff --git a/problems/3499-maximize-active-section-with-trade-i/solution_test.go b/problems/3499-maximize-active-section-with-trade-i/solution_test.go new file mode 100644 index 0000000..b635fb2 --- /dev/null +++ b/problems/3499-maximize-active-section-with-trade-i/solution_test.go @@ -0,0 +1,30 @@ +package main + +import "testing" + +func TestMaxActiveSectionsAfterTrade(t *testing.T) { + tests := []struct { + name string + s string + expected int + }{ + {"example 1: no valid trade", "01", 1}, + {"example 2: single one surrounded by zeros", "0100", 4}, + {"example 3: pick the wider sandwich", "1000100", 7}, + {"example 4: multiple equal sandwiches", "01010", 4}, + {"edge case: all ones", "111", 3}, + {"edge case: all zeros", "0000", 0}, + {"edge case: single zero", "0", 0}, + {"edge case: single one", "1", 1}, + {"edge case: no sandwich, ones at ends", "1001", 2}, + {"edge case: long tail sandwich", "10001000001", 11}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := maxActiveSectionsAfterTrade(tt.s); got != tt.expected { + t.Errorf("maxActiveSectionsAfterTrade(%q) = %d, want %d", tt.s, got, tt.expected) + } + }) + } +}