344. 反转字符串
思路:没什么特别的思路,要求不能用额外的数组,则可以用两个指针进行操作,不会^的可以用一个char暂存,在进行交换
public void reverseString(char[] s) {
int start=0;
int end=s.length-1;
while(start<end){
s[start]^=s[end];
s[end]^=s[start];
s[start]^=s[end];
start++;
end--;
}
}
[541. 反转字符串 II]
思路:这题难在原题目的解释,其实就是当前k个字符串进行交换,后k个字符串不动,是一轮。这样一轮一轮循环下去,最后不满k个字符串则剩余全部交换。
- 所以
i每次移动都是加上2k,到达新位置
public String reverseStr(String s, int k) {
char[] chr=s.toCharArray();
for(int i=0;i<chr.length;i+=k*2){
//要进行交换
int start=i;
int end=Math.min(i+k,chr.length)-1;
converse(chr,start,end);
}
return new String(chr);
}
public void converse(char[] chars,int s,int e){
while(s<e){
chars[s]^=chars[e];
chars[e]^=chars[s];
chars[s]^=chars[e];
s++;
e--;
}
}
[剑指 Offer 05. 替换空格]
思路:要修改字符串就要想到StringBuilder
public String replaceSpace(String s) {
StringBuilder sb=new StringBuilder();
for(char ch : s.toCharArray()){
if(ch==' '){
sb.append("%20");
}else
sb.append(ch);
}
return sb.toString();
}
151. 反转字符串中的单词
思路:整体先反转一次,就达到所有单词的位置被反转了(不管单词内容),再针对每个单词内部进行反转,这样单词内部内容就正序了!
- 创建三个方法:
- 去除多余空格
- 反转范围内的字符串
- 反转每个单词内容
- 注意要用start作为判断,否则最后一个单词不会被反转到(如果用end作为判断的话,end走到sb.length()不符合条件跳出,于是最后一个单词没反转)
public String reverseWords(String s) {
StringBuilder sb=removeSpace(s);
//整个反转
reverse(sb,0,sb.length()-1);
//反转每个单词
reverseString(sb);
return sb.toString();
}
public StringBuilder removeSpace(String s){
//去除多余空格
int start=0;
while(s.charAt(start)==' ')
start++;
int end=s.length()-1;
while(s.charAt(end)==' ')
end--;
StringBuilder sb = new StringBuilder();
while(start<=end){
char c = s.charAt(start);
//去除中间多余空格
if(c!=' ' || sb.charAt(sb.length()-1)!=' ')
sb.append(c);
start++;
}
return sb;
}
//反转给定范围内的字符串
public void reverse(StringBuilder sb,int start,int end){
while(start<end){
char tmp=sb.charAt(start);
sb.setCharAt(start,sb.charAt(end));
sb.setCharAt(end,tmp);
start++;
end--;
}
}
//反转每个单词
public void reverseString(StringBuilder sb){
int start=0;
int end=start+1;
//要用start作为判断,否则最后一个单词不会被反转到(end走到最后了不符合条件跳出)
while(start<sb.length()){
while(end<sb.length() && sb.charAt(end)!=' ')
end++;
reverse(sb,start,end-1);
start=end+1;
end=start+1;
}
}
剑指 Offer 58 - II. 左旋转字符串
思路:先反转0~n-1的字符串,再反转n~最后的字符串,最后整体反转!
原来:abcdefg
各自反转:ba|gfedc
整体反转:cdefg|ab
public String reverseLeftWords(String s, int n) {
StringBuilder sb=new StringBuilder(s);
converse(sb,0,n-1);
converse(sb,n,sb.length()-1);
converse(sb,0,sb.length()-1);
return sb.toString();
}
public void converse(StringBuilder sb,int start,int end){
if(start>end)
return ;
while(start<end){
char ch=sb.charAt(start);
sb.setCharAt(start,sb.charAt(end));
sb.setCharAt(end,ch);
start++;
end--;
}
}
28. 找出字符串中第一个匹配项的下标(KMP)
思路:这题是KMP经典题目。首先要了解KMP是什么:当前出现字符串不匹配时,可以记录部分之前匹配好的内容,这样下次继续匹配时不需要从头再次开始,而是根据之前已经匹配好的继续开始即可
KMP主要用在匹配字符串,KMP有一个重要组成就是前缀表(一个next数组),它是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。
前缀表:记录下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀
- 前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串
- 后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串
其他具体KMP介绍看代码随想录这篇笔记写的很清楚还有视频可以看28. 实现 strStr()
public int strStr(String haystack, String needle) {
if(needle==null || needle.length()==0)
return -1;
int[] next=new int[needle.length()];
getNext(next,needle);
int j=0; //j 指向模式串needle起始位置,i指向文本串haystack起始位置
for(int i=0;i<haystack.length();i++){
while(j>0 && haystack.charAt(i)!=needle.charAt(j))
j=next[j-1]; //当前不匹配,j就要从next数组里寻找下一个匹配的位置
if(haystack.charAt(i)==needle.charAt(j)){
j++; //匹配,向后移动
}
if(j==needle.length()) //j来到模式串末尾表示都匹配完了!
return i-needle.length()+1; //下标从0开始所以+1
}
return -1;
}
private void getNext(int[] next,String s){
int j=0; //j指向前缀末尾位置,i指向后缀末尾位置
next[0]=0;
for(int i=1;i<s.length();i++){
//处理前后缀不相同的情况
if(j>0 && s.charAt(i)!=s.charAt(j)){
//进行回退,找j前一个元素在next数组里的值,就是它要回退到的位置
j=next[j-1];
}
//处理前后缀相同的情况
if(s.charAt(i)==s.charAt(j)){
j++; //j向后移动
}
next[i]=j; //next[i]要记录此时相同前后缀的长度
}
}
459. 重复的子字符串
思路:一样用KMP next数组最后一个值,可以得到下标i之前(包括i)有多大长度的相同前缀后缀,最大长度相同前缀后缀就可以想成是多个重复子串的组合。
public boolean repeatedSubstringPattern(String s) {
if(s.equals(""))
return false;
int[] next=new int[s.length()];
getNext(next,s);
int len=s.length();
int x=next[len-1];
//len-x得到剩余的字符串(可能是最小重复zi chuan,长度除以剩余字符串的余数为0表示都是由重复字符串所组成没有其他额外字符串
if(x!=0 && len%(len-x)==0)
return true;
return false;
}
private void getNext(int[] next,String s){
int j=0;
next[0]=0;
for(int i=1;i<s.length();i++){
while(j>0 && s.charAt(j)!=s.charAt(i)){
j=next[j-1];
}
if(s.charAt(j)==s.charAt(i))
j++;
next[i]=j;
}
}
思路:
思路:
思路:
思路: