我最近被要求设计一种算法来检查两个字符串是否是彼此的字谜。我的目标是最小化空间和时间复杂度,所以我想出了这个算法:
- 创建一个包含 26 个元素的数组,每个元素都初始化为零。
- 遍历第一个字符串并为每个字符递增对应于该字符的数组元素。
- 遍历第二个字符串,并为每个字符递减对应于该字符的数组元素。
- 扫描阵列。如果所有元素都为 0,则这两个字符串是字谜。
但是,这个算法的时间复杂度是 O(n),我想不出一个复杂度更低的算法。有人知道吗?
我最近被要求设计一种算法来检查两个字符串是否是彼此的字谜。我的目标是最小化空间和时间复杂度,所以我想出了这个算法:
但是,这个算法的时间复杂度是 O(n),我想不出一个复杂度更低的算法。有人知道吗?
您的算法是渐近最优的。不可能在 Ω(n) 时间内更好地解决这个问题。为了看到这一点,假设存在可以在 o(n) 时间内解决问题的算法 A(请注意,这里是 n 的 little-o)。那么对于任何 1 > ε > 0,有一些 n 使得对于任何大小至少为 n 的输入,算法必须在最多 εn 步中终止。设置 ε = 1/3 并考虑算法的任何输入,对于前面提到的这个 ε,长度至少为 n。由于该算法最多只能查看两个字符串中 1/3 的字符,因此该函数必须有两个不同的输入,一个是一对字谜,一个不是,这样算法就可以查看每个输入的字符的相同子集。然后该函数必须在每种情况下产生相同的输出,因此至少在其中一个输入上是错误的。我们遇到了一个矛盾,所以这样的算法一定不存在。
您可以通过提前退出来提高平均性能。在扫描第二个字符串时,如果在递减之前 count[char] 为 0,则您没有字谜,您可以停止扫描。
此外,如果字符串短于 26 个字符,则在最后一步中,仅检查第一个字符串中的字符是否为零。
这不会改变大 O,但它可以将您的平均运行时间更改为小于建议解决方案的 2N+26 o,具体取决于您的数据。
为了确保字符串是字谜,您需要比较整个字符串 - 那么这怎么可能比 o(n) 快?
让我们提出一个问题:给定两个字符串 s 和 t,编写一个函数来确定 t 是否是 s 的字谜。
例如,s = "anagram",t = "nagaram",返回 true。s =“老鼠”,t =“汽车”,返回假。
方法一(使用 HashMap ):
public class Method1 {
public static void main(String[] args) {
String a = "protijayi";
String b = "jayiproti";
System.out.println(isAnagram(a, b ));// output => true
}
private static boolean isAnagram(String a, String b) {
Map<Character ,Integer> map = new HashMap<>();
for( char c : a.toCharArray()) {
map.put(c, map.getOrDefault(c, 0 ) + 1 );
}
for(char c : b.toCharArray()) {
int count = map.getOrDefault(c, 0);
if(count == 0 ) {return false ; }
else {map.put(c, count - 1 ) ; }
}
return true;
}
}
方法二:
public class Method2 {
public static void main(String[] args) {
String a = "protijayi";
String b = "jayiproti";
System.out.println(isAnagram(a, b));// output=> true
}
private static boolean isAnagram(String a, String b) {
int[] alphabet = new int[26];
for(int i = 0 ; i < a.length() ;i++) {
alphabet[a.charAt(i) - 'a']++ ;
}
for (int i = 0; i < b.length(); i++) {
alphabet[b.charAt(i) - 'a']-- ;
}
for( int w : alphabet ) {
if(w != 0 ) {return false;}
}
return true;
}
}
方法3:
public class Method3 {
public static void main(String[] args) {
String a = "protijayi";
String b = "jayiproti";
System.out.println(isAnagram(a, b ));// output => true
}
private static boolean isAnagram(String a, String b) {
char[] ca = a.toCharArray() ;
char[] cb = b.toCharArray();
Arrays.sort( ca );
Arrays.sort( cb );
return Arrays.equals(ca , cb );
}
}
方法四:
public class Method4 {
public static void main(String[] args) {
String a = "protijayi";
String b = "jayiproti";
//String c = "gini";
System.out.println(isAnagram(a, b ));// output => true
}
private static boolean isAnagram(String a, String b) {
Map<Integer, Integer> map = new HashMap<>();
a.codePoints().forEach(code -> map.put(code, map.getOrDefault(code, 0) + 1));
b.codePoints().forEach(code -> map.put(code, map.getOrDefault(code, 0) - 1));
//System.out.println(map.values());
for(int count : map.values()) {
if (count<0) return false;
}
return true;
}
}
int anagram (char a[], char b[]) {
char chars[26];
int ana = 0;
int i =0;
for (i=0; i<26;i++)
chars[i] = 0;
if (strlen(a) != strlen(b))
return -1;
i = 0;
while ((a[i] != '\0') || (b[i] != '\0')) {
chars[a[i] - 'a']++;
chars[b[i] - 'a']--;
i++;
}
for (i=0; i<26;i++)
ana += chars[i];
return ana;
}
void main() {
char *a = "chimmy\0";
char *b = "yimmch\0";
printf ("Anagram result is %d.\n", anagram(a,b));
}