Java數據結構和算法總結-字符串相關高頻面試題算法

  前言:週末閒來無事,看了看字符串相關算法的講解視頻,收貨頗豐,跟着視頻講解簡單作了一下筆記,方便之後翻閱複習同時也很樂意分享給你們。什麼字符串在算法中有多重要之類的大路邊上的客套話就很少說了,直接上筆記吧。java

1、字符串正則表達式

  • java:String內置類型,不可更改。(如需更改可考慮:StringBuffer, StringBuilder,char[]等)算法

2、歸類數組

 字符串涉及到的相關題型一般會是如下幾個方面:ui

  • 概念理解:字典序
  • 簡單操做:插入刪除字符、旋轉
  • 規則判斷(羅馬數字轉換 是不是合法的整數、浮點數)
  • 數字運算(大數加法,二進制加法)
  • 排序、交換
  • 字符計數:變位詞
  • 匹配(正則表達式、全串匹配、KMP、週期判斷)
  • 動態規劃(LCS、編輯距離、最長迴文子串)
  • 搜索(單詞變換、排列組合)

3、例題spa

一、交換:把一個只包含01的串排序,可交換任意兩個數的位置,最少須要多少次交換?

  思路:從兩頭往中間掃蕩,掃蕩過程當中在左邊遇到1就和右邊遇到的0交換位置,直接到左有下標相遇時結束。 具體代碼以下:code

 1 public static void main(String[] strs) {
 2         int count = 0;
 3         int[] arrays = new int[] {0, 0, 1, 1, 1, 0, 1, 0, 0, 1};
 4         int left = 0;
 5         int right = arrays.length - 1;
 6         while (true) {
 7             while (arrays[left] == 0) {
 8                 left++;
 9             }
10             while (arrays[right] == 1) {
11                 right--;
12             }
13             if (left >= right) {
14                 break;
15             } else {
16                 int temp = arrays[left];
17                 arrays[left] = arrays[right];
18                 arrays[right] = temp;
19                 count++;
20             }
21         }
22         Logger.println("交換次數:" + count);
23         for (int array : arrays) {
24             Logger.print(array + ", ");
25         }
26 }

清晰起見,交換次數和排序後的的字符串輸出以下:視頻

交換次數:3
0, 0, 0, 0, 0, 1, 1, 1, 1, 1,

二、字符串替換和複製:刪除一個字符串全部的a,而且複製全部的b(字符數組足夠大)

  思路:詳細思路見代碼註釋blog

 1 public static void main(String[] strs) {
 2         char[] input = new char[]{'a', 'b', 'c', 'd', 'a', 'f', 'a', 'b', 'c', 'd', 'b', 'b', 'a', 'b'};
 3         char[] chars = new char[50];
 4         for (int j = 0; j < input.length; j++) {
 5             chars[j] = input[j];
 6         }
 7         Logger.println("操做前:");
 8         for (char c:chars
 9                 ) {
10             Logger.print(c + ", ");
11         }
12         int n = 0;
13         int countB = 0;
14         // 一、刪除a,用n當作新下標,循環遍歷數組,凡是否是a的元素都放到新下標的位置,因爲新n增加慢,老下標i增加快,因此元素不會被覆蓋。
15         // 而且在刪除a時順便記錄b的數量,以便下一步複製b時能夠提早肯定數組最終的最大的下標。
16         for (int i = 0; chars[i] != '\u0000' && i < chars.length; i++) {
17             if (chars[i] != 'a') {
18                 chars[n++] = chars[i];
19             }
20             if (chars[i] == 'b') {
21                 countB++;
22             }
23         }
24 
25         // 二、複製b,因爲在第一步中就已經知道了字符串中b的個數,這裏就能肯定最終字符串的最大下標,從最打下表開始倒着複製原字符串,碰到b時複製便可。
26         int newMaxIndex = n + countB - 1;
27         for (int k = n - 1; k >= 0; k--) {
28             chars[newMaxIndex--] = chars[k];
29             if (chars[k] == 'b') {
30                 chars[newMaxIndex--] = chars[k];
31             }
32         }
33 
34         Logger.println("\n操做後:");
35         for (char c:chars
36                 ) {
37             Logger.print(c + ", ");
38         }
39 }

三、交換星號:一個字符串只包含 * 和數字,請把它的 * 都放在開頭。

  如:1 * 2 * 4 * 3 => * * * 1 2 4 3排序

  • 方案一:倒着操做,從最大下標開始向前遍歷,遇到非 * 號的元素則加入"新"下標中,遍歷完畢後,j即表明 * 號的個數,而後將0-j賦值爲 * 便可。(操做後,數字的相對位置不變) 代碼以下:
 1 public static void main(String[] strs) {
 2         char[] chars = new char[]{'1', '*', '4', '3', '*', '5', '*'};
 3         // 方案一(操做後,數字的相對位置不變)
 4         // 倒着操做:從最大下標開始向前遍歷,遇到非*號的元素則加入"新"下標中,遍歷完畢後,j即表明*號的個數,而後將0-j賦值爲*便可。
 5         int j = chars.length - 1;
 6         for (int i = j; i >= 0; i--) {
 7             if (chars[i] != '*') {
 8                 chars[j--] = chars[i];
 9             }
10         }
11         while (j >= 0) {
12             chars[j--] = '*';
13         }
14         for (char c:chars
15                 ) {
16             Logger.print(c + ", ");
17         }
18 }

輸出結果以下:

*, *, *, 1, 4, 3, 5,
  • 方案二(操做後,數組的相對位置會變)快排劃分,根據循環不變式(每一步循環以後條件都成立):如本題[0..i-1]是*,[i..j-1]是數字,[j...n-1]未探測,循環時,隨着i和j增長,維護此條件依然不變,代碼以下:
 1 public static void main(String[] strs) {
 2         char[] chars = new char[]{'1', '*', '4', '3', '*', '5', '*'};
 3         // 方案二(操做後,數組的相對位置會變)
 4         // 快排劃分,根據循環不變式(每一步循環以後條件都成立):如本題[0..i-1]是*,[i..j-1]是數字,[j...n-1]未探測,循環時,隨着i和j增長,維護此條件依然不變
 5         for (int i = 0, j = 0; j < chars.length; ++j) {
 6             if (chars[j] == '*') {
 7                 char temp = chars[i];
 8                 chars[i] = chars[j];
 9                 chars[j] = temp;
10                 i++;
11             }
12         }
13         for (char c:chars
14                 ) {
15             Logger.print(c + ", ");
16         }
17

輸出結果以下:

*, *, *, 3, 1, 5, 4,

四、單詞翻轉

  例如:I am a student =》 student a am I

  思路:

  一、先將整個字符串翻轉:如:I am a student =》 tneduts a ma I

  二、經過空格判斷出每一個單詞,而後對每一個單詞進行翻轉

  代碼以下:

 1 public static void main(String[] strs) {
 2         String input = "I am a student";
 3         char[] chars = input.toCharArray();
 4         int i = 0;
 5         int j = chars.length - 1;
 6         while (i < j) {
 7             swap(chars, i++, j--);
 8         }
 9         int front = 1;
10         int tail = 0;
11         while (front < chars.length) {
12             if (chars[front] == ' ') {
13                 int frontTemp = front - 1;
14                 while (tail < frontTemp) {
15                     swap(chars, tail++, frontTemp--);
16                 }
17                 tail = front + 1;
18             }
19             front++;
20         }
21         for (char c:chars
22                 ) {
23             Logger.print(c);
24         }
25 }
26 
27 public static void swap(char[] chars, int index1, int index2) {
28         char temp = chars[index1];
29         chars[index1] = chars[index2];
30         chars[index2] = temp;
31 }

輸出結果以下:

student a am I

五、子串變位詞:給定兩個串a和b,問b是否a的子串變位詞。

  例如:a=hello。b=lel,lle,ello都是true;b=elo是false

  思路:

    •   1、首先須要瞭解對兩個串是不是變位詞的判斷:
    1.   對兩個串按統一規則排序,排序後若相等則是變位詞。
    2.   對兩個串中出現的字母統計,兩串中相同的字母出現的次數一致則爲變位詞。
    •   2、而後從母串的第一個元素遍歷,每日後遍歷一個元素就把從當前元素開始到加上子串的長度的位置做爲一個區間和子串比較是不是變位詞。

最後一題綜合前幾個題用到的一些技巧,仍是比較有趣的,這裏就不貼出代碼了,也激發一下你們的動手能力,感興趣的童鞋不妨試着寫一寫。

以上問題若有不一樣思路歡迎交流。

相關文章
相關標籤/搜索