📌  相关文章
📜  包含字符串本身所有字符的最小窗口

📅  最后修改于: 2021-10-28 01:46:25             🧑  作者: Mango

给定一个字符串,找出具有给定字符串所有不同字符的最小窗口长度。例如。 str = “aabcbcdbca”,那么结果将是 4,因为最小的窗口将是 “dbca”。
例子:

Input: aabcbcdbca
Output: dbca
Explanation: 
Possible substrings= {aabcbcd, abcbcd, 
bcdbca, dbca....}
Of the set of possible substrings 'dbca' 
is the shortest substring having all the 
distinct characters of given string. 

Input: aaab
Output: ab
Explanation: 
Possible substrings={aaab, aab, ab}
Of the set of possible substrings 'ab' 
is the shortest substring having all 
the distinct characters of given string.    

解决方案:上面的问题表明,即使最小的字符串包含重复元素,我们也必须找到包含给定字符串的所有不同字符的最小窗口。
例如,在“aabcbcdb”中,包含所有字符的最小字符串是“abcbcd”。
方法一这是使用HashMap解决问题的Brute Force方法。

  • 方法:为了解决这个问题,我们首先要找出字符串存在的所有不同的字符。这可以使用HashMap来完成。接下来是生成所有可能的子串。接下来是检查生成的子字符串是否具有所有必需的字符(存储在 hash_map 中)。如果是,则将其长度与遵循上述约束的最小子串长度进行比较,直到现在。
    HashMap 自Java 1.2 起,HashMap 是 Java 集合的一部分。它提供了Java Map 接口的基本实现。它将数据存储在(键,值)对中。要访问一个值,必须知道它的键。 HashMap 之所以称为 HashMap,是因为它使用了一种称为 Hashing 的技术。散列是一种将大字符串转换为表示相同字符串的小字符串的技术。较短的值有助于索引和更快的搜索。 HashSet 也在内部使用 HashMap。它在内部使用一个链接列表来存储键值对,这些键值对已经在 HashSet 和进一步的文章中详细解释过。
  • 算法 :
    1. 将给定字符串的所有不同字符存储在 hash_map 中。
    2. 取一个变量 count 并将其初始化为值 0。
    3. 使用两个指针生成子串。
    4. 现在检查生成的子字符串是否有效-:
      1. 一旦我们发现之前没有遇到过生成的子串的字符,将 count 增加1
      2. 我们可以使用一个大小为max_chars的访问过的数组来查找当前字符之前是否遇到过。
      3. 如果 count 等于 hash_map 的大小,则生成的子串有效
      4. 如果它是有效的子字符串,则将其与已生成的最小长度子字符串进行比较。
  • 伪代码:
maphash_map;
for ( i=0 to str.length())
hash_map[str[i]]++;//finding all distinct characters of string
minimum_size=INT_MAX
Distinct_chars=hash_map.size()
for(i=0 to str.length())
count=0;
sub_str="";
visited[256]={0};
 for(j=i to n)
   sub_str+=str[j]
   if(visited[str[j]]==0)
   count++
   visited[str[j]]=1;
   if(count==Distinct_chars)
   end loop

if(sub_str.length()
  • 执行:
CPP
// C++ program to find the smallest
// window containing all characters
// of a pattern.
#include 
using namespace std;
 
const int MAX_CHARS = 256;
 
// Function to find smallest window containing
// all distinct characters
string findSubString(string str)
{
    int n = str.length();
 
    // Count all distinct characters.
    int dist_count = 0;
    unordered_map hash_map;
    for (int i = 0; i < n; i++) {
        hash_map[str[i]]++;
    }
 
    dist_count = hash_map.size();
    int size = INT_MAX;
    string res;
    // Now follow the algorithm discussed in below
    for (int i = 0; i < n; i++) {
        int count = 0;
        int visited[256] = { 0 };
        string sub_str = "";
        for (int j = i; j < n; j++) {
            if (visited[str[j]] == 0) {
                count++;
                visited[str[j]] = 1;
            }
            sub_str += str[j];
            if (count == dist_count)
                break;
        }
        if (sub_str.length() < size && count == dist_count)
        {
            res = sub_str;
            size=res.length();
        }
    }
    return res;
}
 
// Driver Code
int main()
{
    string str = "aabcbcdbca";
    cout << "Smallest window containing all distinct"
            " characters is: "
         << findSubString(str);
    return 0;
}


Java
import java.io.*;
import java.util.*;
 
// Java program to find the smallest
// window containing all characters
// of a pattern.
class GFG
{
   
    // Function to find smallest window containing
    // all distinct characters
    public static String findSubString(String str)
    {
        int n = str.length();
       
        // Count all distinct characters.
        int dist_count = 0;
        HashMap mp = new HashMap<>();
        for (int i = 0; i < n; i++)
        {
            if (mp.containsKey(str.charAt(i)))
            {
                Integer a = mp.get(str.charAt(i));
                mp.put(str.charAt(i),a+1);                  
            }
          else
          {
                 mp.put(str.charAt(i), 1);
            }
        }
        dist_count = mp.size();
        int size = Integer.MAX_VALUE;
        String res = "";
       
        // Now follow the algorithm discussed in below
        for (int i = 0; i < n; i++)
        {
            int count = 0;
            int visited[] = new int[256];
            for(int j = 0; j < 256; j++)
              visited[j] = 0;
            String sub_str = "";
            for (int j = i; j < n; j++)
            {
                if (visited[str.charAt(j)] == 0)
                {
                    count++;
                    visited[str.charAt(j)] = 1;
                }
                sub_str += str.charAt(j);
                if (count == dist_count)
                    break;
            }
            if (sub_str.length() < size && count == dist_count)
            {
                res = sub_str;
                size=res.length();
            }
        }
        return res;
    }
   
  // Driver code
    public static void main (String[] args)
    {
        String str = "aabcbcdbca";
        System.out.println("Smallest window containing all distinct"+
                " characters is: "+ findSubString(str)) ;
    }
}
 
// This code is contributed by Manu Pathria


C++
// C++ program to find the smallest
// window containing all characters
// of a pattern.
#include 
using namespace std;
 
const int MAX_CHARS = 256;
 
// Function to find smallest window containing
// all distinct characters
string findSubString(string str)
{
    int n = str.length();
 
    // if string is empty or having one char
    if (n <= 1)
        return str;
 
    // Count all distinct characters.
    int dist_count = 0;
    bool visited[MAX_CHARS] = { false };
    for (int i = 0; i < n; i++) {
        if (visited[str[i]] == false) {
            visited[str[i]] = true;
            dist_count++;
        }
    }
 
    // Now follow the algorithm discussed in below
    // post. We basically maintain a window of characters
    // that contains all characters of given string.
    int start = 0, start_index = -1, min_len = INT_MAX;
 
    int count = 0;
    int curr_count[MAX_CHARS] = { 0 };
    for (int j = 0; j < n; j++) {
        // Count occurrence of characters of string
        curr_count[str[j]]++;
 
        // If any distinct character matched,
        // then increment count
        if (curr_count[str[j]] == 1)
            count++;
 
        // if all the characters are matched
        if (count == dist_count) {
            // Try to minimize the window i.e., check if
            // any character is occurring more no. of times
            // than its occurrence in pattern, if yes
            // then remove it from starting and also remove
            // the useless characters.
            while (curr_count[str[start]] > 1) {
                if (curr_count[str[start]] > 1)
                    curr_count[str[start]]--;
                start++;
            }
 
            // Update window size
            int len_window = j - start + 1;
            if (min_len > len_window) {
                min_len = len_window;
                start_index = start;
            }
        }
    }
 
    // Return substring starting from start_index
    // and length min_len
    return str.substr(start_index, min_len);
}
 
// Driver code
int main()
{
    string str = "aabcbcdbca";
    cout << "Smallest window containing all distinct"
            " characters is: "
         << findSubString(str);
    return 0;
}


Java
// Java program to find the smallest window containing
// all characters of a pattern.
import java.util.Arrays;
public class GFG {
 
    static final int MAX_CHARS = 256;
 
    // Function to find smallest window containing
    // all distinct characters
    static String findSubString(String str)
    {
        int n = str.length();
 
        // if string is empty or having one char
        if (n <= 1)
            return str;
 
        // Count all distinct characters.
        int dist_count = 0;
 
        boolean[] visited = new boolean[MAX_CHARS];
        Arrays.fill(visited, false);
        for (int i = 0; i < n; i++) {
            if (visited[str.charAt(i)] == false) {
                visited[str.charAt(i)] = true;
                dist_count++;
            }
        }
 
        // Now follow the algorithm discussed in below
        // post. We basically maintain a window of
        // characters that contains all characters of given
        // string.
        int start = 0, start_index = -1;
        int min_len = Integer.MAX_VALUE;
 
        int count = 0;
        int[] curr_count = new int[MAX_CHARS];
        for (int j = 0; j < n; j++) {
            // Count occurrence of characters of string
            curr_count[str.charAt(j)]++;
 
            // If any distinct character matched,
            // then increment count
            if (curr_count[str.charAt(j)] == 1)
                count++;
 
            // if all the characters are matched
            if (count == dist_count) {
                // Try to minimize the window i.e., check if
                // any character is occurring more no. of
                // times than its occurrence in pattern, if
                // yes then remove it from starting and also
                // remove the useless characters.
                while (curr_count[str.charAt(start)] > 1) {
                    if (curr_count[str.charAt(start)] > 1)
                        curr_count[str.charAt(start)]--;
                    start++;
                }
 
                // Update window size
                int len_window = j - start + 1;
                if (min_len > len_window) {
                    min_len = len_window;
                    start_index = start;
                }
            }
        }
        // Return substring starting from start_index
        // and length min_len
        return str.substring(start_index,
                             start_index + min_len);
    }
 
    // Driver code
    public static void main(String args[])
    {
        String str = "aabcbcdbca";
        System.out.println(
            "Smallest window containing all distinct"
            + " characters is: " + findSubString(str));
    }
}
// This code is contributed by Sumit Ghosh


Python
# Python program to find the smallest
# window containing
# all characters of a pattern
from collections import defaultdict
 
MAX_CHARS = 256
 
# Function to find smallest window
# containing all distinct characters
 
 
def findSubString(strr):
 
    n = len(strr)
 
    # if string is empty or having one char
    if n <= 1:
        return strr
 
    # Count all distinct characters.
    dist_count = len(set([x for x in strr]))
 
    curr_count = defaultdict(lambda: 0)
    count = 0
    start = 0
    min_len = n
 
    # Now follow the algorithm discussed in below
    # post. We basically maintain a window of characters
    # that contains all characters of given string.
    for j in range(n):
        curr_count[strr[j]] += 1
 
        # If any distinct character matched,
        # then increment count
        if curr_count[strr[j]] == 1:
            count += 1
 
        # Try to minimize the window i.e., check if
        # any character is occurring more no. of times
        # than its occurrence in pattern, if yes
        # then remove it from starting and also remove
        # the useless characters.
        if count == dist_count:
            while curr_count[strr[start]] > 1:
                if curr_count[strr[start]] > 1:
                    curr_count[strr[start]] -= 1
 
                start += 1
 
            # Update window size
            len_window = j - start + 1
 
            if min_len > len_window:
                min_len = len_window
                start_index = start
 
    # Return substring starting from start_index
    # and length min_len """
    return str(strr[start_index: start_index +
                    min_len])
 
 
# Driver code
if __name__ == '__main__':
 
    print("Smallest window containing "
          "all distinct characters is: {}".format(
              findSubString("aabcbcdbca")))
 
# This code is contributed by
# Subhrajit


C#
// C# program to find the smallest window containing
// all characters of a pattern.
using System;
 
class GFG {
 
    static int MAX_CHARS = 256;
 
    // Function to find smallest window containing
    // all distinct characters
    static string findSubString(string str)
    {
        int n = str.Length;
 
        // if string is empty or having one char
        if (n <= 1)
            return str;
 
        // Count all distinct characters.
        int dist_count = 0;
        bool[] visited = new bool[MAX_CHARS];
        for (int i = 0; i < n; i++) {
            if (visited[str[i]] == false) {
                visited[str[i]] = true;
                dist_count++;
            }
        }
 
        // Now follow the algorithm discussed in below
        // post. We basically maintain a window of
        // characters that contains all characters of given
        // string.
        int start = 0, start_index = -1,
            min_len = int.MaxValue;
 
        int count = 0;
        int[] curr_count = new int[MAX_CHARS];
        for (int j = 0; j < n; j++) {
            // Count occurrence of characters of string
            curr_count[str[j]]++;
 
            // If any distinct character matched,
            // then increment count
            if (curr_count[str[j]] == 1)
                count++;
 
            // if all the characters are matched
            if (count == dist_count) {
                // Try to minimize the window i.e., check if
                // any character is occurring more no. of
                // times than its occurrence in pattern, if
                // yes then remove it from starting and also
                // remove the useless characters.
                while (curr_count[str[start]] > 1) {
                    if (curr_count[str[start]] > 1)
                        curr_count[str[start]]--;
                    start++;
                }
 
                // Update window size
                int len_window = j - start + 1;
                if (min_len > len_window) {
                    min_len = len_window;
                    start_index = start;
                }
            }
        }
 
        // Return substring starting from start_index
        // and length min_len
        return str.Substring(start_index, min_len);
    }
 
    // Driver code
    public static void Main(String[] args)
    {
        string str = "aabcbcdbca";
        Console.WriteLine(
            "Smallest window containing all distinct"
            + " characters is: " + findSubString(str));
    }
}
 
// This code contributed by Rajput-Ji


输出
Smallest window containing all distinct characters is: dbca
  • 复杂度分析:
    • 时间复杂度: O(N^2)。
      这个时间需要生成长度为“N”的字符串的所有可能的子字符串。
    • 空间复杂度: O(N)。
      由于已使用大小为 N 的hash_map

方法二这里我们使用了滑动窗口技术来解决。该技术展示了如何将少数问题中的嵌套 for 循环转换为单个 for 循环,从而降低时间复杂度。

  • 方法:基本上一个字符窗口是通过使用两个指针来维护的,即startend 。这些开始结束指针可分别用于缩小和增加窗口的大小。每当窗口包含给定字符串 的所有字符时,窗口从左侧缩小以删除多余的字符,然后将其长度与迄今为止找到的最小窗口进行比较。
    如果在当前窗口中,不能删除更多字符,那么我们开始使用结尾增加窗口的大小,直到字符串中存在的所有不同字符也在窗口中。最后,找到每个窗口的最小尺寸。

  • 算法 :
    1. 维护一个包含最大可能字符(256 个字符)的数组(已访问) ,一旦我们在字符串找到任何字符,就在数组中标记该索引(这是为了计算字符串所有不同的字符)。
    2. 取两个指针开始结束,这将标记窗口的开始和结束。
    3. 取一个counter=0将用于计算窗口中不同的字符。
    4. 现在开始阅读给定的字符串的字符,如果我们遇到尚未访问尚未1,计数器增加一个字符。
    5. 如果计数器等于不同字符总数,则尝试缩小窗口。
    6. 为了缩小窗口 -:
      1. 如果起始指针处的字符频率大于 1,则增加指针,因为它是多余的。
      2. 现在将当前窗口的长度与最小窗口长度进行比较。
  • 执行:

C++

// C++ program to find the smallest
// window containing all characters
// of a pattern.
#include 
using namespace std;
 
const int MAX_CHARS = 256;
 
// Function to find smallest window containing
// all distinct characters
string findSubString(string str)
{
    int n = str.length();
 
    // if string is empty or having one char
    if (n <= 1)
        return str;
 
    // Count all distinct characters.
    int dist_count = 0;
    bool visited[MAX_CHARS] = { false };
    for (int i = 0; i < n; i++) {
        if (visited[str[i]] == false) {
            visited[str[i]] = true;
            dist_count++;
        }
    }
 
    // Now follow the algorithm discussed in below
    // post. We basically maintain a window of characters
    // that contains all characters of given string.
    int start = 0, start_index = -1, min_len = INT_MAX;
 
    int count = 0;
    int curr_count[MAX_CHARS] = { 0 };
    for (int j = 0; j < n; j++) {
        // Count occurrence of characters of string
        curr_count[str[j]]++;
 
        // If any distinct character matched,
        // then increment count
        if (curr_count[str[j]] == 1)
            count++;
 
        // if all the characters are matched
        if (count == dist_count) {
            // Try to minimize the window i.e., check if
            // any character is occurring more no. of times
            // than its occurrence in pattern, if yes
            // then remove it from starting and also remove
            // the useless characters.
            while (curr_count[str[start]] > 1) {
                if (curr_count[str[start]] > 1)
                    curr_count[str[start]]--;
                start++;
            }
 
            // Update window size
            int len_window = j - start + 1;
            if (min_len > len_window) {
                min_len = len_window;
                start_index = start;
            }
        }
    }
 
    // Return substring starting from start_index
    // and length min_len
    return str.substr(start_index, min_len);
}
 
// Driver code
int main()
{
    string str = "aabcbcdbca";
    cout << "Smallest window containing all distinct"
            " characters is: "
         << findSubString(str);
    return 0;
}

Java

// Java program to find the smallest window containing
// all characters of a pattern.
import java.util.Arrays;
public class GFG {
 
    static final int MAX_CHARS = 256;
 
    // Function to find smallest window containing
    // all distinct characters
    static String findSubString(String str)
    {
        int n = str.length();
 
        // if string is empty or having one char
        if (n <= 1)
            return str;
 
        // Count all distinct characters.
        int dist_count = 0;
 
        boolean[] visited = new boolean[MAX_CHARS];
        Arrays.fill(visited, false);
        for (int i = 0; i < n; i++) {
            if (visited[str.charAt(i)] == false) {
                visited[str.charAt(i)] = true;
                dist_count++;
            }
        }
 
        // Now follow the algorithm discussed in below
        // post. We basically maintain a window of
        // characters that contains all characters of given
        // string.
        int start = 0, start_index = -1;
        int min_len = Integer.MAX_VALUE;
 
        int count = 0;
        int[] curr_count = new int[MAX_CHARS];
        for (int j = 0; j < n; j++) {
            // Count occurrence of characters of string
            curr_count[str.charAt(j)]++;
 
            // If any distinct character matched,
            // then increment count
            if (curr_count[str.charAt(j)] == 1)
                count++;
 
            // if all the characters are matched
            if (count == dist_count) {
                // Try to minimize the window i.e., check if
                // any character is occurring more no. of
                // times than its occurrence in pattern, if
                // yes then remove it from starting and also
                // remove the useless characters.
                while (curr_count[str.charAt(start)] > 1) {
                    if (curr_count[str.charAt(start)] > 1)
                        curr_count[str.charAt(start)]--;
                    start++;
                }
 
                // Update window size
                int len_window = j - start + 1;
                if (min_len > len_window) {
                    min_len = len_window;
                    start_index = start;
                }
            }
        }
        // Return substring starting from start_index
        // and length min_len
        return str.substring(start_index,
                             start_index + min_len);
    }
 
    // Driver code
    public static void main(String args[])
    {
        String str = "aabcbcdbca";
        System.out.println(
            "Smallest window containing all distinct"
            + " characters is: " + findSubString(str));
    }
}
// This code is contributed by Sumit Ghosh

Python

# Python program to find the smallest
# window containing
# all characters of a pattern
from collections import defaultdict
 
MAX_CHARS = 256
 
# Function to find smallest window
# containing all distinct characters
 
 
def findSubString(strr):
 
    n = len(strr)
 
    # if string is empty or having one char
    if n <= 1:
        return strr
 
    # Count all distinct characters.
    dist_count = len(set([x for x in strr]))
 
    curr_count = defaultdict(lambda: 0)
    count = 0
    start = 0
    min_len = n
 
    # Now follow the algorithm discussed in below
    # post. We basically maintain a window of characters
    # that contains all characters of given string.
    for j in range(n):
        curr_count[strr[j]] += 1
 
        # If any distinct character matched,
        # then increment count
        if curr_count[strr[j]] == 1:
            count += 1
 
        # Try to minimize the window i.e., check if
        # any character is occurring more no. of times
        # than its occurrence in pattern, if yes
        # then remove it from starting and also remove
        # the useless characters.
        if count == dist_count:
            while curr_count[strr[start]] > 1:
                if curr_count[strr[start]] > 1:
                    curr_count[strr[start]] -= 1
 
                start += 1
 
            # Update window size
            len_window = j - start + 1
 
            if min_len > len_window:
                min_len = len_window
                start_index = start
 
    # Return substring starting from start_index
    # and length min_len """
    return str(strr[start_index: start_index +
                    min_len])
 
 
# Driver code
if __name__ == '__main__':
 
    print("Smallest window containing "
          "all distinct characters is: {}".format(
              findSubString("aabcbcdbca")))
 
# This code is contributed by
# Subhrajit

C#

// C# program to find the smallest window containing
// all characters of a pattern.
using System;
 
class GFG {
 
    static int MAX_CHARS = 256;
 
    // Function to find smallest window containing
    // all distinct characters
    static string findSubString(string str)
    {
        int n = str.Length;
 
        // if string is empty or having one char
        if (n <= 1)
            return str;
 
        // Count all distinct characters.
        int dist_count = 0;
        bool[] visited = new bool[MAX_CHARS];
        for (int i = 0; i < n; i++) {
            if (visited[str[i]] == false) {
                visited[str[i]] = true;
                dist_count++;
            }
        }
 
        // Now follow the algorithm discussed in below
        // post. We basically maintain a window of
        // characters that contains all characters of given
        // string.
        int start = 0, start_index = -1,
            min_len = int.MaxValue;
 
        int count = 0;
        int[] curr_count = new int[MAX_CHARS];
        for (int j = 0; j < n; j++) {
            // Count occurrence of characters of string
            curr_count[str[j]]++;
 
            // If any distinct character matched,
            // then increment count
            if (curr_count[str[j]] == 1)
                count++;
 
            // if all the characters are matched
            if (count == dist_count) {
                // Try to minimize the window i.e., check if
                // any character is occurring more no. of
                // times than its occurrence in pattern, if
                // yes then remove it from starting and also
                // remove the useless characters.
                while (curr_count[str[start]] > 1) {
                    if (curr_count[str[start]] > 1)
                        curr_count[str[start]]--;
                    start++;
                }
 
                // Update window size
                int len_window = j - start + 1;
                if (min_len > len_window) {
                    min_len = len_window;
                    start_index = start;
                }
            }
        }
 
        // Return substring starting from start_index
        // and length min_len
        return str.Substring(start_index, min_len);
    }
 
    // Driver code
    public static void Main(String[] args)
    {
        string str = "aabcbcdbca";
        Console.WriteLine(
            "Smallest window containing all distinct"
            + " characters is: " + findSubString(str));
    }
}
 
// This code contributed by Rajput-Ji
输出
Smallest window containing all distinct characters is: dbca
  • 复杂度分析:
    • 时间复杂度: O(N)。
      由于字符串仅使用两个指针遍历一次。
    • 空间复杂度: O(N)。
      使用大小为 N 的hash_map

相关文章:

  1. 由最大不同字符组成的最小子字符串的长度
  2. https://www.geeksforgeeks.org/find-the-smallest-window-in-a-string- contains-all-characters-of-another-string/

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程