String 字符串作为另一个字符串的子字符串的排列

String 字符串作为另一个字符串的子字符串的排列,string,algorithm,substring,permutation,String,Algorithm,Substring,Permutation,给定一个字符串a和另一个字符串B。找出B的任何置换是否作为a的子字符串存在 My solution-> if length(A)=n and length(B)=m I did this in 0((n-m+1)*m) by sorting B and then checking A with window size of m each time. 比如说, 如果A=“百科全书” 如果B=“dep”,则返回true,因为ped是dep的置换,ped是a的子串 My solution

给定一个字符串a和另一个字符串B。找出B的任何置换是否作为a的子字符串存在

My solution->

if length(A)=n and length(B)=m

I did this in 0((n-m+1)*m) by sorting B and then checking A 
with window size of m each time.
比如说,

如果A=“百科全书”

如果B=“dep”,则返回true,因为ped是dep的置换,ped是a的子串

My solution->

if length(A)=n and length(B)=m

I did this in 0((n-m+1)*m) by sorting B and then checking A 
with window size of m each time.

我需要找到一个更好更快的解决方案。

在j|u random|u hacker在评论中提出的算法的基础上,可以在
O(|a |+|B |)中找到匹配项,如下所示:(注意:在整个过程中,我们使用
|a |
来表示
a的长度)

  • 创建一个整数数组
    count
    ,其域为字母表大小,初始化为all
    0
    s
  • 将距离设置为
    0
  • 对于
    B
    中的每个字符
    Bi
    • 减量
      计数[Bi]
    • 如果
      count[Bi]
      的上一次计数为
      0
      ,也应增加
      距离
  • 对于
    A
    中的每个字符
    Ai
    • 增量
      计数[Ai]
    • 如果
      i
      大于
      |B |
      减量
      计数[Ai-|B |]
    • 对于修改的两个<代码>计数
  • 值中的每一个,如果上一个值是<代码>0
    ,则增加<代码>距离,如果新值是<代码>0,则减少<代码>距离
  • 如果结果是
    distance
    0
    ,则已找到匹配项

  • 注意:j|u random_hacker提出的算法也是
    O(|A |+|B])
    ,因为将
    freqA
    freqB
    进行比较的成本是
    O(|字母表|)
    ,这是一个常数。然而,上述算法将比较成本降低到一个小常数。此外,通过使用未初始化数组的标准技巧,即使字母表的大小不是恒定的,理论上也可以实现这一点。

    这个问题有一个更简单的解决方案,可以在线性时间内完成

    这里:n=A.size(),m=B.size()

    想法是使用散列

    首先,我们散列字符串B的字符

    假设:B=dep

    • 散列B['d']=1
    • 散列B['e']=1
    • 散列B['p']=1
    现在,我们为大小为“m”的每个窗口在字符串“a”上运行一个循环

    假设:A=“百科全书”

    大小为'm'的第一个窗口将包含字符{e,n,c}。我们现在就把它们切碎

    • 赢['e']=1
    • 赢['n']=1
    • 赢['c']=1
    现在我们检查两个数组(hash_B[]win[])中每个字符的频率是否相同。注意:hash_B[]或win[]的最大大小为26

    如果它们不一样,我们就换窗户

    移动窗口后,我们赢['e']的计数减少1赢['y']的计数增加1

    • 赢['n']=1
    • 赢['c']=1
    • 赢['y']=1
    在第七个班次期间,您的阵列的状态为:

    • 赢['p']=1
    • 赢['e']=1
    • 赢['d']=1

    这与哈希_B数组相同。所以,打印“SUCCESS”
    并退出。

    如果我只需要担心ASCII字符,它可以在
    O(n)
    时间和
    O(1)
    空间内完成。我的代码也会打印出排列,但是可以很容易地修改,只需在第一个实例中返回true即可。代码的主要部分位于
    printAllPermutations()
    方法中。以下是我的解决方案:

    一些背景 这是我提出的一个解决方案,它有点类似于拉宾卡普算法背后的想法。在我理解算法之前,我将对其背后的数学进行如下解释:

    1 -> 1st prime
    2 -> 2nd prime
    3 -> 3rd prime
    ...
    n -> nth prime
    
    S={A_1,…,A_n}是只包含素数的大小n的列表。让S中的数字之和等于某个整数Q。然后,S是唯一可能的大小为N的完全素数多集,其元素可以和Q

    正因为如此,我们知道我们可以将每个字符映射到一个素数。我提议的地图如下:

    1 -> 1st prime
    2 -> 2nd prime
    3 -> 3rd prime
    ...
    n -> nth prime
    
    如果我们这样做(我们可以这样做,因为ASCII只有256个可能的字符),那么我们就很容易在较大的字符串B中找到每个排列

    算法: 我们将做以下工作:

    1:计算A中每个字符映射到的素数之和,我们称之为smallHash

    2:创建2个索引(righti和lefti)。righti初始化为零,lefti初始化为A的大小

    ex:     |  |
            v  v
           "abcdabcd"
            ^  ^
            |  |
    
    3:创建一个变量currHash,并将其初始化为B中每个字符对应的质数之和,介于(包括)righti和lefti-1之间

    4:按1迭代righti和lefti,每次更新currHash时,从不再在范围内的字符(lefti-1)中减去映射的素数,并添加与刚刚添加到范围内的字符(righti)对应的素数

    5:每次currHash等于smallHash时,范围中的字符必须是排列。所以我们把它们打印出来

    6:继续,直到到达B的末端。(当righti等于B的长度时)

    此解决方案在
    O(n)
    时间复杂度和
    O(1)
    空间中运行

    实际代码:
    公共
    
    #include <string>
    
    bool is_permuted_substring(std::string_view input_string,
                               std::string_view search_string) {
      if (search_string.empty()) {
        return true;
      }
    
      if (search_string.length() > input_string.length()) {
        return false;
      }
    
      int character_frequencies[256]{};
      auto distance = search_string.length();
      for (auto c : search_string) {
        character_frequencies[(uint8_t)c]++;
      }
    
      for (auto i = 0u; i < input_string.length(); ++i) {
        auto& cur_frequency = character_frequencies[(uint8_t)input_string[i]];
        if (cur_frequency > 0) distance--;
        cur_frequency--;
    
        if (i >= search_string.length()) {
          auto& prev_frequency = ++character_frequencies[(
              uint8_t)input_string[i - search_string.length()]];
          if (prev_frequency > 0) {
            distance++;
          }
        }
    
        if (!distance) return true;
      }
    
      return false;
    }
    
    int main() {
      auto test = [](std::string_view input, std::string_view search,
                     auto expected) {
        auto result = is_permuted_substring(input, search);
        printf("%s: is_permuted_substring(\"%.*s\", \"%.*s\") => %s\n",
               result == expected ? "PASS" : "FAIL", (int)input.length(),
               input.data(), (int)search.length(), search.data(),
               result ? "T" : "F");
      };
    
      test("", "", true);
      test("", "a", false);
      test("a", "a", true);
      test("ab", "ab", true);
      test("ab", "ba", true);
      test("aba", "aa", false);
      test("baa", "aa", true);
      test("aacbba", "aab", false);
      test("encyclopedia", "dep", true);
      test("encyclopedia", "dop", false);
    
      constexpr char negative_input[]{-1, -2, -3, 0};
      constexpr char negative_search[]{-3, -2, 0};
      test(negative_input, negative_search, true);
    
      return 0;
    }
    
    class Test {
      public static boolean isPermuted(int [] asciiA, String subB){
        int [] asciiB = new int[26];
    
        for(int i=0; i < subB.length();i++){
          asciiB[subB.charAt(i) - 'a']++;
        }
        for(int i=0; i < 26;i++){
            if(asciiA[i] != asciiB[i])
            return false;
        }
        return true;
      }
      public static void main(String args[]){
        String a = "abbc";
        String b = "cbabadcbbabbc";
        int len = a.length();
        int [] asciiA = new int[26];
        for(int i=0;i<a.length();i++){
          asciiA[a.charAt(i) - 'a']++;
        }
        int lastSeenIndex=0;
        for(int i=0;i<b.length()-len+1;i++){
          String sub = b.substring(i,i+len);
          System.out.printf("%s,%s\n",sub,isPermuted(asciiA,sub));
    } }
    }
    
    public int PermutationOfPatternInString(string text, string pattern)
    {
        int matchCount = 0;
        Dictionary<char, int> charCount = new Dictionary<char, int>();
        int patLen = pattern.Length;
        foreach (char c in pattern)
        {
            if (charCount.ContainsKey(c))
            {
                charCount[c]++;
            }
            else
            {
                charCount.Add(c, 1);
            }
        }
    
        var subStringCharCount = new Dictionary<char, int>();
    
        // loop through each character in the given text (string)....
        for (int i = 0; i <= text.Length - patLen; i++)
        {
            // check if current char and current + length of pattern-th char are in the pattern.
            if (charCount.ContainsKey(text[i]) && charCount.ContainsKey(text[i + patLen - 1]))
            {
                string subString = text.Substring(i, patLen);
                int j = 0;
                for (; j < patLen; j++)
                {
                    // there is no point going on if this subString doesnt contain chars that are in pattern...
                    if (charCount.ContainsKey(subString[j]))
                    {
                        if (subStringCharCount.ContainsKey(subString[j]))
                        {
                            subStringCharCount[subString[j]]++;
                        }
                        else
                        {
                            subStringCharCount.Add(subString[j], 1);
                        }
                    }
                    else
                    {
                        // if any of the chars dont appear in the subString that we are looking for
                        // break this loop and continue...
                        break;
                    }
                }
    
                int x = 0;
    
                // this will be true only when we have current subString's permutation count
                // matched with pattern's.
                // we need this because the char count could be different 
                if (subStringCharCount.Count == charCount.Count)
                {
                    for (; x < patLen; x++)
                    {
                        if (subStringCharCount[subString[x]] != charCount[subString[x]])
                        {
                            // if any count dont match then we break from this loop and continue...
                            break;
                        }
                    }
                }
    
                if (x == patLen)
                {
                    // this means we have found a permutation of pattern in the text...
                    // increment the counter.
                    matchCount++;
                }
    
                subStringCharCount.Clear(); // clear the count map.
            }
        }
    
        return matchCount;
    }
    
    [TestCase("encyclopedia", "dep", 1)]
    [TestCase("cbabadcbbabbcbabaabccbabc", "abbc", 7)]
    [TestCase("xyabxxbcbaxeabbxebbca", "abbc", 2)]
    public void PermutationOfStringInText(string text, string pattern, int expectedAnswer)
    {
        int answer = runner.PermutationOfPatternInString(text, pattern);
        Assert.AreEqual(expectedAnswer, answer);
    }
    
    public static void main(String[] args) {
        String pattern = "dep";
        String text = "encyclopedia";
        System.out.println(isPermutationAvailable(pattern, text));
    }
    
    public static boolean isPermutationAvailable(String pattern, String text) {
        if (pattern.length() > text.length()) {
            return false;
        }
        int[] patternMap = new int[26];
        int[] textMap = new int[26];
        for (int i = 0; i < pattern.length(); i++) {
            patternMap[pattern.charAt(i) - 'a']++;
            textMap[text.charAt(i) - 'a']++;
        }
        int count = 0;
        for (int i = 0; i < 26; i++) {
            if (patternMap[i] == textMap[i]) {
                count++;
            }
        }
        for (int i = 0; i < text.length() - pattern.length(); i++) {
            int r = text.charAt(i + pattern.length()) - 'a';
            int l = text.charAt(i) - 'a';
            if (count == 26) {
                return true;
            }
    
            textMap[r]++;
            if (textMap[r] == patternMap[r]) {
                count++;
            }
            else if (textMap[r] == patternMap[r] + 1) {
                count--;
            }
    
            textMap[l]--;
            if (textMap[l] == patternMap[l]) {
                count++;
            }
            else if (textMap[l] == patternMap[l] - 1) {
                count--;
            }
        }
        return count == 26;
    }
    
    
            #include <iostream>
            #include <bits/stdc++.h>
            using namespace std;
            
            int main ()
            {
              string shortone =  "abbc";
              string longone ="cbabadcbbabbcbabaabccbabc";
            
              int s_length = shortone.length ();
              int l_length = longone.length ();
              string sub_string;
              string unsorted_substring; // only for printing
            
              // sort the short one
              sort (shortone.begin (), shortone.end ());
            
              if (l_length > s_length)
                {
                          for (int i = 0; i <= l_length - s_length; i++){
                        
                              sub_string = "";
                              
                              //Move the window
                              sub_string = longone.substr (i, s_length);
                              unsorted_substring=sub_string;
                              
                              // sort the substring window 
                              sort (sub_string.begin (), sub_string.end ());
                              if (shortone == sub_string)
                                {
                                  cout << "substring is :" << unsorted_substring << '\t' <<
                                "match found at the position: " << i << endl;
                                }
                    
                    
                        }
                }
              return 0;
            }