Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions problems/3499-maximize-active-section-with-trade-i/analysis.md
Original file line number Diff line number Diff line change
@@ -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.
97 changes: 97 additions & 0 deletions problems/3499-maximize-active-section-with-trade-i/problem.md
Original file line number Diff line number Diff line change
@@ -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'`
51 changes: 51 additions & 0 deletions problems/3499-maximize-active-section-with-trade-i/solution.go
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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)
}
})
}
}