基礎算法題-數組相關

1. 數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。

如果直接排序,後進行選擇,則時間複雜度最優爲O(nlogn),這裏有兩種思路。
第一種,利用快速排序的思想,找到第n/2位置的數。然後掃描數組,確保這個數的確超過數組長度的一半。
第二種,設置兩個標記,一個記錄值,一個記錄次數,當後一個與前一個不同時,記錄數減一,當記錄數減少到0時候,需要更改值的標記。
時間複雜度都爲O(n),兩種方法代碼分別如下:

int MoreThanHalfNum_Solution1(int[] array) {
    int length = array.length;
    //基於快排思想
    int loc = partition(array, 0, length - 1);
    while (loc != length / 2) {
        if (loc > length / 2) {
            loc = partition(array, 0, loc - 1);
        } else {
            loc = partition(array, loc + 1, length - 1);
        }
    }
    int value = array[loc];
    int count = 0;
    for (int i = 0; i < length; i++) {
        if (array[i] == value)
            count++;
    }
    if (count > length / 2)
        return value;
    else
        return 0;
}
int partition(int[] array, int low, int high) {
    if (low >= high) return low;
    int temp = array[low];
    while (low < high) {
        while (low < high && array[high] >= temp) high--;
        array[low] = array[high];
        while (low < high && array[low] <= temp) low++;
        array[high] = array[low];
    }
    array[low] = temp;
    return low;
}

設置兩個標記來處理,最後還得驗證是否超過一半:

int MoreThanHalfNum_Solution2(int[] array) {
    int length = array.length;
    int key = array[0], times = 1;
    for (int i = 1; i < length; i++) {
        if (times == 0) {
            key = array[i];
            times++;
        } else {
            if (array[i] != key)
                times--;
            else
                times++;
        }
    }
    int count = 0;
    for (int i = 0; i < length; i++) {
        if (array[i] == key)
            count++;
    }
    if (count > length / 2)
        return key;
    else
        return 0;
}

2.把只包含素因子2、3和5的數稱作醜數(Ugly Number), 求按從小到大的順序的第N個醜數。

不考慮的效率的話,直接迭代去判斷每個數是否是醜數,直到得到第N個醜數。效率比較低下。
由於後面的醜數可以通過前面的醜數乘上因子獲得,現在設置三個標記來標記依次產生的最小丑數,這個醜數則爲下一個醜數,則這個醜數的標記前進一步,若多個標記產生的醜數都是最小的,則多個標記共同前進一步,直到獲得第N個醜數。
代碼如下:

int GetUglyNumber_Solution(int index) {
    if (index < 2) return index;
    int[] uglyArray = new int[index];
    uglyArray[0] = 1;
    int index_2 = 0, index_3 = 0, index_5 = 0;
    int i = 0, max = 0;
    while (i < index - 1) {
        int max_2 = uglyArray[index_2] * 2;
        int max_3 = uglyArray[index_3] * 3;
        int max_5 = uglyArray[index_5] * 5;
        max = max_2 <= max_3 ? max_2 : max_3;
        max = max <= max_5 ? max : max_5;
        uglyArray[++i] = max;
        if (max == max_2)
            index_2++;
        if (max == max_3)
            index_3++;
        if (max == max_5)
            index_5++;
    }
    return uglyArray[i];
}

3.輸出所有和爲S的連續正數序列。序列內按照從小至大的順序,序列間按照開始數字從小到大的順序。

若限制爲兩個數的和,可以首尾各設一個指針,計算兩個指針指向值的和,大於S,則尾指針向前移動,再迭代計算。若小於S,則首指針向後移動,計算和。一直到滿足要求爲止。
這個題目要求求出連續數字的和,不限元素個數。這裏繼續設置兩個指針,一個放在第一位,一個放在第二位,求累積和,小於S則後面指針向後移動,再累計比較。若大於S則前一個指針向後移動,再累計求和比較,直到滿足要求爲止,可以求出多個結果。

ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) {
    ArrayList<ArrayList<Integer>> array = new ArrayList<ArrayList<Integer>>();
    ArrayList<Integer> one = new ArrayList<Integer>();
    int len = sum / 2 + 1;
    int start = 1, end = 2;
    int total = start + end;
    while (start != len) {
        if (total == sum) {
            for (int i = start; i <= end; i++) {
                one.add(i);
            }
            array.add((ArrayList<Integer>)one.clone());
            one.clear();
            if (end == len)
                break;
            else {
                total += ++end;
            }
        }
        if (total < sum) {
            total += ++end;
        }
        if (total > sum) {
            total -= start++;
        }
    }
    return array;
}

4.在數組中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數

如果直接暴力來計算,可以想象成直接插入排序算法,當數組通過插入排序算法處理完畢時候,數字移動的個數就是逆序對的總數。時間複雜度沒有下面的算法優。
利用歸併算法。將數組分爲兩部分,將這兩部分再遞歸處理。當兩個數組合併成有序的序列時候,進行逆序統計,生成新排序數組是從數組尾部開始生成,也就是從兩個有序的數組中,先找最大的數。設置兩個指針,一個指向前一個有序數組的尾部,一個指向後一個有序數組的尾部。進行比較,當前一個大比後一個大的時候,逆序數增加後一個有序數組的頭部到指針處的元素個數(若後一指針索引爲j,頭部的索引爲low,則增加j-low+1個),前一個指針前移。當後一個指針大,則逆序數不變。
最後的總逆序數爲前一半數組的逆序數加上後一半數組的逆序數,再加上兩個數組合並過程中統計的逆序數,即爲總逆序數。

int InversePairs(int [] array) {
    if(array==null||array.length==0)
        return 0;
    int length = array.length;
    return merge(array,0,length-1);
}
int merge(int[] array, int low, int high) {
    int count1 = 0, count2 = 0;
    if (low < high) {
        int mid = (low + high) / 2;
        count1 = merge(array, low, mid);
        count2 = merge(array, mid + 1, high);
        count1 = count1 + count2 + mergeAndCount(array, low, mid, high);
    }
    return count1;
}
int mergeAndCount(int[] array, int low, int mid, int high) {
    int[] b = new int[array.length];
    for (int i = 0; i < b.length; i++) {
        b[i] = array[i];
    }
    int count = 0;
    int i, j, k;
    for (i = mid, j = high, k = high; i >= low && j > mid; ) {
        if (b[i] > b[j]) {
            count += j - mid;
            array[k--] = b[i--];
        } else {
            array[k--] = b[j--];
        }
    }
    while (i >= low) array[k--] = b[i--];
    while (j > mid) array[k--] = b[j--];
    return count;
}

>5. 設計一個函數,用來判斷在一個矩陣中是否存在一條包含某字符串所有字符的路徑。路徑可以從矩陣中的任意一個格子開始,每一步可以在矩陣中向左,向右,向上,向下移動一個格子。
回溯法,設置一個標記,標記是否可以訪問。匹配成功一個字符後,則向四個方向繼續匹配,失敗則清除不可訪問標記。
代碼如下:

boolean hasPath(char[] matrix, int rows, int cols, char[] str) {
    int[] flag = new int[matrix.length];
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < cols; j++) {
            if (isHas(matrix, rows, cols, i, j, str, 0, flag))
                return true;
        }
    return false;
}
boolean isHas(char[] a, int rows, int cols, int i, int j, char[] str, int k, int[] flag) {
    int index = i * cols + j;
    if (i < 0 || j < 0 || i >= rows || j >= cols || flag[index] == 1 || a[index] != str[k])
        return false;
    if (k == str.length - 1)
        return true;
    flag[index] = 1;
    if (isHas(a, rows, cols, i - 1, j, str, k + 1, flag) || isHas(a, rows, cols, i + 1, j, str, k + 1, flag) ||
            isHas(a, rows, cols, i, j - 1, str, k + 1, flag) || isHas(a, rows, cols, i, j + 1, str, k + 1, flag))
        return true;
    flag[index] = 0;//失敗則去除標記
    return false;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章