zoukankan      html  css  js  c++  java
  • [LeetCode] Minimum Window Substring 散列映射问题

    题目:


    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).

    For example,
    S = "ADOBECODEBANC"
    T = "ABC"

    Minimum window is "BANC".

    Note:
    If there is no such window in S that covers all characters in T, return the emtpy string "".

    If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.

    Hide Tags
     Hash Table Two Pointers String
         在字符串 S 中查找最小的窗口,使窗口中全部包含字符串T 中的字符,(不按顺序),需要注意的地方:
    • T 中的字符可以重复,窗口需要重复包含。
    • 测试 实验中的是SCII字符 ,所以可以用128位数组代替 hash table。
    • leetcode  c++ 中不能用 hash_map。

    思路:

    1. 使用一个映射int need(hash table 或者 128位数组) 存储T中个字符需要的个数,因为需求可能为负,所以用int。
    2. 使用一个映射bool exitst(hash table 或者 128位数组) 存储T中个字符是否存在,使用hashtable 也构造这个,因为find 是遍历查找的。
    3. 用一个var 记录窗口中符合T 中char 的个数。
    4. 用下表start、last 标记窗口位置,start 指向窗口内第一个char,last 指向窗口外右边第一个char(包括结尾)。
    5. 每次循环加入或删除(记录一个flag)一个字符,如果不存在便继续循环。
    6. 通过判断加入删除flag进行操作,更新need 表,更新var, 如果等于T 的长度,更新返回记录。
    7. 循环结束判断能否查找。
     下面是我写的,需要的时间复杂度为O(length(S)),即O(n),空间复杂度为O(length(T)):
     1 #include <string>
     2 #include <hash_map>
     3 #include <iostream>
     4 #include <map>
     5 using namespace std;
     6 using namespace __gnu_cxx;
     7 
     8 class Solution {
     9 public:
    10     string minWindow(string S, string T) {
    11         int numS = S.length(),numT = T.length();
    12         if(numS<1||numT<1)    return "";
    13         int WinStart=0,WinLast=0,WinCount =0,retStart,leng=INT_MAX;
    14         hash_map<char, int > need;
    15         hash_map<char, bool > exist;
    16         for(int i =0;i<numT;i++){
    17             need[T[i]]++;
    18             exist[T[i]] = true;
    19         }
    20 
    21         bool addorminus;
    22         char curchar;
    23         while(WinStart<=numS-numT){
    24             if(WinCount!=numT&&WinLast<numS){
    25                 addorminus = true;
    26                 curchar = S[WinLast++];
    27             }
    28             else{
    29                 addorminus = false;
    30                 curchar = S[WinStart++];
    31             }
    32             if(!exist[curchar]) continue;
    33             if(addorminus){
    34                 if(need[curchar]>0)  WinCount++;
    35                 need[curchar]--;
    36                 if(WinCount==numT&&leng>WinLast - WinStart){
    37                     retStart = WinStart;
    38                     leng = WinLast - WinStart;
    39                 }
    40             }
    41             else{
    42                 if(WinCount==numT&&leng>WinLast - WinStart+1){
    43                     retStart = WinStart-1;
    44                     leng = WinLast - WinStart+1;
    45                 }
    46                 need[curchar] ++;
    47                 if(need[curchar]>0)  WinCount--;
    48             }
    49         }
    50         if(leng==INT_MAX)
    51             return "";
    52         return S.substr(retStart,leng);
    53     }
    54 };
    55 
    56 int main()
    57 {
    58     string s = "1A123BAC1";
    59     string t = "AABC";
    60     Solution sol;
    61 
    62     string ret = sol.minWindow(s,t);
    63     cout<<ret<<endl;
    64     return 0;
    65 }
    View Code
     leetcode 讨论里面有另外一个实现,也是O(n),实现类似,不同的是循环内是通过判断窗口中已经有T中字符的个数来进行 add or delete,我写的是通过目标操作字符来进行,逻辑上没有ta写的方便。
     https://oj.leetcode.com/discuss/10337/accepted-o-n-solution
     
     
     1 class Solution {
     2 public:
     3     string minWindow(string S, string T) {
     4         if (S.empty() || T.empty())
     5         {
     6             return "";
     7         }
     8         int count = T.size();
     9         int require[128] = {0};
    10         bool chSet[128] = {false};
    11         for (int i = 0; i < count; ++i)
    12         {
    13             require[T[i]]++;
    14             chSet[T[i]] = true;
    15         }
    16         int i = -1;
    17         int j = 0;
    18         int minLen = INT_MAX;
    19         int minIdx = 0;
    20         while (i < (int)S.size() && j < (int)S.size())
    21         {
    22             if (count)
    23             {
    24                 i++;
    25                 require[S[i]]--;
    26                 if (chSet[S[i]] && require[S[i]] >= 0)
    27                 {
    28                     count--;
    29                 }
    30             }
    31             else
    32             {
    33                 if (minLen > i - j + 1)
    34                 {
    35                     minLen = i - j + 1;
    36                     minIdx = j;
    37                 }
    38                 require[S[j]]++;
    39                 if (chSet[S[j]] && require[S[j]] > 0)
    40                 {
    41                     count++;
    42                 }
    43                 j++;
    44             }
    45         }
    46         if (minLen == INT_MAX)
    47         {
    48             return "";
    49         }
    50         return S.substr(minIdx, minLen);
    51     }
    52 };
    View Code
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    高斯消元(学习笔记)
    离散化(学习笔记)
    并查集(学习笔记)
    模板---负环(学习笔记)
    差分数组 前缀和(学习笔记)
    manacher马拉车算法(学习笔记)
    Java 常用对象-Object类
    Java 值传递和引用传递
    Java 集合-Set接口和三个子类实现
    Java 集合-Arrays工具类的介绍
  • 原文地址:https://www.cnblogs.com/Azhu/p/4127606.html
Copyright © 2011-2022 走看看