我正在尝试解决以下问题
你有两个字符串。 A尺寸为n,B,尺寸为m。米是非常非常的 与n相比较少。找出A是否包含子串 是B的字谜。
我采取的方法如下
public static boolean ana_check(String a, String b)
{
int n=a.length();
int m=b.length();
boolean k;
for(int i=0;i<=(n-m);i++){
k= anagram((a.substring(i,i+m)),b);
if(k)
return true;
}
return false;
}
正如你所看到的,我从字符串A的开头开始提取每个长度为m的字符串,并检查它是否是B的字谜。 为了检查anagram我为每个字符串构建了一个频率图,如果发现它们是相同的,我返回true。代码如下:
public static boolean anagram(String s, String t) {
// Strings of unequal lengths can't be anagrams
if(s.length() != t.length()) {
return false;
}
// They're anagrams if both produce the same 'frequency map'
return frequencyMap(s).equals(frequencyMap(t));
}
private static Map<Character, Integer> frequencyMap(String str) {
Map<Character, Integer> map = new HashMap<Character, Integer>();
for(char c : str.toLowerCase().toCharArray()) {
Integer frequency = map.get(c);
map.put(c, frequency == null ? 1 : frequency+1);
}
return map;
}
我相信anagram方法在O(n)时间运行。 ana_check方法的时间复杂度是多少?整个代码是线性的还是二次的?
答案 0 :(得分:2)
好吧,让我们看看......
假设length()方法在恒定时间内运行(即:它不像strlen()那样工作)。 你的方法frequencyMap是o(m),anagram调用它两次。字谜称为n-m次。 总复杂度大约为o(2 * m * n)。 m <&lt;&lt; n,'big o'是O(n)。
我可以建议一些优化。首先,您在每次调用anagram时重新生成字符串b的频率图。在ana_check的开头做一次。你可以有一个anagram方法,它采用字符串和频率图而不是两个字符串。
我要做的另一件事是从字谜中删除长度检查。是的,这是一个安全功能,但您已经知道传入的字符串大小相同。无论如何,如果它们的长度不同,频率图仍然不匹配,因此功能正确。
更棘手的优化是修改字符串a的频率图,而不是每次都重新进行。对于第一个子字符串,您可以照常执行。但是你向前移动一个角色,从地图中减去第一个角色并添加新角色。当然,如果m <= 3则不会产生影响,但任何大于此的东西都将是胜利。
答案 1 :(得分:0)
您无需比较每个位置的整个地图。
首先创建一个签名的频率图并减去每个字母
在B
。保留一个计数器c
,其中包含多少个非零条目
在地图上。
接下来,将m
的{{1}}个字母B
添加到地图中。对于
您添加的每个字母,如果该计数过去为零,则递增A
,
或者如果在添加完字母后它变为零,则递减c
。
如果c
现在为零,那么你就找到了一个字谜(每个负数
来自c
的来自B
的积极计数平衡了,否则
继续。
将A
的下一个字母添加到频率图中,然后删除该字母
在此之前发出A
个字母,对两者进行适当调整m
操作
重复最后两步,直到c
变为零或用完为止
c
中的字母。
您可以尝试通过每次识别来进一步优化这一点
你添加一个没有出现在A
中的角色,你可以保证一个
不匹配下一个B
个字符(这与计数只是正数的位置不同,因为您传递的其他字符可能会在m
之前取消)。所以你可以重启
这封信后的先决条件。操作的复杂性
这允许你跳过不是很高,但这和特殊情况
代码可能不会更快。