字符串6:两串旋转练习题(*)

时间:2023-02-24 11:33:25

题目:如果对于一个字符串A,将A的前面任意一部分挪到后边去形成的字符串称为A的旋转词。比如A="12345",A的旋转词有"12345","23451","34512","45123"和"51234"。对于两个字符串A和B,请判断A和B是否互为旋转词。给定两个字符串A和B及他们的长度lena,lenb,请返回一个bool值,代表他们是否互为旋转词。测试样例:"cdab",4,"abcd",4  返回:true

思路:这题与前面String2:左旋字符串题目近似。String2中是给出一个字符串,求出左旋k个字符后的字符串。本题是给定两个字符串,判断是否是旋转字符串。求字符串旋转k后的新的字符串可以看做单词反转问题通过2次反转进行解决,也可以使用str=str+str拼接成为大字符串后移动k个字符后进行截取length个字符来实现。本题中判断两个字符串是否是旋转关系,由于k不确定,因此方法1是假设k从0开始到k进行逐一反转再与str2进行比较,每次旋转时间复杂度为O(n),共要旋转n次,故时间复杂度为O(N^2),方法2是拼接成为大字符串后从k=0开始截取length长度的字符串与str2进行比较,要比较n次,每次比较要对length=n长度的字符串进行遍历,因此时间复杂度是O(N^2),空间复杂度为O(n)--如果仅仅是左旋K个字符,2种方法时间复杂度分别为O(n)和O(1),空间复杂度为O(1)和O(n).

本题中首先拼接得到大字符串,然后从k=0~k=length-1进行遍历,每次长度为length的字符串,看是否匹配str2。对于字符串的匹配,可以使用kmp算法,kmp算法专门用于进行字符串的匹配,在长度为n的字符串搜索匹配长度为m的字符串的时间复杂度可以降低为O(m+n).所以本题关键是kmp算法的理解和使用。

字符串的str1.contains(str2)方法的底层实现就是使用kmp算法来进行匹配的。可以使用contains()方法,但是对于kmp算法也要掌握。

基于String类库的代码:

import java.util.*;
public class Rotation {
public boolean chkRotation(String A, int lena, String B, int lenb) {
// write code here
if(lena!=lenb){
return false;
}
String C = A+A;
//直接使用了String类库的contains()方法,其底层实现时KMP算法
return C.contains(B);
}
}

基于KMP算法的代码:

Kmp算法的原理容易理解,就是避免每次匹配失败后有从pattern串的头部开始匹配,而是通过借助pattern串的覆盖函数,跳过不可能匹配的位置,直接从可能匹配的位置开始比较。

已知目标串target和模式串pattern:

步骤①求出覆盖函数的数组

对于pattern,先得到这个字符串的覆盖函数数组next[],对于数组next[],其中的元素next[i]是指i前面的字符串中覆盖的字符个数,所谓覆盖是中一个字符串中开头的k个字符和结尾的k个字符相同,例如abcedab的覆盖函数是2,即字符ab产生了覆盖。

通过以下函数来计算一个pattern字符串的覆盖函数数组。

public int[] getNextArray(char[] ms) {
if (ms.length == 1) {
return new int[] { -1 };
}
int[] next = new int[ms.length];
next[0] = -1;
next[1] = 0;
int pos = 2;
int cn = 0;
while (pos < next.length) {
if (ms[pos - 1] == ms[cn]) {
next[pos++] = ++cn;
} else if (cn > 0) {
cn = next[cn];
} else {
next[pos++] = 0;
}
}
return next;
}
}

步骤②:找出模式串在目标串中的位置

例如对于char[] chars={'a','b','a','a','b','c','a','b','a'};得到的next数组是{-1,0,0,1,1,2,0,1,2}

总的实现代码是:
import java.util.*;
public class Rotation {
public boolean chkRotation(String a, int lena, String b, int lenb) {
if (a == null || b == null || lena != lenb) {
return false;
}
String b2 = b + b;
return getIndexOf(b2, a) != -1;
}

// KMP Algorithm
public int getIndexOf(String s, String m) {
if (s.length() < m.length()) {
return -1;
}
char[] ss = s.toCharArray();
char[] ms = m.toCharArray();
int si = 0;
int mi = 0;
int[] next = getNextArray(ms);
while (si < ss.length && mi < ms.length) {
if (ss[si] == ms[mi]) {
si++;
mi++;
} else if (next[mi] == -1) {
si++;
} else {
mi = next[mi];
}
}
return mi == ms.length ? si - mi : -1;
}

public int[] getNextArray(char[] ms) {
if (ms.length == 1) {
return new int[] { -1 };
}
int[] next = new int[ms.length];
next[0] = -1;
next[1] = 0;
int pos = 2;
int cn = 0;
while (pos < next.length) {
if (ms[pos - 1] == ms[cn]) {
next[pos++] = ++cn;
} else if (cn > 0) {
cn = next[cn];
} else {
next[pos++] = 0;
}
}
return next;
}
}
参考:http://blog.csdn.net/power721/article/details/6132380

字符串6:两串旋转练习题(*)