1. 題目
2. 題意
題目很好理解,需要注意的是範圍是[1,n]
,跟數組下標範圍[0,n-1]
剛好相差了1。
3. 方法一
3.1 思路
由於數字範圍剛好大於數組下標範圍1,最簡單的思路,構造一個大小爲n的boolean類型的數組boolean[] isContain
,isContain[i]
代表數組中是否包含了數字i+1
。從頭到尾遍歷整個數組,對每個值val,將isContian[val-1]
置爲true
,即標記出現的值。再從頭到尾遍歷isContain
數組,找出哪些下標爲false,推斷出哪些數字沒有出現在[1,n]的範圍中。
該方法的時間複雜度爲O(n)
,需要遍歷2次數組,空間複雜度爲O(n)
,爲boolean數組的開銷。
3.2 代碼
public List<Integer> findDisappearedNumbers(int[] nums) {
boolean[] isContain = new boolean[nums.length];
for (int num : nums
) {
isContain[num - 1] = true;
}
List<Integer> response = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
if (!isContain[i]) {
response.add(i + 1);
}
}
return response;
}
3.3 運行結果
4. 方法二
4.1 思路
對於方法一,運行速度快,但沒有實現空間複雜度爲O(1)
,接下來考慮保持時間複雜度不變O(n)
,降低空間複雜度。
考慮方法一,我們的空間開銷是在boolean數組上,它的作用在於記錄哪些值已經出現過了,因此我們考慮能否使原數組也有記錄值是否出現的能力。聯想到一個簡單的方法,正負值
,我們可以當某個值出現時,我們修改原數組的值的正負,來標記該值是否已經出現。
例如對於[3,3,2]
數組,我們從頭遍歷,第一個數字的絕對值爲3,將3-1=2
下標對應的值修改爲負,原數組變爲[3,3,-2]
,對於第二個數,同樣絕對值爲3,將3-1=2
下標對應的值修改爲負,原數組爲[3,3,-2]
,遍歷第三個數,絕對值爲2,將2-1=1
下標對應的值改爲負,原數組爲[3,-3,-2]
,從頭遍歷數組,發現只有下標爲0的數爲正,即該數組中不包含0+1=1
,不包含1
這個數。
4.2 代碼
public List<Integer> findDisappearedNumbers1(int[] nums) {
for (int i = 0; i < nums.length; i++) {
int temp = Math.abs(nums[i]) - 1;
if (nums[temp] > 0) {
nums[temp] = -nums[temp];
}
}
List<Integer> response = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
if (nums[i] > 0) {
response.add(i + 1);
}
}
return response;
}