CONTENTS
- LeetCode 76. 最小覆盖子串(困难)
 - LeetCode 77. 组合(中等)
 - LeetCode 78. 子集(中等)
 - LeetCode 79. 单词搜索(中等)
 
LeetCode 76. 最小覆盖子串(困难)
【题目描述】
给你一个字符串 s、一个字符串 t。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 ""。
注意:
- 对于 
t中重复字符,我们寻找的子字符串中该字符数量必须不少于t中该字符数量。 - 如果 
s中存在这样的子串,我们保证它是唯一的答案。 
【示例1】
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
 
【示例2】
输入:s = "a", t = "a"
输出:"a"
解释:整个字符串 s 是最小覆盖子串。
 
【示例3】
输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。
 
【提示】
 
     
      
       
       
         1 
        
       
         ≤ 
        
       
         s 
        
       
         . 
        
       
         l 
        
       
         e 
        
       
         n 
        
       
         g 
        
       
         t 
        
       
         h 
        
       
         , 
        
       
         t 
        
       
         . 
        
       
         l 
        
       
         e 
        
       
         n 
        
       
         g 
        
       
         t 
        
       
         h 
        
       
         ≤ 
        
       
         1 
        
        
        
          0 
         
        
          5 
         
        
       
      
        1\le s.length, t.length\le 10^5 
       
      
    1≤s.length,t.length≤105
 s 和 t 由英文字母组成
【分析】
本题是滑动窗口的一个经典的应用,我们枚举 s 中的每个右端点  
     
      
       
       
         i 
        
       
      
        i 
       
      
    i,对于每个  
     
      
       
       
         i 
        
       
      
        i 
       
      
    i 都找出最近的一个左端点  
     
      
       
       
         j 
        
       
      
        j 
       
      
    j,使得 s[j, i] 中包含 t 中的所有字符。
能用滑动窗口(双指针)的题目一定要具有单调性,即当  
     
      
       
       
         i 
        
       
      
        i 
       
      
    i 往右移动的过程中  
     
      
       
       
         j 
        
       
      
        j 
       
      
    j 一定不会往左移动。假设 s[j, i] 中已经包含 t 中的所有字符,那么当  
     
      
       
       
         i 
        
       
      
        i 
       
      
    i 向右移动变为  
     
      
       
        
        
          i 
         
        
          ′ 
         
        
       
      
        i' 
       
      
    i′ 后 s[j, i'] 一定也包含 t 中的所有字符,因此  
     
      
       
       
         j 
        
       
      
        j 
       
      
    j 不可能往左移动变成 s[j', i']。
还有一个问题是如何快速判断当前区间中是否包含 t 中的所有字符,我们可以用哈希表分别统计 t 中每个字符出现的次数(t_cnt)以及滑动窗口内每个字符出现的次数(s_cnt),然后使用一个变量 cnt 统计 t 中有多少字符被滑动窗口包含了,如果 cnt 等于 t 的长度则说明全部字符以及被包含了,那么如何精准统计 cnt 呢?分情况讨论即可:
- 若当前字符 
c在滑动窗口中出现的次数已经大于t中该字符的数量则不累计cnt; - 若当前字符 
c在滑动窗口中出现的次数小于等于t中该字符的数量则将cnt加一。 
如果字符 s[j] 出现的次数大于 t 中该字符的数量则可以将  
     
      
       
       
         j 
        
       
      
        j 
       
      
    j 向右移动。
【代码】
class Solution {
public:
    string minWindow(string s, string t) {
        unordered_map<char, int> s_cnt, t_cnt;
        int cnt = 0;
        string res;
        for (auto &c: t) t_cnt[c]++;
        for (int i = 0, j = 0; i < s.size(); i++)
        {
            s_cnt[s[i]]++;
            if (s_cnt[s[i]] <= t_cnt[s[i]]) cnt++;
            while (s_cnt[s[j]] > t_cnt[s[j]]) s_cnt[s[j]]--, j++;
            if (cnt == t.size() && (res.empty() || i - j + 1 < res.size()))
                res = s.substr(j, i - j + 1);
        }
        return res;
    }
};
 
LeetCode 77. 组合(中等)
【题目描述】
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
 你可以按任何顺序返回答案。
【示例1】
输入:n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]
 
【示例2】
输入:n = 1, k = 1
输出:[[1]]
 
【提示】
 
     
      
       
       
         1 
        
       
         ≤ 
        
       
         n 
        
       
         ≤ 
        
       
         20 
        
       
      
        1\le n\le 20 
       
      
    1≤n≤20
  
     
      
       
       
         1 
        
       
         ≤ 
        
       
         k 
        
       
         ≤ 
        
       
         n 
        
       
      
        1\le k\le n 
       
      
    1≤k≤n
【分析】
DFS 搜索即可,需要注意判重,可以指定搜索顺序从小到大,即如果搜过 i i i 后那么下一个数就从 i + 1 i+1 i+1 开始搜。
【代码】
class Solution {
public:
    vector<vector<int>> res;
    vector<int> v;
    vector<vector<int>> combine(int n, int k) {
        dfs(n, k, 1);
        return res;
    }
    void dfs(int n, int k, int now)
    {
        if (!k) { res.push_back(v); return; }
        for (int i = now; i <= n; i++)
        {
            v.push_back(i);
            dfs(n, k - 1, i + 1);
            v.pop_back();
        }
    }
};
 
LeetCode 78. 子集(中等)
【题目描述】
给你一个整数数组 nums,数组中的元素互不相同。返回该数组所有可能的子集(幂集)。
 解集不能包含重复的子集。你可以按任意顺序返回解集。
【示例1】
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
 
【示例2】
输入:nums = [0]
输出:[[],[0]]
 
【提示】
 
     
      
       
       
         1 
        
       
         ≤ 
        
       
         n 
        
       
         u 
        
       
         m 
        
       
         s 
        
       
         . 
        
       
         l 
        
       
         e 
        
       
         n 
        
       
         g 
        
       
         t 
        
       
         h 
        
       
         ≤ 
        
       
         10 
        
       
      
        1\le nums.length\le 10 
       
      
    1≤nums.length≤10
  
     
      
       
       
         − 
        
       
         10 
        
       
         ≤ 
        
       
         n 
        
       
         u 
        
       
         m 
        
       
         s 
        
       
         [ 
        
       
         i 
        
       
         ] 
        
       
         ≤ 
        
       
         10 
        
       
      
        -10\le nums[i]\le 10 
       
      
    −10≤nums[i]≤10
 nums 中的所有元素互不相同
【分析】
这题如果用搜索来写其实和上一题一样,只需要枚举 k k k 的大小,然后对于每个 k k k 都 DFS 一遍即可,这种方式就不给出代码了。
或者也可以换一种方式搜索,对于每个数我们都可以选或不选一共有两种方案,在 DFS 的时候将这两种方案都考虑进去即可。
当我们想枚举每个数选或者不选这种子集时,可以使用一个二进制数来表示,例如要枚举三个数选或不选,就可以用一个三位的二进制数表示,当这个二进制数为 000 时表示三个数都不选,为 001 是表示只选第三个数,以此类推。
【代码】
【DFS 实现代码】
class Solution {
public:
    vector<vector<int>> res;
    vector<int> v;
    vector<vector<int>> subsets(vector<int>& nums) {
        dfs(nums, 0);
        return res;
    }
    void dfs(vector<int>& nums, int u)
    {
        if (u == nums.size()) { res.push_back(v); return; }
        dfs(nums, u + 1);  // 不选nums[u]
        v.push_back(nums[u]);  // 选nums[u]
        dfs(nums, u + 1);
        v.pop_back();
    }
};
 
【迭代实现代码】
class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> res;
        int n = nums.size();
        for (int i = 0; i < 1 << n; i++)
        {
            vector<int> v;
            for (int j = 0; j < n; j++)
                if (i >> j & 1) v.push_back(nums[j]);
            res.push_back(v);
        }
        return res;
    }
};
 
LeetCode 79. 单词搜索(中等)
【题目描述】
给定一个 m x n 二维字符网格 board 和一个字符串单词 word。如果 word 存在于网格中,返回 true;否则,返回 false。
 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
【示例1】

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true
 
【示例2】

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
输出:true
 
【示例3】

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"
输出:false
 
【提示】
 
     
      
       
       
         m 
        
       
         = 
        
       
         = 
        
       
         b 
        
       
         o 
        
       
         a 
        
       
         r 
        
       
         d 
        
       
         . 
        
       
         l 
        
       
         e 
        
       
         n 
        
       
         g 
        
       
         t 
        
       
         h 
        
       
      
        m == board.length 
       
      
    m==board.length
  
     
      
       
       
         n 
        
       
         = 
        
       
         = 
        
       
         b 
        
       
         o 
        
       
         a 
        
       
         r 
        
       
         d 
        
       
         [ 
        
       
         i 
        
       
         ] 
        
       
         . 
        
       
         l 
        
       
         e 
        
       
         n 
        
       
         g 
        
       
         t 
        
       
         h 
        
       
      
        n == board[i].length 
       
      
    n==board[i].length
  
     
      
       
       
         1 
        
       
         ≤ 
        
       
         m 
        
       
         , 
        
       
         n 
        
       
         ≤ 
        
       
         6 
        
       
      
        1\le m, n\le 6 
       
      
    1≤m,n≤6
  
     
      
       
       
         1 
        
       
         ≤ 
        
       
         w 
        
       
         o 
        
       
         r 
        
       
         d 
        
       
         . 
        
       
         l 
        
       
         e 
        
       
         n 
        
       
         g 
        
       
         t 
        
       
         h 
        
       
         ≤ 
        
       
         15 
        
       
      
        1\le word.length\le 15 
       
      
    1≤word.length≤15
 board 和 word 仅由大小写英文字母组成
【分析】
【代码】
                


















