字符串
- 方法一:subtring一行解决
class Solution {
public String dynamicPassword(String password, int target) {
return password.substring(target)+password.substring(0,target);
}
}
- 方法二:局部反转+整体反转
- 反转区间为前n的子串
- 反转区间为n到末尾的子串
- 反转整个字符串
class Solution {
public String dynamicPassword(String password, int target) {
int len=password.length();
StringBuilder sb=new StringBuilder(password);
reverseString(sb,0,target-1);
reverseString(sb,target,len-1);
return sb.reverse().toString();
}
public void reverseString(StringBuilder sb, int start, int end) {
while (start < end) {
char temp = sb.charAt(start);
sb.setCharAt(start, sb.charAt(end));//反转
sb.setCharAt(end, temp);
start++;
end--;
}
}
}
- 方法一:暴力
只要needle开头的字母与haystack的一个字母匹配,马上进入while循环查询是否匹配,如果不匹配,重新开始下一次循环
class Solution {
public int strStr(String haystack, String needle) {
char[] h = haystack.toCharArray();
char[] n = needle.toCharArray();
boolean flag=false;
for(int i=0;i+n.length<=h.length;i++){
int j=i,index=0;
while(h[j]==n[index]){
j++;index++;
if(index==n.length){
flag=true;
break;
}
}
if(flag){
return i;
}
}
return -1;
}
}
官方的暴力解法
class Solution {
public int strStr(String haystack, String needle) {
char[] h = haystack.toCharArray();
char[] n = needle.toCharArray();
for(int i=0;i+n.length<=h.length;i++){
int flag=0;
for(int j=0;j<n.length;j++){
if(h[i+j]!=n[j]){
flag=1;
break;
}
}
if(flag==0){
return i;
}
}
return -1;
}
}
- 方法2:KMP算法
上面两个图解讲的是比较清楚的,可以参考。看完了还不是特别懂。。next数组构造那一块挺难理解,有空再回来看看。
class Solution {
public int strStr(String haystack, String needle) {
if (needle.length() == 0) return 0;
int[] next = new int[needle.length()];
getNext(next, needle);
int j = 0;
for (int i = 0; i < haystack.length(); i++) {
while (j > 0 && needle.charAt(j) != haystack.charAt(i)) //找到匹配不成功的位置,查找前缀表next[j-1],赋值给j。就可以跳到当前位置继续比较
j = next[j - 1];//j前缀表[j-1]的值,
if (needle.charAt(j) == haystack.charAt(i)) //当前字符匹配成功的话,先让j++,结束本次循环后i++
j++;
if (j == needle.length()) //全部匹配成功,返回下标
return i - needle.length() + 1;
}
return -1;
}
private void getNext(int[] next, String s) {
int left = 0;//left指向前缀末尾,也代表了最长相等前后缀
next[0] = 0;//初始化第一位
for (int right = 1; right < s.length(); right++) {//right指向后缀末尾
while (left > 0 && s.charAt(left) != s.charAt(right)) //如果不相等就让left指针回退。这地方特别难理解
left = next[left - 1];
if (s.charAt(left) == s.charAt(right))
left++;
next[right] = left;
}
}
}
- 方法一:暴力
先把s的所有长度<=/2的子字符串,保存到集合str
对子字符串集合进行遍历,记子字符串长度为:m = sub.length()
如果某一个子字符串不能通过重复多次组合成长度等于n的字符串,即n % m != 0,则说明s不能由这个子字符串重复组成;
如果某一子字符串可以通过重复多次组合成长度等于n的字符串,即n % m == 0, 则说明s可能由这个子字符串重复组成。① 若由子字符串组合成新的字符串内容等于s,则返回true,否则遍历下一个子字符串。
class Solution {
public boolean repeatedSubstringPattern(String s) {
int n=s.length();
List<String> str = new ArrayList<>();
for(int i=1;i<=n/2;i++){
str.add(s.substring(0,i));
}
for(String sub: str){
int m=sub.length();
if(n%m!=0) continue;
String sb= new String();
for(int i=0;i<n/m;i++){
sb+=sub;
}
if(s.equals(sb)){
return true;
}
}
return false;
}
}
方法二:移动匹配
这个思路挺妙的
当一个字符串s:abcabc,内部由重复的子串组成,那么这个字符串的结构一定是这样的:
也就是由前后相同的子串组成。
那么既然前面有相同的子串,后面有相同的子串,用 s + s,这样组成的字符串中,后面的子串做前串,前面的子串做后串,就一定还能组成一个s,如图:
所以判断字符串s是否由重复子串组成,只要两个s拼接在一起,里面还出现一个s的话,就说明是由重复子串组成。
当然,我们在判断 s + s 拼接的字符串里是否出现一个s的的时候,要刨除 s + s 的首字符和尾字符,这样避免在s+s中搜索出原来的s,我们要搜索的是中间拼接出来的s。
class Solution {
public boolean repeatedSubstringPattern(String s) {
String str = s + s;
str=str.substring(1,str.length()-1);//掐头去尾
return str.contains(s);
}
}
方法三:KMP(我晕)
真的看不懂,只能记住这个公式,len(s) % (len(s) - maxLen) = 0,其中 len(s) 为字符串 s 的长度,maxLen 为最长公共前后缀的长度。
这个公式翻译一下就是:如果 s 是周期串,那【s 的长度】是【s 的长度减去最长公共前后缀的长度】的倍数,那字符串 s 就是周期串。
class Solution {
public boolean repeatedSubstringPattern(String s) {
if (s.equals("")) return false;
int len = s.length();
int[] next = new int[len];
getNext(next, s);
// 最后判断是否是重复的子字符串,这里 next[len-1] 即代表next数组末尾的值
if (next[len-1] > 0 && len % (len - next[len-1]) == 0) {
return true;
}
return false;
}
private void getNext(int[] next, String s) {
int left = 0;//left指向前缀末尾,也代表了最长相等前后缀
next[0] = 0;//初始化第一位
for (int right = 1; right < s.length(); right++) {//right指向后缀末尾
while (left > 0 && s.charAt(left) != s.charAt(right)) //如果不相等就让left指针回退,到0时就停止回退
left = next[left - 1];
if (s.charAt(left) == s.charAt(right))
left++;
next[right] = left;
}
}
}