第四章 字符串part02
151.翻转字符串里的单词
Leetcode链接: 翻转字符串里的单词
class Solution {
public String reverseWords(String s) {
int left = 0;
int right = s.length() - 1;
//去除首位空格
while (left <= right && s.charAt(left) == ' ') {
left++;
}
while (left <= right && s.charAt(right) == ' ') {
right--;
}
//去除中间的多余空格
StringBuilder sb = new StringBuilder();
while(left <= right){
char c = s.charAt(left);
if(c != ' '){
sb.append(c);
}else if(sb.charAt(sb.length()-1) != ' '){
sb.append(c);
}
left++;
}
//反转字符串
reverse(sb, 0, sb.length() - 1);
//反转每个单词
int n = sb.length();
int start = 0, end = 0;
while (start < n) {
while (end < n && sb.charAt(end) != ' ') {
++end;
}
reverse(sb, start, end - 1);
start = end + 1;
end++;
}
return sb.toString();
}
public void reverse(StringBuilder sb, int left, int right) {
while (left < right) {
char tmp = sb.charAt(left);
sb.setCharAt(left++, sb.charAt(right));
sb.setCharAt(right--, tmp);
}
}
}
本来一开始想到的方法就是使用java的split方法,然后再反转得到的array。如果这么做这道题就没有太大的意义了。后来看了一下答案,答案用的这个方法是这样的,一开始我们得到一个这样的string:
String s = " hello world "
首先去掉首位的空格让String变成:
String s = "hello world"
再翻转string得到,
String s = "dlrow olleh"
然后再把里面的单词翻转过来,翻转的时候遇到空格就只保留一个空,最后得到答案
String s = " world hello"
卡码网:55.右旋转字符串
题目链接: 右旋转字符串
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = Integer.parseInt(in.nextLine());
String s = in.nextLine();
n = n % s.length();
String front = s.substring(0,s.length()-n);
String end = s.substring(s.length()-n,s.length());
System.out.println(end+front);
}
}
这是我最开始想到的方法,先把,好像做过这种题目,但是发现这个方法的速度确实有点慢。看到了网上另外一种的方法。先把String从0到n的翻转,再把n到最后的翻转,再两个一个翻转。
下面是c++代码:
// 版本二
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
int n;
string s;
cin >> n;
cin >> s;
int len = s.size();
reverse(s.begin(), s.begin() + len - n);
reverse(s.begin() + len - n, s.end());
reverse(s.begin(), s.end());
cout << s << endl;
}
28. 实现 strStr()
Leetcode链接: 找出字符串中第一个匹配项的下标
这题使用的是KMP算法是最好的,但是为什么自己每次学完KMP算法很快就会忘记。
视频链接: 最浅显易懂的 KMP 算法讲解
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length(), m = needle.length();
if (m == 0) {
return 0;
}
int[] pi = makeNext(needle);
for (int i = 0, j = 0; i < n; i++) {
while (j > 0 && haystack.charAt(i) != needle.charAt(j)) {
j = pi[j - 1];
}
if (haystack.charAt(i) == needle.charAt(j)) {
j++;
}
if (j == m) {
return i - m + 1;
}
}
return -1;
}
public int[] makeNext(String str) {
int len = str.length();
if(len == 1){
return new int[]{0};
}
int[] next = new int[len];
int j = 0;
next[0] = 0;
for(int i = 1; i < len; ){
if(str.charAt(i) != str.charAt(j)){
if(j != 0){
j = next[j-1];
}else{
next[i] = 0;
i++;
}
}else{
j+=1;
next[i] = j;
i++;
}
}
return next;
}
}
459.重复的子字符串
class Solution {
public boolean repeatedSubstringPattern(String s) {
if (s.equals("")) return false;
int len = s.length();
// 原串加个空格(哨兵),使下标从1开始,这样j从0开始,也不用初始化了
s = " " + s;
char[] chars = s.toCharArray();
int[] next = new int[len + 1];
// 构造 next 数组过程,j从0开始(空格),i从2开始
for (int i = 2, j = 0; i <= len; i++) {
// 匹配不成功,j回到前一位置 next 数组所对应的值
while (j > 0 && chars[i] != chars[j + 1]) j = next[j];
// 匹配成功,j往后移
if (chars[i] == chars[j + 1]) j++;
// 更新 next 数组的值
next[i] = j;
}
// 最后判断是否是重复的子字符串,这里 next[len] 即代表next数组末尾的值
if (next[len] > 0 && len % (len - next[len]) == 0) {
return true;
}
return false;
}
}