* 描述:
* 给定一个字符串str和长度leftsize,
* 请把str左侧leftsize的部分和右部分做整体交换。要求额外空间复杂度O(1)。
* 例如:
* 输入: abcde 3
* 输出: deabc
* 输入: abcdefgh 5
* 输出: fghabcde
解法一:(10W人中99000人都会的解法)
应用左神一句话,大家都会得东西,你拿出来毫无意义,拿什么凸显自己,人家凭啥要你。
分三次翻转 先翻转前 leftsize个 在翻转其它的 最后整体翻转
先翻转 left --> left + leftsize
然后翻转 left + leftsize + 1 --> right
最后翻转 整体
例如: abcde 3
首先翻转 abc -> cba
然后翻转 de -> ed
此时整个字符串为 cbaed
然后翻转整个字符串结果为:deabc
复杂度分析:
空间复杂度:O(1) 只有有限的几个变量
时间复杂度:
假设左半部分是 L 右半部分是 R
翻转左边 L / 2
翻转右边 R / 2
整体翻转 (L + R) / 2
时间复杂度 大约是 O(2n)
解法一代码实现:
public class Code1 {
// 从 left 到 fight 翻转字符串
public static void reserve(char[] chars, int left, int right) {
while (left < right) {
char temp = chars[left];
chars[left++] = chars[right];
chars[right--] = temp;
}
}
//分三次翻转 先翻转前 leftsize个 在翻转其它的 最后整体翻转
//先翻转 left --> mid 然后翻转 mid + 1 --> right 最后翻转 整体
public static String solution1(char[] chars, int left, int mid, int right) {
reserve(chars, left, mid);
reserve(chars, mid + 1, right);
reserve(chars, left, right);
return String.valueOf(chars);
}
public static String solution1(String str, int leftsize) {
//判空
if (leftsize <= 0 || leftsize >= str.length()) {
return str;
}
return solution1(str.toCharArray(),0,leftsize - 1, str.length() - 1);
}
public static void main(String[] args){
System.out.println(solution1("abcde", 3));
}
}
解法二:
abcdefgh 5
将上例划分为左右两个部分 左5 右str.length - 5 = 3 abcde(left) fgh(right)
取左右部分最小的值为same 作为交换条件 即为 same = 3
首先顺序交换 前三个和后三个 abc fgh
交换完成之后 结果为 fgh de abc
由于是交换之前左部分长 所以是左部分开头same(3)个已经处理完毕 fgh
新的左部分变为 5-3 = 2 de 右部分为 3 abc
新的same = 左右部分字符个数的最小值 即为 2
接下来只需要更改对应指针的值 此问题就递归为 deabc 2(same)
此时是右边长 de abc
还是顺序交换最短的部分所包含的字符数次 也就是2次 左2 < 右3
结果就变为 bcade
由于是交换之前右边长 所以 右侧same(2)个处理完毕 de
新的左部分为 bc 2 右部分为 a 1
此时变为子问题 bca 1(same)
继续交换 结果 acb
由于是交换之前左部分长 所以a 不动 此时变为子问题 cb 1(same)
由于是左边等于右边的长度 所以进行最后一次交换
结果为bc
总体变化流程为:||之间的表示已经处理完毕
abcdefgh -> |fgh| deabc -> |fgh| bca |de| -> |fgha| cb |de| -> fghabcde
abcdefgh 5 -> deabc 2 -> bca 1 -> cb 1
解法二代码实现:
public class Code2 {
//此题的注释以例二为例
public static String solution2(String s, int leftsize) {
//判空
if (leftsize <= 0 || leftsize >= s.length()) {
return s;
}
char[] str = s.toCharArray();
int L = 0;
int R = str.length - 1;
int lpart = leftsize; //左半部分 5 左边未处理的字符数
int rpart = s.length() - leftsize;//右半部分 3 右边未处理的字符数
int same = Math.min(lpart, rpart); //相同个数的部分 same = 3
exchange(str, L, R, same);
//在这个exchange 结束之后 整个字符串 变为fghdeabc
//此结果意味着前 same个字符已经处理好了 剩下就是递归处理后面
//需要做的仅仅就是玩好 L R same 这三个变量而已
while (lpart - rpart != 0) { //此条件表示还有未处理的字符
if (lpart - rpart > 0) { //左边长 fghdeabc
L += same; //于是L左移same个,表示前same(3)个已经处理好了 L指向d
lpart -= same;//也就是意味着 rpart 中已经有same个处理完了
} else {
//同理 右边长 以abcdefgh 3 为例
//第一交换之后 结果为 fghdeabc 右边长表示 右边3个已经交换完毕
//此时只需要递归处理 前面 fghde 即可
R -= same; //修改R的指向
rpart -= same;//也就是意味着 rpart 中已经有same个处理完了
}
same = Math.min(lpart, rpart);
exchange(str, L, R, same);
}
return String.valueOf(str);
}
//str 从左出发数 size个 和 从右出发 数size个 交换
//以例二为例:abcdefgh 5 -> fghabcde
//size = 3 第一次交换完成之后结果为 fghdeabc
//也就是前三个和后三个顺序交换
public static void exchange(char[] str, int L, int R, int sameSize) {
int i = R - sameSize + 1;// 7 - 3 + 1 = 5 (d的位置)
char tmp = 0;
while (sameSize-- != 0) { //size就是交换的次数
tmp = str[L];
str[L++] = str[i];
str[i++] = tmp;
}
}
public static void main(String[] args){
//Test
System.out.println(solution2("abcde", 3));
System.out.println(solution2("abcdefgh", 5));
System.out.println(solution2("abcdefgh", 3));
}
}