448. Find All Numbers Disappeared in an Array

Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once.
Find all the elements of [1, n] inclusive that do not appear in this array.
Could you do it without extra space and in O(n) runtime? You may assume the returned list does not count as extra space.

Example:
Input:
[4,3,2,7,8,2,3,1]
Output:
[5,6]

題意與思路

這道題是說,給我們一個數組,數組長度爲n,數組裏面的每一個元素都是在

[1,n]的區間裏的數字,裏面有一些數字會出現多次,也就意味着有一些數字會沒有,請我們找出那些缺失的數字。

一開始是想排序?先排序,然後在從頭到尾遍歷,但是有一些數字出現兩次,不太好寫判斷條件。然後注意到所有的數字都一定是在1-n範圍的,那麼,可以使用一個新的數組來標記這些數,哪些存在哪些不存在。

比如說,示例中,數組[4,3,2,7,8,2,3,1],第一個元素是4,那麼我們就用新數組arr[4-1]標記這個元素存在。也就是對於原數組中的元素a,在新的數組arr中,標記arr[a-1]=1來表示它存在。最後再遍歷一下標記數組,那些空缺的數字,也就是我們需要的答案。

代碼如下:

public List<Integer> findDisappearedNumbers(int[] nums) {
    int[] data = new int[nums.length];

    for (int i : nums) {
        data[i - 1] = 1;
    }

    List<Integer> ret = new ArrayList<>();

    for (int i = 0; i < data.length; i++) {
        if (data[i] == 0) {
            ret.add(i + 1);
        }
    }

    return ret;
}

時間複雜度可以一眼看出就是O(2n)

當然,還可以改進一下這個算法,不用創建新的數組來做標記,如果只使用原來的數組,如何做標記呢?

如果使用原來的數組,需要一個很重要的問題:如果第一個數爲3,就意味着要去標記data[3 - 1]的位置,但是data[3 - 1]裏面的數被破壞了,後面再遍歷到它的時候怎麼辦呢?

也就是,如何同時標記一個數的位置,又不能破壞原有的數。

廣大的勞動人民總是有無窮的智慧的:我們可以將要標記的數轉爲負數,如果是負數,就說明是被標記了(這個位置代表的數存在),同時也可以將負數轉換回原來的數。

看看代碼是怎麼實現的呢:D

public List<Integer> findDisappearedNumbers(int[] nums) {

    for (int i = 0; i < nums.length; i++) {
        int index = Math.abs(nums[i]) - 1; // 先得到index
        if (nums[index] > 0) { // 如果那個位置上的數 > 0
            nums[index] = -nums[index]; // 就標記它
        }
    }

    List<Integer> ret = new ArrayList<>();

    for (int i = 0; i < nums.length; i++) {
        if (nums[i] >= 0) { // 只要是大於0的數,就說明是沒有的數
            ret.add(i + 1);
        }
    }

    return ret;
}

這樣就通過原數組解決了問題~


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章