Skip to content

Commit ee01580

Browse files
authored
Merge pull request ByteByteGoHq#15 from marttp/kotlin-sliding-windows
Kotlin Chapter 5: Sliding Windows
2 parents b2d4105 + 8b4cc71 commit ee01580

File tree

4 files changed

+108
-0
lines changed

4 files changed

+108
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
fun longestSubstringWithUniqueChars(s: String): Int {
2+
var maxLen = 0
3+
val hashSet = mutableSetOf<Char>()
4+
var left = 0
5+
var right = 0
6+
while (right < s.length) {
7+
// If we encounter a duplicate character in the window, shrink
8+
// the window until it's no longer a duplicate.
9+
while (s[right] in hashSet) {
10+
hashSet.remove(s[left])
11+
left++
12+
}
13+
// Once there are no more duplicates in the window, update
14+
// 'maxLen' if the current window is larger.
15+
maxLen = maxOf(maxLen, right - left + 1)
16+
hashSet.add(s[right])
17+
// Expand the window.
18+
right++
19+
}
20+
return maxLen
21+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
fun longestSubstringWithUniqueCharsOptimized(s: String): Int {
2+
var maxLen = 0
3+
val prevIndexes = mutableMapOf<Char, Int>()
4+
var left = 0
5+
var right = 0
6+
while (right < s.length) {
7+
// If a previous index of the current character is present
8+
// in the current window, it's a duplicate character in the
9+
// window.
10+
if (s[right] in prevIndexes && prevIndexes[s[right]]!! >= left) {
11+
// Shrink the window to exclude the previous occurrence
12+
// of this character.
13+
left = prevIndexes[s[right]]!! + 1
14+
}
15+
// Update 'maxLen' if the current window is larger.
16+
maxLen = maxOf(maxLen, right - left + 1)
17+
prevIndexes[s[right]] = right
18+
// Expand the window.
19+
right++
20+
}
21+
return maxLen
22+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
fun longestUniformSubstringAfterReplacements(s: String, k: Int): Int {
2+
val freqs = mutableMapOf<Char, Int>()
3+
var highestFreq = 0
4+
var maxLen = 0
5+
var left = 0
6+
var right = 0
7+
while (right < s.length) {
8+
// Update the frequency of the character at the right pointer
9+
// and the highest frequency for the current window.
10+
freqs[s[right]] = freqs.getOrDefault(s[right], 0) + 1
11+
highestFreq = maxOf(highestFreq, freqs[s[right]]!!)
12+
// Calculate replacements needed for the current window.
13+
val numCharsToReplace = (right - left + 1) - highestFreq
14+
// Slide the window if the number of replacements needed exceeds
15+
// 'k'. The right pointer always gets advanced, so we just need
16+
// to advance 'left'.
17+
if (numCharsToReplace > k) {
18+
// Remove the character at the left pointer from the hash map
19+
// before advancing the left pointer.
20+
freqs[s[left]] = freqs[s[left]]!! - 1
21+
left++
22+
}
23+
// Since the length of the current window increases or stays the
24+
// same, assign the length of the current window to 'maxLen'.
25+
maxLen = right - left + 1
26+
// Expand the window.
27+
right++
28+
}
29+
return maxLen
30+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
fun substringAnagrams(s: String, t: String): Int {
2+
val lenS = s.length
3+
val lenT = t.length
4+
if (lenT > lenS) {
5+
return 0
6+
}
7+
var count = 0
8+
val expectedFreqs = IntArray(26)
9+
val windowFreqs = IntArray(26)
10+
// Populate 'expected_freqs' with the characters in string 't'.
11+
for (c in t) {
12+
expectedFreqs[c - 'a']++
13+
}
14+
var left = 0
15+
var right = 0
16+
while (right < lenS) {
17+
// Add the character at the right pointer to 'window_freqs'
18+
// before sliding the window.
19+
windowFreqs[s[right] - 'a']++
20+
// If the window has reached the expected fixed length, we
21+
// advance the left pointer as well as the right pointer to
22+
// slide the window.
23+
if (right - left + 1 == lenT) {
24+
if (windowFreqs.contentEquals(expectedFreqs)) {
25+
count++
26+
}
27+
// Remove the character at the left pointer from
28+
// 'window_freqs' before advancing the left pointer.
29+
windowFreqs[s[left] - 'a']--
30+
left++
31+
}
32+
right++
33+
}
34+
return count
35+
}

0 commit comments

Comments
 (0)