1. Hash Table1.1 Sliding Window SubstringLC3: Longest substring without repeating charactersLC159: Longest substring with at most two distinct charactersLC340: Longest substring with at most K distinct charactersLC424: Longest repeating character replacementLC395: Longest substring with at least K repeating charactersLC438: Find all anagrams in a stringLC76: Minimum window substringLC30: Substring with concatenation of all words1.2 Sliding WindowLC239: Contains duplicate IILC220: Contains duplicate IIILC239: Sliding window maximumLC480: Sliding window median1.3 StringsLC49: Group anagramsLC336: Palindrome pairsLC291: Word pattern IILC244: Shortest word distance IILC249: Group shifted stringsLC358: Rearrange string k distance apartTask schedule1.4 Geometry and MathLC447: Number of bloomerangsLC356: Line reflectionLC149: Max points on a lineLC166: Fraction to recurring decimalLC380: Insert delete getrandom O(1)LC381: Insert delete get random O(1) - Duplicates allowed1.5 OthersLC508: Most frequent subtree sum2. MatrixLC42: Trapping rain waterLC11: Container with most waterLC407: Trapping rain water IILC84: Largest rectangle in histogramLC221: Maximal squareLC363: Max sum of rectangle no larger than K
Hash table questions: https://leetcode.com/tag/hash-table/
Given a string, find the length of the longest substring without repeating characters.
two-pointers: 'i' scans the whole string, 'j' points to the start of each no-repeat window whenever we find a repeated char, we move 'j' to the right of last occurrence index (if 'j' falls behind the new pos before movement). we keep putting chars into the map, updating the index, and counting the non-repeat length.
int lengthOfLongestString(string s) {
unordered_map<char, int> mp;
int maxLen = 0;
for(int j=0, i=0; i<n; ++i) {
char c = s[i];
if(mp.find(c) != mp.end()) {
j = std::max(j, mp[c]+1);
}
mp[c] = i;
maxLen = std::max(maxLen, i-j+1);
}//--for
return maxLen;
}
Given a string, find the length of the longest substring T that contains at most K distinct characters.
when map size is over 2, i.e., 3 or more chars have been found, then move pointer 'j' until K chars are there.
int lengthOfLongestSubstringTwoDistinct(string s, int K) {
unordered_map<char, int> mp;
int maxLen = 0;
for(int j=0, i=0; i<n; ++i) {
char c = s[j];
++ mp[c];
while(mp.size()>K) {
if(--mp[s[j]]==0) mp.erase(s[j]);
++ j;
}
maxLen = std::max(maxLen, i-j+1);
}//--for
return maxLen;
}
Given a string that consists of only uppercase English letters, you can replace any letter in the string with another letter at most k times. Find the length of a longest substring containing all repeating letters you can get after performing the above operations.
The problem is similar to longest substring with most K distinct chars. But this time, the constraint is we can only have most K characters that is different with the most frequent character in the substring.
int characterReplacement(string s, int k) {
unordered_map<char, int> mp;
int maxLen = 0, freq = 0;
for(int j=0, i=0; i<n; ++i) {
char c = s[i];
freq = std::max(freq, ++mp[c]);
while((i-j+1) - freq > k) {
if(--mp[s[j]]==0) mp.erase(s[j]);
++ j;
}
maxLen = std::max(maxLen, i-j+1);
}//--for
return maxLen;
}
Find the length of the longest substring T of a given string (consists of lowercase letters only) such that every character in T appears no less than k times.
first record counts of every character in a hashmap then, locate the first character that appear less than k times in the string. this character is definitely not included in the result, and that separates the string into two parts. keep doing this recursively and the maximum of the left/right part is the answer.
class Solution {
public:
int longestSubstring(string s, int k) {
int n = s.length();
if(n==0 || n<k) return 0;
vector<int> mp(26, 0);
for(int i=0; i<n; ++i) {
int cind = s[i] - 'a';
++ mp[cind]; //count appearance of each char
}//--for
int idx = 0;
while(idx<n && mp[s[idx]-'a']>=k) ++ idx;
if(idx == n) return n;
int left = longestSubstring(s.substr(0, idx), k);
int right = longestSubstring(s.substr(idx+1), k);
return std::max(left, right);
}
};
Given a string s and a non-empty string p, find all the start indices of p's anagrams in s.
vector<int> findAnagrams(string s, string p) {
int n = s.length(), m = p.length();
if(n < m) return {};
vector<int> rst;
vector<int> pmap(26,0), wmap(26,0); //'p' map and sliding window map
for(auto c : p) ++ pmap[c-'a']; //init pmap
for(int i=0; i<m; ++i) ++ wmap[s[i]-'a']; //init wmap
if(pmap == wmap) rst.push_back(0);
for(int i=m; i<n; ++i){
char c = s[i];
++ wmap[c-'a'];
-- wmap[s[i-m]-'a'];
if(pmap == wmap) rst.push_back(i-m+1);
}//--for
return rst;
}
Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).
1) build a map<char, int> for string T, count the map size, M 2) use two pointers to search string S: whenever we find a char in T, we place/update the map, and only count when it is new or times less than that in T map 3) when count reaches M, we have found a window holding all chars in T, and now we test to shrink the left to maintain the meet condition (when stop, leftmost char must be an effective one in T) 4) calculate the length and compare against min 5) move left pointer forward, decrease count, and repeat the above steps
string findMinWindow(string S, string T) {
if(S.length() < T.length()) return "";
unordered_map<char, int> mp;
for(auto c : T) ++ mp[c];
unordered_map<char, int> seen;
int count = 0, minLen = INT_MAX, minStart = 0;
for(int j=0, i=0; i<S.length(); ++i) {
char c = s[i];
if(mp.find(c) != mp.end()) {
++ seen[c];
if(seen[c] <= mp[c]) ++ count;
}
if(count == mp.size()) {
while(mp.find(s[j])==mp.end() || seen[s[j]]>mp[s[j]]) {
if(seen.find(s[j])!=seen.end()) --seen[s[j]];
++ j;
}
}
//now 'j' points to an effective char
int curLen = i-j+1;
if(curLen < minLen) {
minLen = curLen;
minStart = j;
}
++ j;
-- count;
-- seen[s[j]];
}//--for
return minLen==INT_MAX ? "" : s.substr(minStart, minLen);
}
You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening characters.
Each time look forward total 'words' length, if all matches, record the index and move one step forward; if certain word matches more times, or some word doesn't match, break and test next sequence
vector<int> findSubstring(string s, vector<string>& words) {
int nw = words.size(); int len = words[0].length();
if(s.length() < nw*len) return {};
unordered_map<string, int> dict;
for(auto wd : words) ++ dict[wd];
unordered_map<string, int> seen;
vector<int> rst;
for(int i=0; i<s.length()-nw*len+1; ++i) {
seen.clear();
int j = 0;
for(; j<nw; ++j) {
string wd = s.substr(i+j*len, len); //extract the word
if(dict.find(wd) == dict.end()) break;
++ seen[wd];
if(seen[wd] > dict[wd]) break;
}//--for
if(j == nw) rst.push_back(i);
}//--for
return rst;
}
maintain a set containing unique values from nums[i-k] to nums[i-1] if(nums[i]) is in set s, then return true; ow, update the set
bool containsNearbyDuplicate(vector<int>& nums, int k) {
int n = nums.size();
if(n == 0) return false;
if(n <= k) k = n-1;
unordered_set<int> set;
for(int i=0; i<nums.size(); ++i) {
if(i > k) set.erase(nums[i-k-1]);
if(set.find(nums[i]) != set.end()) return true;
set.insert(nums[i]);
}//--for
return false;
}
Given an array of integers, find out whether there are two distinct indices i and j in the array such that the absolute difference between nums[i] and nums[j] is at most t and the absolute difference between i and j is at most k.
Using a set to keep the k+1-lenght array, which all elements are distinct. Before the container's size reached k+1, we just find the first elment that is not less than [nums[i]-t] and judge the element's value whether it is less than [nums[i]+t].
<==>
set<long long int> set;
for(int i=0; i<n; ++i) {
if(i > k) set.erase(nums[i-k-1]);
auto pos = set.lower_bound((long long)nums[i]-t); //time: log(k)
if(pos != set.end() && (long long)*pos-(long long)nums[i]<=t) return true;
set.insert((long long)nums[i]);
}//--for
return false;
//see: http://www.cnblogs.com/grandyang/p/4545261.html
Given an array of strings, group anagrams together.
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
int n = strs.size();
std::vector<std::vector<std::string>> rst;
if(n == 0) return rst;
std::unordered_map<std::string, int> map; //hash map
for(int ii=0; ii<n; ++ii){
std::string word = strs[ii];
std::sort(word.begin(), word.end());
if(map.find(word)==map.end()) { //first see
int size = map.size();
map[word] = size; //map.size(); //key=word, value=loc in vector
rst.push_back({strs[ii]});
} else { //already appeared
int pos = map[word];
rst[pos].push_back(strs[ii]);
}
}//-for
return rst;
}
};
Design a class which receives a list of words in the constructor, and implements a method that takes two words word1 and word2 and return the shortest distance between these two words in the list.
Given a list of strings which contains only lowercase alphabets, group all strings that belong to the same shifting sequence.
Given a non-empty string s and an integer k, rearrange the string such that the same characters are at least distance k from each other.
All input strings are given in lowercase letters. If it is not possible to rearrange the string, return an empty string ""
.
HashMap + Max Heap + Greedy We work on chars with highest frequency, and put them k-distance apart. And, in between we place the remaining (k-1) chars. 1) build the mapping between the char and frequency 2) feed to mapping info to max heap, and pick up the most frequent one to place; we know that the chars cannot be adjacent, and thus we remove the char from the heap and save it somewhere else, then we pick up the next (k-1) chars in such fashion. After the round, i.e., placing k chars, we place the removed ones back to the heap, and repeat the above steps; 3) the rearrangment is impossible if the heap becomes empty, as we have no way to make them k-distance apart.
string rearrangeString(string s, int k) {
int len = s.length();
if(k==0) return s;
//count char frequncy
unordered_map<char, int> mp;
for(auto c : s) ++mp[c];
//place into heap
using T = std::pair<int, char>;
priority_queue<T> pq;
for(auto it=mp.begin(); it!=mp.end(); ++it)
pq.push({it->second, it->first});
//greedy to put
string rst = "";
while(!pq.empty()) {
vector<T> cache;
int cnt = std::min(len, k);
for(int i=0; i<cnt; ++i) {
if(pq.empty()) return "";
T item = pq.top(); pq.pop();
rst += item.second;
if(--item.first > 0)
cache.push_back(item);
-- len;
}//--for
for(auto item : cache) pq.push(item);
}//--while
return rst;
}
//see: http://juneend.blogspot.com/2016/07/358-rearrange-string-k-distance-apart.html
//see: http://www.cnblogs.com/grandyang/p/5586009.html
-Task schedule I
string taskSchedule(vector<int>& tasks, int cooldown){
string rst = "";
int cycle = 0;
unordered_map<int, int> mp; //key=taskID, value=last schedule time
for(int i=0; i<tasks.size(); ) {
int task = tasks[i];
if(mp.find(task)==mp.end() || cycle>=mp[task]+cooldown) {
rst += std::to_string(task);
mp[task] = cycle;
++ i;
} else {
rst += "-";
}
++ cycle;
}//--for
}
-Task schedule II
int taskSchedule(vector<int>& tasks, int cooldown){
int time = 0;
unordered_map<int, int> mp; //key=taskID, value=last schedule time
for(int i=0; i<tasks.size(); ++i) {
int task = tasks[i];
if(mp.find(task)!=mp.end() && cycle<=mp[task]+cooldown){
int idlecycles = mp[task]+cooldown - cycle;
time += idlecycles;
}
++ time;
mp[task] = time;
}//--for
}
-Task schedule III
Given a sequence of tasks like A B C
(means 3 different tasks), and a cold time, which means you need to wait for that much time to start next [same] task, now find the sequence of tasks such that all tasks are finished in minimum time.
Input: string, n, e.g., AAABBB, 2
Output: AB_AB_AB ("_" represents do nothing and wait)
int cnt = k; //std::min(len, k);
//if(pq.empty()) return "";
if(pq.empty()) {rst+="-"; continue;}
Given two integers representing the numerator and denominator of a fraction, return the fraction in string format.
If the fractional part is repeating, enclose the repeating part in parentheses.
http://blog.csdn.net/ljiabin/article/details/42025037
Design a data structure that supports all following operations in average O(1) time.
Design a data structure that supports all following operations in average O(1) time.
unordered_map<int,priority_queue<int>> mp; //cannot use 'vector<int>' here
vector<int> data;
//see: https://discuss.leetcode.com/topic/53687/c-solution-using-map-and-vector-with-detailed-explanation/2
//see: http://www.cnblogs.com/grandyang/p/5756148.html
Given the root of a tree, you are asked to find the most frequent subtree sum.
unordered_map<int,int> mp;
getSum(root, mp);
unordered_map<int, vector<int>> cntMap;
int maxCnt = 0;
for(auto it=mp.begin(); it!=mp.end(); ++it) {
int val = it->second;
maxCnt = std::max(val, maxCnt);
cntMap[val].push_back(it->first);
}//--for
return cntMap[maxCnt];
Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.
http://www.cnblogs.com/boring09/p/4231906.html
Given a 2D binary matrix filled with 0's and 1's, find the largest square containing only 1's and return its area.
int maxSide = 0;
//topmost row
for(int j=0; j<c; ++j) {
dp[0][j] = matrix[0][j] - '0';
maxSide = std::max(maxSide, dp[0][j]);
}
//leftmost col
for(int i=0; i<r; ++i) {
dp[i][0] = matrix[i][0] - '0';
maxSide = std::max(maxSide, dp[i][0]);
}
for(int i=1; i<r; ++i) {
for(int j=1; j<c; ++j) {
if(matrix[i][j] == '1') {
dp[i][j] = std::min(dp[i-1][j-1], std::min(dp[i-1][j], dp[i][j-1])) + 1;
if(dp[i][j] > maxSide) maxSide = dp[i][j];
}
}//--for
}//--for
return maxSide * maxSide;