-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathminimum-window-substring.cpp
139 lines (122 loc) · 4.45 KB
/
minimum-window-substring.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
* Copyright (c) 2018 Christopher Friedt
*
* SPDX-License-Identifier: MIT
*/
#include <algorithm>
#include <array>
#include <vector>
using namespace std;
class Solution {
public:
// https://leetcode.com/problems/minimum-window-substring/
string minWindow(string s, string t) {
//
// This is attempt 2 using the sliding window approach. It's basically the
// same approach that I took before except it handles duplicates in t.
//
// The algorithmic complexity in minimum-window-substring.README.txt is
// wrong but I jotted down a number of interesting notes there.
//
// If we look at the algorithmic complexity of this approach, it's
// at least O( N ), where N is the number of characters in s. In the
// worst-case scenario (where all of the search terms are at the end of s),
// it is ~O( 2N ) because we would grow the window to the size of s and then
// shrink it to N - M.
//
if (s.empty() || t.empty() || s.length() < t.length()) {
return "";
}
// t_count is a LUT so that we can use to see if a given char in s is a term
// in t. Really it's like an unordered_map<char,size_t>. We likely waste a
// fair amount of space by using a LUT. In this case, it's 1kB which can be
// significant on small platforms. It's fast though. If we were to expand
// this algorithm to s and t as string vectors, or any arbitrary key_type,
// an unordered_map<key_type,size_t> would be preferred. N.B. the reason we
// don't simply use e.g. an unordered_set<char> here is to account for
// duplicates in t.
array<size_t, 256> t_count;
fill(t_count.begin(), t_count.end(), 0);
// we keep track of the number of unique terms in t. once we have matched
// the t_count in s_count for all unique items in t, then we have found a
// valid window.
size_t n_t_unique = 0;
// populate the t_count LUT with items in t, and also count the unique items
// in t
for (auto c : t) {
if (0 == t_count[c]) {
n_t_unique++;
}
t_count[c]++;
}
// here we maintain a running count (also via LUT) of the characters in s
// contained within our window.
array<size_t, 256> s_count;
fill(s_count.begin(), s_count.end(), 0);
// keep track of the smallest window position and length
size_t win_pos = 0;
size_t win_len = SIZE_MAX;
size_t L, R, t_matched;
for (L = 0, R = 0, t_matched = 0; R < s.size();) {
// since we initialize L and R at zero, we have to pre-fill s_count if s[
// 0 ] is a term in t
if (0 == L && 0 == R) {
if (t_count[s[0]]) {
s_count[s[0]] = 1;
if (s_count[s[0]] == t_count[s[0]]) {
// we have exactly the number of s[ 0 ] in our window that exist in
// t
t_matched++;
}
}
}
if (t_matched < n_t_unique) {
// increase R to widen the search window
R++;
if (R >= s.size()) {
// do not segfault
break;
}
if (t_count[s[R]] > 0) {
// s[ R ] is a term in t, so increase the count within our widened
// search window
s_count[s[R]]++;
if (s_count[s[R]] == t_count[s[R]]) {
// we have exactly the number of s[ R ] in our window that exist in
// t
t_matched++;
}
}
} else { // if ( t_matched >= n_t_unique )
if (t_matched == n_t_unique) {
// we have found an "interesting" window
size_t new_win_pos = L;
size_t new_win_len = (R - L) + 1;
if (new_win_len < win_len) {
win_pos = new_win_pos;
win_len = new_win_len;
if (t.length() == win_len) {
// the answer cannot get any smaller than this so, assuming
// "there can be only one" (answer), return the newly found
// window.
break;
}
}
}
// increase L to narrow the search window
if (t_count[s[L]] > 0) {
// s[ L ] was a term in t, so decrease the count within our narrowing
// search window
if (s_count[s[L]] == t_count[s[L]]) {
// we no longer will have exactly the number of s[ L ] in our window
// that exist in t
t_matched--;
}
s_count[s[L]]--;
}
L++;
}
}
return (SIZE_MAX == win_len) ? "" : s.substr(win_pos, win_len);
}
};