LeetCode—76(最小覆盖子串)
方法:
第一种解决办法是用HashMap,而不是HashSet,因为要统计T串中字母的个数,而不是仅仅看某个字母是否在T串中出现。统计好T串字母的个数后,就开始遍历S串,对于S中的每个遍历到的字母,都在HashMap中的映射值减一。如果减一后的映射值仍然大于等于0,则T串中存在,我们使用计数器自增1,当计数器=T.size()时,说明窗口已经包含了T中的所有字母。此时更新一个minLen和结果res,这里的minLen是我们维护的一个全局变量,用来记录出现过的包含T串所有字母的最短的子串的长度,结果res就是这个最短的子串。然后我们要开始收缩左边界,由于我们遍历的时候,对映射值减了1,所以此时去除字母的时候,就要把减去的1加回来,此时如果加1后的值大于0了,说明此时我们少了一个T中的字母,那么cnt值就要减1了,然后移动左边界left。那么你可能会疑问,对于不在T串中的字母的映射值也这么加呀减呀的,真的大丈夫(带胶布)吗?其实没啥事,因为对于不在T串中的字母,我们减1后,变-1,cnt不会增加,之后收缩左边界的时候,映射值加1后为0,cnt也不会减少,所以并没有什么影响啦。
C++代码:
class Solution {
public:
string minWindow(string s, string t) {
string res = "";
unordered_map<char, int> letterCnt;
int left = 0, cnt = 0, minLen = INT_MAX;
for (char c : t) ++letterCnt[c];
for (int i = 0; i < s.size(); ++i) {
if (--letterCnt[s[i]] >= 0) ++cnt;
while (cnt == t.size()) {
if (minLen > i - left + 1) {
minLen = i - left + 1;
res = s.substr(left, minLen);
}
if (++letterCnt[s[left]] > 0) --cnt;
++left;
}
}
return res;
}
};
第二种:这道题也可以不用HashMap,直接用个int的数组来代替,因为ASCII只有256个字符,所以用个大小为256的int数组即可代替HashMap,但由于一般输入字母串的字符只有128个,所以也可以只用128,其余部分的思路完全相同,虽然只改了一个数据结构,但是运行速度提高了一倍,说明数组还是比HashMap快啊。
C++代码:
class Solution {
public:
string minWindow(string s, string t) {
string res = "";
vector<int> letterCnt(128, 0);
int left = 0, cnt = 0, minLen = INT_MAX;
for (char c : t) ++letterCnt[c];
for (int i = 0; i < s.size(); ++i) {
if (--letterCnt[s[i]] >= 0) ++cnt;
while (cnt == t.size()) {
if (minLen > i - left + 1) {
minLen = i - left + 1;
res = s.substr(left, minLen);
}
if (++letterCnt[s[left]] > 0) --cnt;
++left;
}
}
return res;
}
};
LeetCode—77(组合)
方法:深度优先搜索DFS解,建立一个res来保存结果的最大集合。还要定义一个保存每个小集合的out,每次放一个数到out里,如果out里数个数到了k个,则把out保存到最终结果中,否则在下一层继续调用递归。
C++代码:
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> res;
vector<int> out;
helper(n,k,1,out,res);//这里的1为level,即现在数字到哪了,只能往上取
return res;
}
void helper(int n,int k,int level,vector<int>& out,vector<vector<int>>& res){
if(out.size() == k) {res.push_back(out);return;}
for(int i = level;i <= n;i++){//此处要等于,考虑完全
out.push_back(i);
helper(n,k,i+1,out,res);
out.pop_back();
}
}
};
解法二:利用性质 C(n, k) = C(n-1, k-1) + C(n-1, k),一直拆分。(还没看懂)
C++代码:
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
if (k > n || k < 0) return {};
if (k == 0) return {{}};
vector<vector<int>> res = combine(n - 1, k - 1);
for (auto &a : res) a.push_back(n);
for (auto &a : combine(n - 1, k)) res.push_back(a);
return res;
}
};
LeetCode—78(子集)
方法:跟上一题思路差不多,区别是每次把递归的结果都保存入res中。
C++代码:(不够精简)
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> res;
vector<int> out;
int d = nums.size();
helperDFS(nums,d,0,res,out);//从零开始,与上一题不同
return res;
}
void helperDFS(vector<int>& nums,int d,int level,vector<vector<int>>& res,vector<int>& out){
res.push_back(out);
for(int i = level;i < d;i++){
out.push_back(nums[i]);
helperDFS(nums,d,i+1,res,out);
out.pop_back();
}
}
};
LeetCode—79(单词搜索)
方法:这道题典型的深度优先遍历DFS的应用
C++代码:
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
if(board.empty() || board[0].empty()) return false;
int m = board.size(),n = board[0].size();
vector< deque<bool> > visited(m, deque<bool>(n,false));
for(int i = 0;i < m;i++){
for(int j = 0;j < n;j++){
if(search(board,word,visited,i,j,0)) return true;
}
}
return false;
}
bool search(vector<vector<char>>& board,string word,vector<deque<bool>>& visited,int i,int j,int idx){
if(idx == word.size()) return true;
int m = board.size(),n = board[0].size();
if(i < 0 || j < 0 || i >= m || j >= n || visited[i][j] || board[i][j] != word[idx]) return false;
visited[i][j] = true;
bool res = search(board,word,visited,i+1,j,idx+1)
|| search(board,word,visited,i-1,j,idx+1)
|| search(board,word,visited,i,j+1,idx+1)
|| search(board,word,visited,i,j-1,idx+1);
visited[i][j] = false;//这步很重要;记住
return res;
}
};
LeetCode—80(删除排序数字中的重复项II)
方法:此题与26题及其相似,都是利用快慢指针。26题是每个元素只出现一次,而本题是两次,所以需要一个count进行计数。
C++代码:
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if(nums.size() <= 2) return nums.size();//很重要跟上一题的判断条件不一样了
int pre = 0,cur = 1,n = nums.size(),count = 1;//此处cur也为1
while(cur < n){
if(nums[pre] == nums[cur] && count == 0) ++cur;
else{
if(nums[pre] == nums[cur]) --count;
else count = 1;
nums[++pre] = nums[cur++];
}
}
return pre+1;
}
};