個人面試準備過程---字符串相關(更新中)

字符串簡介

String 內置類型,不可理性,要更改的話考慮轉StringBuffer,StringBuilder,char[]之類java

對java來講,一個char的範圍 [0,65535],16位面試

面試題整體分析

  • 和數組相關,內容普遍正則表達式

    • 概念理解:字典序,哪一個排在字典前面,哪一個字典序就小數組

    • 簡單操做: 插入、刪除字符,旋轉ui

    • 規則判斷 羅馬數字轉換,是不是合法的整數、浮點數spa

    • 數字運算(套數加法、二進制加法)code

    • 排序、交換(partition過程)排序

    • 字符計數(hash): 變位詞遞歸

    • 匹配(正則表達式、全串匹配、KMP、週期判斷)ci

    • 動態規劃(LCS、編輯距離、最長迴文子串)

    • 搜索(單詞變換、排列組合)

例1 把一個0-1串進行排序,能夠交換任意兩個位置,問最少交換的次數

思路:快排partition 最左邊0和最右邊的1均可以無論

public int exchangeTimes(String s){
        int answer = 0;
        for(int i = 0, j = s.length() - 1; i < j; i++, j--){
            for(; i < j && s.charAt(i) == '0'; i++);
            for(; i < j && s.charAt(j) == '1'; j--);
            if(i < j) answer++;
        }
        return answer;
    }

例2 刪除一個字符串全部的a,而且複製全部的b.注:字符數組足夠大

public void solve(char[] chars){
        //先刪除a,能夠利用原來字符串的空間,過程相似插入排序
        int n = 0;//刪除a後的字符數組長度
        int bCount = 0;
        for(int i = 0; s[i] != '\0'; i++){
            if(chars[i] == 'a'){
                chars[n++] = chars[i];
            }
            if(chars[i] == 'b'){
                bCount++;
            }
        }
        //從後往前複製
        //步驟1. 遍歷計算新串長度,b出現的次數2. 從後往前遍歷 3.舊串複製,若是遇到b,複製兩遍
        int newLength = n + bCount;
        chars[newLength] = '\0';
      for(int i = n, j = newLength - 1; i >= 0; i--){
            chars[j--] = chars[i];
            if(chars[i] == 'b'){
                chars[j--] = 'b'; 
        }
    }

思考題:如何把字符串的空格變成"%20"

public void replaceSpace(char[] chars){
        int length = 0;
        int spaceCount = 0;
        for(int i = 0; chars[i] != '\0'; i++){
            length++;
            if(chars[i] == ' '){
                spaceCount++;
            }
        }

        int newLength = length + 2 * spaceCount;
        chars[newLength] = '\0';
        for(int i = newLength - 1, j = length; j >= 0; j--){
            if(chars[j] == ' '){
                char[i] = '0';
                char[--i] = '2';
                char[--i] = '%'; 
            }else{
                char[i--] = char[j];
            }
        }
    }

例3 一個字符串只包含*和數字,請把它的*號都放開頭。

方法1 快排partition,由於過程不穩定,因此數字相對順序會變化

public void sortStar(char[] chars){
        for(int i = 0 , j = 0; j < a.length; j++){
            if(chars[i] == '*'){
                swap(a[i++], a[j])
            }
        }
    }

    private void swap(char[] chars, int i, int j){
        char temp = chars[i];
        chars[i] = chars[j];
        chars[j] = temp;
    }

方法2 倒着處理

public void sortStar(char[] chars){
        int length = chars.length;
        int i = length - 1;
        for(int j = length - 1; j >= 0; j--){
            if(chars[j] != '*'){
                chars[i--] = chars[j];
            }
        }
        while(i >= 0){
            chars[i--] = '*';
        }
    }

注意:以上兩種解法的異同,方法1,用到交換和快排partition思想,可是沒法保證數字的順序;方法2,使用倒着向前處理的思想,若是必須用交換,只能採用方法1

例4 單詞翻轉

翻轉句子中所有的單詞,單詞內容不變,例如I'm a student. 變爲student. a I'm
思路:in-place翻轉 字符串第i位到第j位
while(i < j) swap(s[i++], s[j--]);
1. 翻轉整個句子:.tneduts a m'I
2. 每一個單詞單獨翻轉: students. a I'm

這段代碼寫得很是醜陋
public void revertStr(char[] chars){
    int length = chars.length;
    //翻轉整個句子
    revertInPlace(chars, 0, length - 1);
    //翻轉每一個單詞
    String str = new String(chars);
    String[] strs = str.split(" ");
    int wordCounts = strs.length;
    int[] eachLength = new int[wordCounts];
    int i = 0;
    for(String s : strs){
        eachLength[i++] = s.length();
    }
    int start = 0;
    for(int j = 0; j < wordCounts; j++){
        revertInPlace(chars, start, start + eachLength[j] - 1);
        start += eachLength[j] + 1;
    }
}
private void revertInPlace(char[] chars, int i, int j){
    while(i < j){
        swap(chars, i++, j--);
    }
}
private void swap(char[] chars, int i, int j){
    char temp = chars[i];
    chars[i] = chars[j];
    chars[j] = temp;
}

思考題:字符串循環移位

abcd 移動1次爲bcda,移動兩次爲cdab,移動三次爲dabc
結論:長度爲n,移動m次,至關於移動m%n次
    - 前m%n位翻轉,後n-m%n位翻轉
    - 整體再翻轉一次
public void circularMove(char[] chars, int m){
    int n = chars.length;
    revertInPlace(chars, 0, m % n - 1);
    revertInPlace(chars, m % n, n - 1);
    revertInPlace(chars, 0, n - 1);
}
private void revertInPlace(char[] chars, int i, int j){
    while(i < j){
        swap(chars, i++, j--);
    }
}
private void swap(char[] chars, int i, int j){
    char temp = chars[i];
    chars[i] = chars[j];
    chars[j] = temp;
}

總結:

  • in-place(原地)理解

    • 自己爲O(1)空間

    • 遞歸,堆棧空間能夠不考慮

  • 原地相關的問題

    • 字符串循環左移、右移

    • 快排partition相關

  • 滑動窗口

    • 能達到O(n)的時間複雜度

    • O(1)的空間複雜度

  • 規則相關---細緻

  • 匹配(暴力):KMP比較少見

  • Manacher----要求比較高的筆試

相關文章
相關標籤/搜索