目录
给定两个字符串A、B,判断B在A中是否存在,存在返回A中的下标,不存在返回-1。
题目:
给定两个字符串A、B,判断B在A中是否存在,存在返回A中的下标,不存在返回-1。
例:A: ABCABCAABCABCD
B: ABCABCD
返回值:7
(全部代码及运行结果放于最后)
1、暴力循环(BF)
逐个字符比对,不相同后移一位继续比对。知道查找到结束。
2、RK算法
在主串中找到对应等于模式串(例如:ABCABCD)的子串,利于hash函数计算hash值对比是否一样,一样查找成果返回。
相比于BF算法只是改变了字符串比较的方法。
此处主要注意hash函数的设置,减少hash冲突。
我使用的hash函数:
public static int hashfunction(String str){
int m=str.length()*10000;
for (int i = 0; i < str.length(); i++) {
m+= (int) str.charAt(i)*i;
}
return m;
}
3、BM算法
相对于暴力循环改变了本次的移动步长,不是原来的1位。主要利于好后缀和坏字符两种方式寻找最佳移动步长。
坏字符规则:从右往左匹配,找到A中第一个不匹配的字符(坏字符),将B串右移、直到B串出现与A串坏字符对齐的字符,再从右往左寻找坏字符。如果B串中没有该坏字符、则直接移到该坏字符的下一位即可。
好后缀规则:从右往左匹配,找到坏字符(意味着该坏字符后面的串是匹配的,该串即为好后缀),往左寻找B中是否还有该好后缀,如果有、将B右移到该位置与A好后缀对齐。重复该规则。如果B串往右没有该好后缀,则右移到好后缀的往右错一位的位置,重复该规则。避免B串的前缀与好后缀的后缀匹配。
坏字符:A
好后缀:BC
两种规则综合使用,哪种移动的位数多使用哪种。
时间复杂度:o(n/m),最坏O(m*n)
代码:
package SF;
/*
* 字符串查找
* 1、BF算法
* 2、RK算法
* 3、BM算法
* */
public class Stringsearch {
public static void main(String[] args) {
String str1="ABCACBCAABCDB";
String str2="ABCDB";
System.out.println(search(str1,str2));
System.out.println(search1(str1,str2));
System.out.println(search2(str1,str2));
}
/*
* 1、暴力循环
* */
public static int search(String str1,String str2){
int m=str1.length();
int n=str2.length();
if (m<n)return -2;
for (int i = 0; i <=m-n; i++) {
int j;
for ( j = 0; j <n; j++) {
if(str1.charAt(i+j)!=str2.charAt(j))break;
}
if(j==n)return i+1;
}
return -1;
}
/*
* 2、RK算法,利用hash函数获取哈希值
* */
public static int search1(String str1,String str2){
int m=str1.length();
int n=str2.length();
if (m<n)return -2;
int str2hash=hashfunction(str2);
for (int i = 0; i <=m-n; i++) {
String s=strsplit(str1,i,n);
if (hashfunction(s)==str2hash)return i+1;
}
return -1;
}
public static int hashfunction(String str){
int m=str.length()*10000;
for (int i = 0; i < str.length(); i++) {
m+= (int) str.charAt(i)*i;
}
return m;
}
public static String strsplit(String str,int start,int length){
if ((start+length)>str.length()) System.err.println("不可分割");
char[] chars=new char[length];
for (int i = 0; i < length; i++) {
chars[i]=str.charAt(i+start);
}
return new String(chars);
}
/*
* 3、BM算法,计算最佳移动步长
* */
public static int search2(String str1,String str2){
int m=str1.length();
int n=str2.length();
if (m<n)return -2;
int move=0;
for (int c = 0; c <= m-n; c=c+move+1) {
//查找
String buf=strsplit(str1,c,n);
if (hashfunction(buf)==hashfunction(str2))return c+1;
//计算移动步长
StringBuilder goodstr= new StringBuilder();
char badstr = 0;
int moveg=0;//好字符移动步长
int moveb=0;//坏字符移动步长
int index=0;
//查找好字符和坏字符
for (int i = n-1; i >=0; i--) {
if(str2.charAt(i)==buf.charAt(i)) goodstr.append(str1.charAt(i));
else {badstr=buf.charAt(i);index=i;break;};
}
//计算坏字符移动步长
for (int i = index-1; i >=0; i--) {
if (badstr==str2.charAt(i)){
moveb=index-i;
break;
}
}
//计算好字符移动步长
goodstr.reverse();
String goodstr1= String.valueOf(goodstr);
for (int i = index-goodstr.length(); i >=0; i--) {
String newstr=strsplit(str2,i,goodstr.length());
if(newstr.equals(goodstr1)){
moveg=index-i+1;
break;
}
}
//取最大步长
move=Math.max(moveb,moveg)-1;
if (move<0)move=0;
}
return -1;
}
}
运行结果:
9
9
9
进程已结束,退出代码0