* 描述:
* 給定一個字符串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));
}
}