1. 程式人生 > 其它 >找到字串的最長無重複字元子串 & 字串的統計字串

找到字串的最長無重複字元子串 & 字串的統計字串

找到字串的最長無重複字元子串

題目:找到字串的最長無重複字元子串

《程式設計師程式碼面試指南》第94題 P300 難度:尉★★☆☆

首先是幾個變數的介紹:雜湊表mapkey表示某個字元value這個字元最近一次出現的位置整型變數pre,如果當前遍歷到字元str[i],pre表示在必須以str[i-1]字元結尾的情況下最長無重複字元子串開始位置的前一個位置初始pre=-1整型變數len,記錄以每一個字元結尾的情況下,最長無重複字元子串長度的最大值,初始時,len=0。從左到右依次遍歷str,假設現在遍歷到str[i],接下來求在必須以str結尾的情況下,最長無重複字元子串的長度。

map(str[i])

的值表示之前的遍歷中最近一次出現str字元的位置,假設在a位置。想要求以str[i]結尾的最長無重複子串a位置必然不能包含進來,因為str[a]等於str[i]

根據pre的定義,pre+1表示在必須以str[i-1]字元結尾的情況下最長無重複字元子串的開始位置。也就是說,以str[i-1]結尾的最長無重複子串是向左擴到pre位置停止的

如果pre位置在a位置的左邊,因為str[a]不能包含進來,而str[a+1..i-1]上都是不重複的,所以以str[i]結尾的最長無重複字元子串就是str[a+1..i]。如果pre位置在a位置的右邊以str[i-1]結尾的最長無重複子串是向左擴到pre位置停止

的。所以以str[i]結尾的最長無重複子串向左擴到pre位置也必然會停止,而且str[pre+1..i-1]這一段上肯定不含有str[i],所以以str[i]結尾的最長無重複字元子串就是str[pre+1..i]

計算完長度之後,pre位置和a位置哪一個在右邊,就作為新的pre值。然後計算下一個位置的字元,整個過程中求得所有長度的最大值用len記錄下來返回即可。
具體請參看如下程式碼中的maxUnique方法。

public int maxUnique(String str) {
    if (str == null || str.equals("")) {
        return 0;
    }
    char[] chas = str.toCharArray();
    int[] map = new int[256];
    for (int i = 0; i < 256; i++) {
        map[i] = -1;
    }
    int len = 0;
    int pre = -1;
    int cur = 0;
    for (int i = 0; i != chas.length; i++) {
        pre = Math.max(pre, map[chas[i]]);
        cur = i - pre;
        len = Math.max(len, cur);
        map[chas[i]] = i;
    }
    return len;
}

字串的統計字串

題目:字串的統計字串

《程式設計師程式碼面試指南》第80題 P258 難度:士★☆☆☆

這題沒什麼含金量,逐個遍歷str[i]==str[i-1]num++否則拼接字串。注意在遍歷完成後還需要再拼接上最後一種字元的次數。不多說,直接看程式碼:

public String getCountString(String str) {
    if (str == null || str.equals("")) {
        return "";
    }
    char[] chs = str.toCharArray();
    String res = String.valueOf(chs[0]);
    int num = 1;
    for (int i = 1; i < chs.length; i++) {
        if (chs[i] != chs[i - 1]) {
            res = concat(res, String.valueOf(num), String.valueOf(chs[i]));
            num = 1;
        } else {
            num++;
        }
    }
    return concat(res, String.valueOf(num), "");
}

public String concat(String s1, String s2, String s3) {
    return s1 + "_" + s2 + (s3.equals("") ? s3 : "_" + s3);
}

(個人覺得用StringBuilder效率更高一點)

進階問題

public char getCharAt(String cstr, int index) {
    if (cstr == null || cstr.equals("")) {
        return 0;
    }
    char[] chs = cstr.toCharArray();
    boolean stage = true;
    char cur = 0;
    int num = 0;
    int sum = 0;
    for (int i = 0; i != chs.length; i++) {
        if (chs[i] == '_') {
            stage = !stage;
        } else if (stage) {
            sum += num;
            if (sum > index) {
                return cur;
            }
            num = 0;
            cur = chs[i];
        } else {
            num = num * 10 + chs[i] - '0';
        }
    }
    return sum + num > index ? cur : 0;
}

書上的方法很繁瑣,我的方法是通過split("_")分割字串,分割後索引為奇數1、3、5…的字串通過Integer.parseInt()轉化後就是各個字元的次數,直接去統計就行,不需要像書上這樣還挨個num=num*10+chs[i]去計算次數。。