(编程题)字母易位词

版权声明:如需转载,敬请标明出处。 https://blog.csdn.net/Aphysia/article/details/82997337

题目

两个单词如果包含相同的字母,次序不同,则称为字母易位词(anagram)。例如,“silent”和“listen”是字母易位词,而“apple”和“aplee”不是易位词。请定义函数检查两个单词是否是字母易位词。可以假设两个单词字母均为小写。要求算法复杂度尽量低。

思路

  • 1.暴力破解:判断str1中的每一个字母是否出现在str2中,同时我们需要一个大小与字符串位数一致的数组来记录str2中已经被标记的位。
  public static boolean compare(String str1, String str2) {
    int i,j;
    if (str1 == null && str2 == null) {
      return true;
    }
    if ((str1 == null && str2 != null)
        || (str1 != null && str2 == null)
        || str1.length() != str2.length()) {
      return false;
    }
    // boolean 默认是false
    boolean[] flags = new boolean[str2.length()];
    for (i = 0; i < str1.length(); i++) {
      char temp = str1.charAt(i);
      for (j = 0; j < str2.length(); j++) {
        if (str2.charAt(j) == temp && !flags[j]) {
          flags[j]=true;
          break;
        }
      }
      if(j>=str2.length()){
        return false;
      }
    }
    return true;
  }

我们可以看到用到两个for循环,一个会遍历n次,里层for循环我们假设最坏的情况是每次都走到最后一位(比如world和dlrow),那么里面的次数是n,n-1,n-2…1,复杂程度为

n(n-1)/2=1/2*n^2+1/2*n=O(n^2)
  • 2.是否可以先排序再一一比较就可以了,比较的时候最多是n次,那么我们的排序算法如果能降低复杂度的话,这也是一个好办法。
  public static boolean compare2(String str1,String str2){

    if (str1 == null && str2 == null) {
      return true;
    }
    if ((str1 == null && str2 != null)
            || (str1 != null && str2 == null)
            || str1.length() != str2.length()) {
      return false;
    }
    char[] str1ToChar = str1.toCharArray();
    Arrays.sort(str1ToChar);
    char[] str2ToChar = str2.toCharArray();
    Arrays.sort(str2ToChar);
    for(int i=0;i<str1.length();i++){
      if(str1ToChar[i]!=str2ToChar[i]){
        return false;
      }
    }
    return true;
  }

我们知道java提供的排序算法复杂度是O(n*logn),两次排序加上比较:

2*O(n*logn)+n
  • 3.我们希望能进一步减低算法复杂度,于是想到一个计数器,找到26大小的数组来记录每一个字母出现的次数,遍历第一个数组的时候,个数不断增加,遍历第二个数组的时候,不断减少,如果最后是0,就证明两个字符串中字符出现的次数都是一样的。
  public static boolean compare(String str1,String str2){

    if (str1 == null && str2 == null) {
      return true;
    }
    if ((str1 == null && str2 != null)
            || (str1 != null && str2 == null)
            || str1.length() != str2.length()) {
      return false;
    }
    int[] num = new int[26];
    for(int i=0;i<str1.length();i++){
      num[str1.charAt(i)-'a']++;
    }
    for(int i=0;i<str2.length();i++){
      num[str2.charAt(i)-'a']--;
    }
    for(int i=0;i<num.length;i++){
      if(num[i]!=0){
        return false;
      }
    }
    return true;
  }

我们可以看到这个算法中,遍历两次字符串2*n,又遍历一次m(m<=n).
所以算法的复杂度是:

2*n+m=O(n)

总结:其实里面没有什么深奥的算法,只是一些小技巧,用空间来换取时间,一开始不比较,而是将字符串的异同表现在字符出现的个数上,这样子,问题就迎刃而解了。

猜你喜欢

转载自blog.csdn.net/Aphysia/article/details/82997337