最近做了几道字符串旋转的问题,发现其解决思路是一样的,于是写此文小结一下。
1、左旋转字符串
题目描述
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcXYZdef"和数字3,该函数将返回左旋转两位得到的结果"XYZdefabc"。
解题思路
这道题当然可以用简单的substring方法直接得结果,但是这应该不是算法出题者的本意。
解这种题常用的思路是多次翻转,我们要知道 BA = 旋转(旋转(A)旋转(B))
意思也就是 按题意分割的部分先旋转,再将整体旋转,最后就是所得的结果。
若还不懂可以看下图说明:
明白了实现思路在写代码就容易了。
package String;
/**
* @description: 左旋转字符串
* Input:
* S="abcXYZdef"
* K=3
*
* Output:
* "XYZdefabc"
* @author: Kevin
* @createDate: 2020/2/23
* @version: 1.0
*/
public class LeftRotateString {
public static void main(String[] args) {
String str = "abcXYZdef";
int n = 3;
LeftRotateString solution = new LeftRotateString();
String res = solution.LeftRotateString(str, n);
System.out.println(res); // XYZdefabc
}
public String LeftRotateString(String str, int n) {
if (n >= str.length())
return str;
char[] chars = str.toCharArray();
reverse(chars, 0, n - 1);
reverse(chars, n, chars.length - 1);
reverse(chars, 0, chars.length - 1);
return new String(chars);
}
private void reverse(char[] chars, int i, int j) {
while (i < j)
swap(chars, i++, j--);
}
private void swap(char[] chars, int i, int j) {
char t = chars[i];
chars[i] = chars[j];
chars[j] = t;
}
}
2、右旋转字符串(没这道题,自己举的hh)
要学会举一反三,有左旋同样可以实现右旋。
package String;
/**
* @description: 自举:右旋转字符串
* * Input:
* * S="abcXYZdef"
* * K=3
* *
* * Output:
* * "defabcXYZ"
* @author: Kevin
* @createDate: 2020/2/23
* @version: 1.0
*/
public class RightRotateString {
public static void main(String[] args) {
String str = "abcXYZdef";
int n = 3;
RightRotateString solution = new RightRotateString();
String res = solution.RightRotateString(str, n);
System.out.println(res); // defabcXYZ
}
public String RightRotateString(String str, int n) {
if (n >= str.length())
return str;
char[] chars = str.toCharArray();
int l = chars.length;
// 区别就是选择的起始位置
reverse(chars, l - n, l - 1);
reverse(chars, 0, l - n - 1);
reverse(chars, 0, l - 1);
return new String(chars);
}
private void reverse(char[] chars, int i, int j) {
while (i < j)
swap(chars, i++, j--);
}
private void swap(char[] chars, int i, int j) {
char t = chars[i];
chars[i] = chars[j];
chars[j] = t;
}
}
3、翻转单词顺序列
题目描述
力扣链接
输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. “,则输出"student. a am I”。
解题思路
同样是多次旋转,只不过是分割的条件不在是上题中的n,而是成了判断单词。
package String;
/**
* @description: 翻转单词顺序列
* @author: Kevin
* @createDate: 2020/2/24
* @version: 1.0
*/
public class ReverseSentence {
public static void main(String[] args) {
ReverseSentence solution = new ReverseSentence();
String str = "I am a student.";
System.out.println(solution.ReverseSentence(str)); // student. a am I
}
public String ReverseSentence(String str){
int n = str.length();
char[] chars = str.toCharArray();
int i=0,j=0;
while (j <= n) {
// 空格分割单词,或者为最后一个词
if (chars[j]==' ' || j==n){
reverse(chars, i, j-1);
i = j+1;
}
j++;
}
reverse(chars, 0, n - 1);
return new String(chars);
}
/**
* 翻转字符串
* @param chars 待翻转字符串
* @param s 起点
* @param e 终点
*/
private void reverse(char[] chars,int s,int e){
while(s<e){
swap(chars, s++, e--);
}
}
private void swap(char[] chars,int s,int e){
char t = chars[s];
chars[s] = chars[e];
chars[e] = t;
}
}