【问题标题】:Find Length of smallest substring which contains another string as subsequence查找包含另一个字符串作为子序列的最小子字符串的长度
【发布时间】:2020-08-19 21:26:08
【问题描述】:

假设我有一个字符串 s1 = "eabegcghdefgh" 和另一个字符串 s2 = "egh"

代码应该返回答案4,因为s1 的子字符串"efgh"(因为它是包含s2 作为子序列的最小子字符串)。

注意:可能有几个子字符串,但"efgh" 是最小的子字符串。

换句话说,找到包含另一个字符串s2的所有字符的s1的最小子字符串的长度,但要按顺序。

请注意:我想问一下如何在 O(n) 时间复杂度中做到这一点。

【问题讨论】:

  • 不错的问题。到目前为止你尝试了什么? O(n) 可能需要一些复杂的簿记。我会调查类似的事情:丢弃所有不(或不能)发挥作用的字符,然后搜索所有出现的字符串。如果你记住字符的原始位置,你就知道长度。不过这很棘手。

标签: string algorithm data-structures time-complexity


【解决方案1】:
public static String smallestWindow(String S, String T) {
    if (S.equals(T))  //If S and T are equal, then simply return S.
        return S;
    /**
     * Use sliding window. 

如果存在 S 的子串 W 使得 T 是 W 的子序列, 那么 S 的一个比 W 长或与 W 相同的子串也必须存在。 因此,从 S 中的索引 0 和 T 中的索引 0 开始找到 S 的这样一个子串。 如果到达 T 的最后一个字符,则 S 中的当前索引是子串的结束索引,并找到 S 中子串的最大可能开始索引。 找到起始索引和结束索引后,可以更新最小窗口大小,同时存储起始索引和结束索引。

然后将 T 中的索引设置为 0 并尝试在 S 中查找另一个子字符串。 重复该过程,直到到达 S 的末尾。 访问完S中的所有字符后,可以得到最小的子串长度,并返回最短的子串。

     */
    int sLength = S.length(), tLength = T.length();
    int start = 0, end = sLength - 1;
    int sIndex = 0, tIndex = 0;
    while (sIndex < sLength) {
        if (S.charAt(sIndex) == T.charAt(tIndex))
            tIndex++;
        if (tIndex == tLength) {
            int rightIndex = sIndex;
            tIndex--;
            while (tIndex >= 0) {
                if (S.charAt(sIndex) == T.charAt(tIndex))
                    tIndex--;
                sIndex--;
            }
            sIndex++;
            if (rightIndex - sIndex < end - start) {
                start = sIndex;
                end = rightIndex;
            }
            tIndex = 0;
        }
        sIndex++;
    }
    int windowSize = end - start + 1;
        return S.substring(start, start + windowSize);
}

【讨论】:

  • 这对我来说似乎是一个好方法,但它不是 O(n)。要了解原因,假设 Sp a 的字符串,Tq a 的字符串。那么这种方法需要 O((p−q)×q) 时间,因为有 O(p−q) 次调用回溯循环,每个调用都需要 O(q) 时间。因此,如果 p = 2q,则 n = 3q,这种方法需要 O(n²/9) = O(n²) 时间。
【解决方案2】:

这是一个基本的滑动窗口问题,通常被称为“包含另一个字符串的所有字符的字符串中的最小窗口”。我们通过从要搜索的字符串的第一个索引开始有两个指针“low”和“high”来解决这个问题,我们递增高指针直到模式的所有字符都匹配,然后我们尝试缩小子字符串递增低指针。

这是解决问题的 java sn-p。

 public static String smallestWindow(String s, String pat){
    if(s == null || s.length() == 0)return "-1";
    int map[] = new int[128];
for(char k : pat.toCharArray())
map[k]++;
int count =0,start=-1,end=-1,lo=0,hi=0,min= Integer.MAX_VALUE;

for(hi = 0;hi<s.length();hi++)
{
    if(map[s.charAt(hi)] >0)
     count++;

     map[s.charAt(hi)]--;

     if(count == pat.length())
     {
         while(lo<hi && map[s.charAt(lo)] <0)
         { map[s.charAt(lo)]++;
             lo++;
         }
         if(min > hi - lo +1)
         {
             min = hi - lo+1;
             start = lo;
             end = hi+1;
         }
         map[s.charAt(lo)]++;

         lo++;
         count--; 
     }
}
return start == -1? "-1" : s.substring(start,end);
}

我建议您观看此视频以更好地理解它。 Smallest window in a string containing all the characters of another string

【讨论】:

  • 问题不一样,一个字符串包含另一个字符串的所有字符并不意味着另一个字符串是第一个字符串的子序列。
猜你喜欢
  • 2015-03-09
  • 2013-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-04
  • 1970-01-01
  • 2013-07-28
  • 1970-01-01
相关资源
最近更新 更多