给你一个字符串 s
,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s
中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
**注意:**输入字符串 s
中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
示例
输入:s = “the sky is blue”
输出:“blue is sky the”
题目链接
https://leetcode.cn/problems/reverse-words-in-a-string/description/
要得到目标字符串我们要做三步
在处理第一步上略显麻烦。
class Solution {
public String reverseWords(String s) {
int newlen = 0, fast = 0;//newlen为处理空格后的字符串长度,fast为遍历当前字符串的下标
char[] ch = s.toCharArray();
//去除多余的空格
while(ch[fast] == ' '){//处理前导空格
fast++;
}
//处理中间和尾随空格
while(fast < ch.length){//根据前面移除元素的方法
if(ch[fast] != ' '){
//正常为字符情况
ch[newlen++] = ch[fast++];
}
else if(ch[fast] == ' ' && ch[fast - 1] != ' '){//保留分隔空格
ch[newlen++] = ' ';
fast++;
}else if(ch[fast] == ' ' && ch[fast - 1] == ' '){//去除中间的连续空格
fast++;
}
}
if(ch[newlen - 1] == ' '){//如果末尾是空格,则总长度减1
newlen--;
}
char[] ans = new char[newlen];
for(int i = 0; i < newlen; i++){
ans[i] = ch[i];
}
//反转整个字符串
reverse(ans, 0, newlen - 1);
//反转单词
int last = 0;
for(int i = 0; i < newlen; i++){
if(ans[i] == ' '){
reverse(ans, last, i - 1);
last = i + 1;
}
}
reverse(ans, last, newlen - 1);
return new String(ans);
}
public static void reverse(char[] ch, int l, int r){
while(l < r){
char temp = ch[r];
ch[r] = ch[l];
ch[l] = temp;
l++;
r--;
}
}
}
字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k,请编写一个函数,将字符串中的后面 k 个字符移到字符串的前面,实现字符串的右旋转操作。
例如,对于输入字符串 “abcdefg” 和整数 2,函数应该将其转换为 “fgabcde”。
输入描述
输入共包含两行,第一行为一个正整数 k,代表右旋转的位数。第二行为字符串 s,代表需要旋转的字符串。
输出描述
输出共一行,为进行了右旋转操作后的字符串。
输入示例
2
abcdefg
输出示例
fgabcde
题目链接
https://kamacoder.com/problempage.php?pid=1065
要得到目标字符串, 可以分为三步
k
个字符当然还有一种投机的方法, 就是先把后k
个放入新数组, 在放前面的。不过这样就缺少了点乐趣。
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int k = scanner.nextInt();
String s = scanner.next();
int len = s.length();
char[] ch = new char[len];
for(int i = 0; i < len; i++){
if(len - k + i < len)
ch[i] = s.charAt(len - k + i);
else
ch[i] = s.charAt(i - k);
}
String ans = new String(ch);
System.out.println(ans);
}
}
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int k = scanner.nextInt();
String s = scanner.next();
char[] ch = s.toCharArray();
reverse(ch, 0, ch.length - 1);
reverse(ch, 0, k - 1);
reverse(ch, k, ch.length - 1);
System.out.println(new String(ch));
}
public static void reverse(char[] ch, int l, int r){
while(l < r){
char temp = ch[l];
ch[l] = ch[r];
ch[r] = temp;
l++;
r--;
}
}
}
给你两个字符串 haystack
和 needle
,请你在 haystack
字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle
不是 haystack
的一部分,则返回 -1
。
示例
输入:haystack = “sadbutsad”, needle = “sad”
输出:0
解释:“sad” 在下标 0 和 6 处匹配。
第一个匹配项的下标是 0 ,所以返回 0 。
题目链接
https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/
可以用h
和n
代表遍历到这两个字符串转换为数组后的下标位置, 如果不同则重置h
和n
的大小。否则持续遍历, 直至n = needle.length
。
class Solution {
public int strStr(String haystack, String needle) {
char[] hay = haystack.toCharArray();
char[] need = needle.toCharArray();
//haystack长度小于needle直接退出
if(hay.length < need.length)
return -1;
//hay搜索下标为h,needle搜索下标n,hay[h] == need[n], h++,n++; n == needle.length, return h - n;
//hay[h] != need[n], h = h - n + 1, n = 0
int h = 0, n = 0;
while(n < need.length && h < hay.length){
if(hay[h] == need[n]){
h++;
n++;
}
else{
h = h - n + 1;
n = 0;
}
}
if(n == need.length)
return h - n;
else
return -1;
}
}
给定一个非空的字符串 s
,检查是否可以通过由它的一个子串重复多次构成。
示例
输入: s = “abab”
输出: true
解释: 可由子串 “ab” 重复两次构成。
题目链接
https://leetcode.cn/problems/repeated-substring-pattern/description/
暴力求解思路: 遍历所有可能是子串的长度len
, 长度满足0 < len <= s.length / 2
。还必须满足len
是主串长度的因数, 这样才能重复组成。
移动匹配思路: 若 s
由重复子串构成,则 s
一定存在于 (s + s).substring(1, 2n-1)
中。例如:
s = "abab"
→ s + s = "abababab"
→ 去掉首尾字符后为 "bababa"
,其中包含原字符串 "abab"
。可以这么理解
假设 s
由子串 t
重复 k
次构成(k ≥ 2
),则:
s + s = t + t + ... + t
(重复 2k
次)。2k-2
次 t
,因此原字符串 s
必然存在其中。还有一种利用KMP的解法, 但是我还没弄明白。
public class Solution {
public boolean repeatedSubstringPattern(String s) {
int n = s.length();
// 遍历所有可能的子串长度(必须是n的因数)
for (int k = 1; k <= n / 2; k++) {
if (n % k != 0) continue; // 跳过非因数
String sub = s.substring(0, k);
boolean valid = true;
// 检查子串是否能重复构成原字符串
for (int i = 1; i < n / k; i++) {
String current = s.substring(i * k, (i + 1) * k);
if (!current.equals(sub)) {
valid = false;
break;
}
}
if (valid) return true;
}
return false;
}
}
public class Solution {
public boolean repeatedSubstringPattern(String s) {
String ss = s + s;
int n = s.length();
return ss.substring(1, 2 * n - 1).contains(s);
}
}