Registro de cambios de Admin Page Creator
Solution Explanation
For every position i of the string we want to know the longest
substring that starts at i and contains at most k different
characters.
If we could check all substrings that start at i we would need
O(n²) time – far too slow for n ≤ 10⁵.
The classic way to solve this problem is a sliding window (two‑pointer) technique.
1. Sliding window
left – start of the current window
right – end of the current window (inclusive)
While we move right to the right we add the new character to a
frequency table.
If the number of distinct characters becomes larger than k,
we shrink the window from the left side until the condition is satisfied
again.
During the whole process we keep the maximum length that we have seen.
2. Data structures
counts : [Character : Int]– how many times each character occurs inside the current window.distinct : Int– current number of different characters.maxLen : Int– answer so far.
The alphabet is small (at most 26 different letters in the test data),
so the dictionary stays tiny – O(1) memory.
3. Algorithm
if k == 0 // not needed for the given constraints
answer = 0
else
left = 0
maxLen = 0
distinct = 0
for right = 0 ..< n
add s[right] to counts
if distinct > k
while distinct > k
remove s[left] from counts
left += 1
maxLen = max(maxLen, right - left + 1)
answer = maxLen
Adding a character
If it is already in the dictionary we just increase its counter.
Otherwise we insert it with value 1 and increase distinct.
Removing a character
If its counter becomes 0 we delete the entry and decrease distinct,
otherwise we just decrement the counter.
4. Correctness Proof
We prove that the algorithm outputs the length of the longest substring
containing at most k distinct characters.
Lemma 1
At any time the window [left, right] contains at most k distinct
characters.
Proof.
When right is increased we add one character.
If the number of distinct characters becomes k+1, the inner while
loop removes characters from the left until the number of distinct
characters is k again.
No other operation can increase the number of distinct characters.
∎
Lemma 2
For every position right the algorithm considers the longest
substring ending at right that satisfies the condition.
Proof.
When right is fixed, the algorithm keeps shrinking the window from
the left until the condition is satisfied (Lemma 1).
After the loop terminates, the window [left, right] is the longest
possible ending at right that still contains at most k distinct
characters – otherwise we could have moved left one step to the left
and still satisfy the condition, contradicting the loop termination.
∎
Lemma 3
maxLen is the length of the longest valid substring of the whole
string.
Proof.
During the scan, for each right we update maxLen with the length of
the longest valid substring ending at right (Lemma 2).
Therefore after the last iteration maxLen is the maximum over all
valid substrings of the string. ∎
Theorem
The algorithm outputs the correct answer.
Proof.
By Lemma 3 the value printed by the algorithm equals the length of
the longest substring that contains at most k distinct characters,
which is exactly the required answer. ∎
5. Complexity Analysis
Time – Each character is inserted into the window once and removed
at most once.
O(n) where n = |s|.
Memory – The dictionary stores at most the number of distinct
characters in the current window, bounded by the alphabet size.
O(1) (≤ 26 for the given tests).
6. Reference Implementation (Swift 5.5)
import Foundation
// ---------- Read input ----------
guard let kLine = readLine(),
let k = Int(kLine.trimmingCharacters(in: .whitespacesAndNewlines)),
let sLine = readLine() else {
exit(0)
}
let s = sLine.trimmingCharacters(in: .whitespacesAndNewlines)
// ---------- Edge case ----------
if k == 0 {
print(0)
exit(0)
}
// ---------- Sliding window ----------
var counts: [Character: Int] = [:]
var left = 0
var maxLen = 0
var distinct = 0
let chars = Array(s)
for right in 0..<chars.count {
let c = chars[right]
if let current = counts[c] {
counts[c] = current + 1
} else {
counts[c] = 1
distinct += 1
}
// shrink from the left while we have too many distinct chars
while distinct > k {
let leftChar = chars[left]
if let cur = counts[leftChar] {
if cur == 1 {
counts.removeValue(forKey: leftChar)
distinct -= 1
} else {
counts[leftChar] = cur - 1
}
}
left += 1
}
let currentLen = right - left + 1
if currentLen > maxLen {
maxLen = currentLen
}
}
// ---------- Output ----------
print(maxLen)
The program follows exactly the algorithm proven correct above and is fully compatible with Swift 5.5.