Algorithm 字符串x中包含字符串y的所有字符的最小窗口宽度

Algorithm 字符串x中包含字符串y的所有字符的最小窗口宽度,algorithm,Algorithm,在字符串x中查找包含另一个字符串y的所有字符的最小窗口宽度。例如: String x = "coobdafceeaxab" String y = "abc" 答案应该是5,因为x中包含y所有三个字母的最短子字符串是“bdafc” 我可以想出一个简单的解决方案,它的复杂性是O(n^2*log(m)),其中n=len(x)和m=len(y)。有人能提出更好的解决方案吗?谢谢 更新< /强>:现在想想,如果我把我的集合改成 Tr1::unOrdEdEdMult,那么我可以把复杂性降低到O(n^ 2

在字符串
x
中查找包含另一个字符串
y
的所有字符的最小窗口宽度。例如:

String x = "coobdafceeaxab"
String y = "abc"
答案应该是5,因为
x
中包含
y
所有三个字母的最短子字符串是“bdafc”

我可以想出一个简单的解决方案,它的复杂性是
O(n^2*log(m))
,其中
n=len(x)
m=len(y)
。有人能提出更好的解决方案吗?谢谢


<强>更新< /强>:现在想想,如果我把我的集合改成<代码> Tr1::unOrdEdEdMult,那么我可以把复杂性降低到O(n^ 2)< /> >,因为插入和删除都应该是代码> O(1)< /C> >。< / P> < P>这是我在C++中的解决方案,仅供参考。 更新:最初我使用std::set,现在我将其更改为tr1::unordered_map,以将复杂性降低到n^2,否则这两个实现看起来非常相似,为了避免这篇文章太长,我只列出了改进的解决方案

#include <iostream>
#include <tr1/unordered_map>
#include <string>

using namespace std;
using namespace std::tr1;

typedef tr1::unordered_map<char, int> hash_t;

// Returns min substring width in which sentence contains all chars in word
// Returns sentence's length + 1 if not found
size_t get_min_width(const string &sent, const string &word) {
    size_t min_size = sent.size() + 1;
    hash_t char_set; // char set that word contains
    for (size_t i = 0; i < word.size(); i++) {
        char_set.insert(hash_t::value_type(word[i], 1));
    }
    for (size_t i = 0; i < sent.size() - word.size(); i++) {
        hash_t s = char_set;
        for (size_t j = i; j < min(j + min_size, sent.size()); j++) {
            s.erase(sent[j]);
            if (s.empty()) {
                size_t size = j - i + 1;
                if (size < min_size) min_size = size;
                break;
            }
        }
    }
    return min_size;
}

int main() {
    const string x = "coobdafceeaxab";
    const string y = "abc";
    cout << get_min_width(x, y) << "\n";
}
#包括
#包括
#包括
使用名称空间std;
使用名称空间std::tr1;
typedef tr1::无序映射散列;
//返回包含word中所有字符的句子的最小子字符串宽度
//如果未找到,则返回句子长度+1
大小\u t获取\u最小\u宽度(常量字符串和已发送、常量字符串和字){
size\u t min\u size=sent.size()+1;
hash\u t char\u set;//单词包含的字符集
对于(size_t i=0;i时间:O(n)(一次通过)
空格:O(k)

我会这样做:
为字符串Y中的所有字符创建一个哈希表(我假设所有字符在Y中都不同)

第一关:
从字符串X的第一个字符开始。
更新哈希表,例如:对于键“a”,输入位置(如1)。
继续这样做,直到从Y中获取所有字符(直到哈希表中的所有键都有值)。
如果您再次获得某个字符,请更新其较新的值并删除较旧的值

第一次通过后,从哈希表中获取最小值和最大值。
这是迄今为止观察到的最小窗口

现在,转到字符串X中的下一个字符,更新哈希表,看看是否得到更小的窗口


编辑:

让我们举个例子:
字符串x=“coobdafceeaxab”
字符串y=“abc”

首先从Y字符初始化哈希表。
h[a]=-1
h[b]=-1
h[c]=-1

现在,从X的第一个字符开始。
第一个字符是c,h[c]=0
第二个字符(o)不是哈希的一部分,请跳过它。
..
第四个字符(b),h[b]=3
..
第六个字符(a),输入哈希表h[a]=5。
现在,哈希表中的所有键都有一些值。
最小值为0(c),最大值为5(a),到目前为止最小窗口为6(0到5)。
第一关完成了

获取下一个字符。f不是哈希表的一部分,请跳过它。
下一个字符(c),更新哈希表h[c]=7。
查找新窗口,最小值为3(b),最大值为7(c)。
新窗口为3到7=>5

继续这样做,直到字符串X的最后一个字符

我希望现在天气晴朗。
编辑

从散列中查找最大值和最小值有一些问题。
我们可以维护已排序的链接列表,并将其映射到哈希表。
每当链接列表中的任何元素发生更改时,都应将其重新映射到哈希表。
这两种操作都是O(1)

总空间为m+m


编辑

以下是上述问题的小规模可视化: 对于“coobdafceeaxab”和“abc”

第0步:
初始双链接列表=空
初始哈希表=NULL

第一步:
头[c,0]尾
h[c]=[0,'指向LL'中c节点的指针]

第二步:
头[c,0][b,3]尾
h[c]=[0',指向LL']中的c节点的指针,h[b]=[3',指向LL']中的b节点的指针

第三步:
头[c,0][b,3][a,5]尾
h[c]=[0',指向LL']中的c节点的指针,h[b]=[3',指向LL']中的b节点的指针,h[a]=[5',指向LL']中的节点的指针
最小窗口=>与尾部和头部的差异=>(5-0)+1=>长度:6

第四步:
将C的条目更新到此处的索引7。(从链表中删除“C”节点并在尾部追加)
头[b,3][a,5][c,7]尾
h[c]=[7',指向LL']中的c节点的新指针,[b]=[3',指向LL']中的b节点的指针,h[a]=[5',指向LL']中的节点的指针,
最小窗口=>与尾部和头部的差异=>(7-3)+1=>长度:5

等等

请注意,上面的链表更新和哈希表更新都是O(1)。
如果我错了,请纠正我


摘要:

时间复杂度:O(n)和一次通过

空间复杂度:O(k),其中k是字符串Y的长度

int min_width(const string& x, const set<char>& y) {
  vector<int> at;
  for (int i = 0; i < x.length(); i++)
    if (y.count(x[i]) > 0)
      at.push_back(i);

  int ret = x.size();
  int start = 0;
  map<char, int> count;

  for (int end = 0; end < at.size(); end++) {
    count[x[at[end]]]++;
    while (count[x[at[start]]] > 1)
      count[x[at[start++]]]--;
    if (count.size() == y.size() && ret > at[end] - at[start] + 1)
      ret = at[end] - at[start] + 1;
  }
  return ret;
}
int最小宽度(常量字符串和x、常量集和y){
向量at;
对于(int i=0;i0)
at.推回(i);
int-ret=x.size();
int start=0;
地图计数;
对于(int end=0;end1)
计数[x[在[start++]]]--;
如果(count.size()==y.size()&&ret>在[结束]-在[开始]+1)
ret=在[结束]-在[开始]+1;
}
返回ret;
}
编辑:这是杰克想法的一个实现。它的时间复杂性与我的相同,但没有内在的复杂性
int min_width(const string& x, const set<char>& y) {
  int ret = x.size();
  map<char, int> index;
  set<int> index_set;

  for (int j = 0; j < x.size(); j++) {
    if (y.count(x[j]) > 0) {
      if (index.count(x[j]) > 0)
        index_set.erase(index[x[j]]);
      index_set.insert(j);
      index[x[j]] = j;
      if (index.size() == y.size()) {
        int i = *index_set.begin();
        if (ret > j-i+1)
          ret = j-i+1;
      }
    }
  }
  return ret;
}
static int minWidth(String x, HashSet<Character> y) {
    int ret = x.length();
    Map<Character, Integer> index = new LinkedHashMap<Character, Integer>();

    for (int j = 0; j < x.length(); j++) {
        char ch = x.charAt(j);
        if (y.contains(ch)) {
            index.remove(ch);
            index.put(ch, j);
            if (index.size() == y.size()) {
                int i = index.values().iterator().next();
                if (ret > j - i + 1)
                    ret = j - i + 1;
            }
        }
    }
    return ret;
}
public int smallestWindow(String str1, String str2){
        if(str1==null || str2==null){
            throw new IllegalArgumentException();
        }
        Map<String, Node> map=new HashMap<String, Node>();
        Node head=null, current=null;

        for(int i=0;i<str1.length();i++){
            char c=str1.charAt(i);
            if(head==null){
                head=new Node(c);
                current=head;
                map.put(String.valueOf(c), head);
            }
            else{
                current.next=new Node(c);
                current.next.pre=current;
                current=current.next;
                map.put(String.valueOf(c), current);
            }
        }

        Node end=current;
        int min=Integer.MAX_VALUE;
        int count=0;

        for(int i=0;i<str2.length();i++){
            char c = str2.charAt(i);
            Node n=map.get(String.valueOf(c));
            if(n!=null){
                if(n.index==Integer.MAX_VALUE){
                    count++;
                }
                n.index=i;
                if(n==head){
                    Node temp=head;
                    head=head.next;
                    if(head==null){//one node
                        return 1;
                    }
                    head.pre=null;        
                    temp.pre=end;
                    end.next=temp;
                    temp.next=null;
                    end=temp;
                }
                else if(end!=n){
                    n.pre.next=n.next;
                    n.next.pre=n.pre;
                    n.pre=end;
                    n.next=null;
                    end.next=n;
                    end=n;
                }
                if(count==str1.length()){
                    min=Math.min(end.index-head.index+1, min);
                }
            }
        }
        System.out.println(map);
        return min;
    }
private static String minWindow(String s, String t) {
    int[] needToFind = new int[256];
    int[] hasFound = new int[256];

    for(int i = 0; i < t.length(); ++i) {
       needToFind[t.charAt(i)]++;
    }

    int count = 0;
    int minWindowSize = Integer.MAX_VALUE;
    int start = 0, end = -1;
    String window = "";

    while (++end < s.length()) {
        char c = s.charAt(end);
        if(++hasFound[c] <= needToFind[c]) {
           count++;
        }

        if(count < t.length()) continue;
        while (hasFound[s.charAt(start)] > needToFind[s.charAt(start)]) {
           hasFound[s.charAt(start++)]--;
        }

        if(end - start + 1 < minWindowSize) {
           minWindowSize = end - start + 1;
           window = s.substring(start, end + 1);
        }
    }
    return window;
}
public class StringSearchDemo {

public String getSmallestSubsetOfStringContaingSearchString(String toMatch,
        String inputString) {
    if (inputString.isEmpty() || toMatch.isEmpty()) {
        return null;
    }
    //      List<String> results = new ArrayList<String>(); // optional you can comment this out

    String smallestMatch = "";
    //      String largestMatch = ""; 
    int startPointer = 0, endPointer = 1;
    HashMap<Character, Integer> toMatchMap = new HashMap<Character, Integer>();

    for (char c : toMatch.toCharArray()) {
        if (toMatchMap.containsKey(c)) {
            toMatchMap.put(c, (toMatchMap.get(c) + 1));
        } else {
            toMatchMap.put(c, 1);
        }
    }

    int totalCount = getCountofMatchingString(toMatchMap, toMatch);
    for (int i = 0; i < inputString.length();) {
        if (!toMatchMap.containsKey(inputString.charAt(i))) {
            endPointer++;
            i++;
            continue;
        }
        String currentSubString = inputString.substring(startPointer,
                endPointer);
        if (getCountofMatchingString(toMatchMap, currentSubString) >= totalCount) {
            //              results.add(currentSubString); // optional you can comment this out
            if (smallestMatch.length() > currentSubString.length()) {
                smallestMatch = currentSubString;
            } else if (smallestMatch.isEmpty()) {
                smallestMatch = currentSubString;
            }
            //              if (largestMatch.length() < currentSubString.length()) {
            //                  largestMatch = currentSubString;
            //              }
            startPointer++;
        } else {
            endPointer++;
            i++;
        }

    }
    //      System.out.println("all possible combinations = " + results); // optional, you can comment this out
    //      System.out.println("smallest result = " + smallestMatch);
    //      System.out.println("largest result = " + largestMatch);
    return smallestMatch;
}

public int getCountofMatchingString(HashMap<Character, Integer> toMatchMap,
        String toMatch) {
    int match = 0;
    HashMap<Character, Integer> localMap = new HashMap<Character, Integer>();

    for (char c : toMatch.toCharArray()) {
        if (toMatchMap.containsKey(c)) {
            if (localMap.containsKey(c)) {
                if (localMap.get(c) < toMatchMap.get(c)) {
                    localMap.put(c, (localMap.get(c) + 1));
                    match++;
                }
            } else {
                localMap.put(c, 1);
                match++;
            }
        }
    }
    return match;
}

public static void main(String[] args) {
    String inputString = "zxaddbddxyy由ccbbwwaay漢字由来"; 
    String matchCriteria = "a由";
    System.out.println("input=" + matchCriteria);
    System.out.println("matchCriteria=" + inputString);
    String result = (new StringSearchDemo())
            .getSmallestSubsetOfStringContaingSearchString(matchCriteria, inputString);
    System.out.println("smallest possbile match = " + result);
}