【问题标题】:How can I check if two strings are permutations of each other in O(n) time? (java)如何检查两个字符串是否在 O(n) 时间内相互排列? (爪哇)
【发布时间】:2017-02-09 12:35:30
【问题描述】:

我编写了这个类,它可以检查两个给定的字符串是否是彼此的排列。但是,据我了解,这是在 O(n^2) 时间运行的,因为 string.indexOf() 在 O(n) 时间运行。

如何让这个程序更有效率?

import java.util.*;

public class IsPermutation{
   public void IsPermutation(){
      System.out.println("Checks if two strings are permutations of each other.");
      System.out.println("Call the check() method");
   }

   public boolean check(){
      Scanner console = new Scanner(System.in);
      System.out.print("Insert first string: ");
      String first = console.nextLine();
      System.out.print("Insert second string: ");
      String second = console.nextLine();

      if (first.length() != second.length()){
         System.out.println("Not permutations");
         return false;
      }

      for (int i = 0; i < first.length(); i++){
         if (second.indexOf(first.charAt(i)) == -1){
            System.out.println("Not permutations");
            return false;
         } 
      }
      System.out.println("permutations");
      return true;
   }
}

【问题讨论】:

  • 没关系让它更高效,这是不正确的。这将说AAAATTTTTA 的排列。
  • 统计每个字符串的每个字符的个数,并比较它们是否相同。
  • 视情况而定,但如果你知道它只会是 ascii 范围内的字符,我可能会创建一个 int[256] 并使用桶排序来查看它们是否具有相同数量的相同的字符
  • 你可以通过切换到 Haskell 来提高效率

标签: java algorithm


【解决方案1】:

首先,可以在O(nlogn)中对两个字符串进行排序(将它们转换为char[]之后),然后简单的相等测试会告诉你原始字符串是否是排列。

可以通过创建HashMap&lt;Character, Integer&gt; 来实现O(n) 解决方案平均情况,其中每个键是字符串中的一个字符,值是它的出现次数(这称为Histogram)。获得它之后,再次对两个映射进行简单的相等性检查将告诉您原始字符串是否是排列。

【讨论】:

  • 您可以使用 int[65536] 来代替 HashMap,以实现恒定的内存使用。 (或int[128] 用于 ASCII)+1 用于文本,通常称为频率计数。 “直方图”更常用于数字的分布。 (字符是我知道的数字,但通常不是这样想的)
【解决方案2】:

归档 O(n) 的一种方法是计算每个字符出现的频率。

我会使用 HashMap,其中字符作为键,频率作为值。

//create a HashMap containing the frequencys of every character of the String  (runtime O(n) )
public HashMap<Character, Integer> getFrequencys(String s){
    HashMap<Character, Integer> map = new HashMap<>();

    for(int i=0; i<s.length(); i++){
        //get character at position i
        char c = s.charAt(i);

        //get old frequency (edited: if the character is added for the 
        //first time, the old frequency is 0)
        int frequency;
        if(map.containsKey(c)){
            frequency = map.get(c);
        }else{
            frequency = 0;
        }
        //increment frequency by 1
        map.put(c, frequency+1 );
    }

    return map;
}

现在您可以为两个字符串创建一个 HashMap 并比较每个字符的频率是否相同

//runtime O(3*n) = O(n)
public boolean compare(String s1, String s2){
    if(s1.length() != s2.length()){
        return false;
    }

    //runtime O(n)
    HashMap<Character, Integer> map1 = getFrequencys(s1);
    HashMap<Character, Integer> map2 = getFrequencys(s2);

    //Iterate over every character in map1 (every character contained in s1)  (runtime O(n) )
    for(Character c : map1.keySet()){
        //if the characters frequencys are different, the strings arent permutations
        if( map2.get(c) != map1.get(c)){
            return false;
        }
    }

    //since every character in s1 has the same frequency in s2,
    //and the number of characters is equal => s2 must be a permutation of s1

    return true;
}

编辑:(未经测试的)代码中存在空指针错误

【讨论】:

    【解决方案3】:

    分拣解决方案:

    public void IsPermutation(String str1, String str2) {
      char[] sortedCharArray1 = Arrays.sort(str1.toCharArray());
      char[] sortedCharArray2 = Arrays.sort(str2.toCharArray());
    
      return Arrays.equals(sortedCharArray1, sortedCharArray2);
    }
    

    时间复杂度:O(n log n) 空间复杂度:O(n)

    频率计数解决方案:

    //Assuming that characters are only ASCII. The solutions can easily be modified for all characters
    
    public void IsPermutation(String str1, String str2) {
        if (str1.length() != str2.length())
            return false;
    
        int freqCountStr1[] = new int[256];
        int freqCountStr2[] = new int[256];
    
        for (int i = 0; i < str1.length(); ++i) {
            int c1 = str1.charAt(i);
            int c2 = str2.charAt(i);
            ++freqCountStr1[c1];
            ++freqCountStr2[c2];
        }
    
        for (int i = 0; i < str1.length(); ++i) {
            if (freqCountStr1[i] != freqCountStr2[i]) {
                return false;
            }
        }
    
        return true;
      }
    }
    

    时间复杂度:O(n) 空间复杂度:O(256)

    【讨论】:

      猜你喜欢
      • 2020-05-10
      • 1970-01-01
      • 2011-03-14
      • 2021-10-07
      • 2011-10-02
      • 1970-01-01
      • 2011-11-21
      • 2015-10-30
      • 1970-01-01
      相关资源
      最近更新 更多