1. 程式人生 > 其它 >判斷字元陣列中是否所有的字元都只出現過一次 & 在有序但含有空的陣列中查詢字串

判斷字元陣列中是否所有的字元都只出現過一次 & 在有序但含有空的陣列中查詢字串

判斷字元陣列中是否所有的字元都只出現過一次

題目:判斷陣列中所有的數字是否只出現一次

《程式設計師程式碼面試指南》第81題 P261 難度:要求1:士★☆☆☆ 要求2:尉★★☆☆

要求1很簡單,時間複雜度O(N)遍歷一遍chas,用map記錄每種字元的出現情況即可。書中使用了長度固定的陣列,也可以使用雜湊表來實現。

public boolean isUnique1(char[] chas) {
    if (chas == null) {
        return true;
    }
    boolean[] map = new boolean[256];
    for (int i = 0; i < chas.length; i++) {
        if (map[chas[i]]) {
            return false;
        }
        map[chas[i]] = true;
    }
    return true;
}

要求2的整體思路是先將chas排序排序後相同的字元就放在一起。所以問題的關鍵是選擇什麼樣的排序演算法,使得額外空間複雜度O(1),並且時間複雜度儘量低

public boolean isUnique2(char[] chas) {
    if (chas == null) {
        return true;
    }
    heapSort(chas);
    for (int i = 1; i < chas.length; i++) {
        if (chas[i] == chas[i - 1]) {
            return false;
        }
    }
    return true;
}

public void heapSort(char[] chas) {
    for (int i = 0; i < chas.length; i++) {
        heapInsert(chas, i);
    }
    for (int i = chas.length - 1; i > 0; i--) {
        swap(chas, 0, i);
        heapify(chas, 0, i);
    }
}

public void heapInsert(char[] chas, int i) {
    int parent = 0;
    while (i != 0) {
        parent = (i - 1) / 2;
        if (chas[parent] < chas[i]) {
            swap(chas, parent, i);
            i = parent;
        } else {
            break;
        }
    }
}

public void heapify(char[] chas, int i, int size) {
    int left = i * 2 + 1;
    int right = i * 2 + 2;
    int largest = i;
    while (left < size) {
        if (chas[left] > chas[i]) {
            largest = left;
        }
        if (right < size && chas[right] > chas[largest]) {
            largest = right;
        }
        if (largest != i) {
            swap(chas, largest, i);
        } else {
            break;
        }
        i = largest;
        left = i * 2 + 1;
        right = i * 2 + 2;
    }
}

public void swap(char[] chas, int index1, int index2) {
    char tmp = chas[index1];
    chas[index1] = chas[index2];
    chas[index2] = tmp;
}

在有序但含有空的陣列中查詢字串

題目:在有序但是含有空的陣列中查詢字串

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

【解答】
本題的解法儘可能多地使用了二分查詢,具體過程如下:

  1. 假設在strs[left..right]上進行查詢的過程,全域性整型變數res表示字串str在strs中最左的位置。初始時,left=0right=strs.length-1, res=-1
  2. mid=(left+right)/2,則strs[mid]strs[left..right]中間位置的字串
  3. 如果字串strs[mid]與str一樣,說明找到了str,令res=mid。但要找的是最左的位置
    還要在左半區尋找看有沒有更左的str出現,所以令right=mid-1,然後重複步驟2。
  4. 如果字串strs[mid]與str不一樣,並且strs[mid]!=null,此時可以比較strs[mid]和str,如果strs[mid]的字典順序比str小,說明整個左半區不會出現str,需要在右半區尋找,所以令left=mid+1,然後重複步驟2。
  5. 如果字串strs[mid]與str不一樣,並且strs[mid]==null,此時從mid開始從右到左遍歷左半區(即strs[left..mid])。如果整個左半區都為null,那麼繼續用二分的方式在右半區上查詢(即令left=mid+1),然後重複步驟2。如果整個左半區不都為null,假設從右到左遍歷strs[left..mid]時,發現第一個不為null的位置是i,那麼把str和strs[i]進行比較。如果strs[i]字典順序小於str,同樣說明整個左半區沒有str,令left=mid+1,然後重複步驟2。如果strs[i]字典順序等於str,說明找到str,令res=mid,但要找的是最左的位置,還要在strs[left..i-1]上尋找,看有沒有更左的str出現,所以令right=i-1,然後重複步驟2。如果strs[i]字典順序大於str,說明strs[i..right]上都沒有str,需要在strs[left..i-1]上查詢,所以令right=i-1,然後重複步驟2。

具體過程請參看如下程式碼中的getlndex方法。

public int getIndex(String[] strs, String str) {
    if (strs == null || strs.length == 0 || str == null) {
        return -1;
    }
    int res = -1;
    int left = 0;
    int right = strs.length - 1;
    int mid = 0;
    int i = 0;
    while (left <= right) {
        mid = (left + right) / 2;
        if (strs[mid] != null && strs[mid].equals(str)) {
            res = mid;
            right = mid - 1;
        } else if (strs[mid] != null) {
            if (strs[mid].compareTo(str) < 0) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        } else {
            i = mid;
            while (strs[i] == null && --i >= left)
                ;
            if (i < left || strs[i].compareTo(str) < 0) {
                left = mid + 1;
            } else {
                res = strs[i].equals(str) ? i : res;
                right = i - 1;
            }
        }
    }
    return res;
}