問題描述
Given an unsorted integer array, find the first missing positive integer.
For example,
Given [1,2,0] return 3,
and [3,4,-1,1] return 2.
Your algorithm should run in O(n) time and uses constant space.
問題分析
這是一道hard題,自己沒有思路TAT,在網上搜了解答
分析題意
- 要找的是第一個不存在的正數,那么對于長度為n的輸入,非正數和大于n的數都是沒有用的。
- 要求用常數空間解決,因此不能另開數組,而應該在原數組上進行操作,這時應留意到,數組的下標是0到n-1,與我們考慮的正數范圍1到n是一一對應的。
- 我們利用下標作為標記,將數組中每個在1到n之間的元素item,放在nums[item-1]的位置,然后第二次遍歷數組,找到第一個nums[i] != i+1的位置,則i+1就是我們要找的first missing postive integer。
做法
- 第一次遍歷數組,若nums[i]的值在1,n之間且nums[nums[i]-1] != nums[i],則交換nums[nums[i]-1]和nums[i]。nums[nums[i]-1] != nums[i]包含兩層含義,1)如果nums[i] != i+1,則nums[i]-1 != i,那么nums[i]需要被調換到它應該去的位置;如果nums[nums[i]-1] == nums[i]說明待交換的兩個數字相等,則不需交換,否則會死循環。需要注意的是,如果被換到nums[i]位置的數字依然符合交換條件,那么需要繼續進行交換,也就是說這里不是一個if判斷,而是一個while循環。
- 第二次遍歷數組,找到第一個nums[i] != i+1的位置,返回i+1。
復雜度分析
雖然這個思想還是蠻好理解,但是在一個for循環里又出現了一個while循環,它的復雜度能是O(n)嗎?其實是醬紫,算法復雜度應該看的是基本操作的次數,在這個問題里,基本操作指的是交換操作,而每次交換操作,都至少有一個數字去了它應該去的地方,那么一個n長度的數組,最多只需要n次交換操作,所以它的復雜度是O(n)的~
AC代碼
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n = nums.size();
int i;
for (i = 0; i < n; i++){
while(nums[i] > 0 && nums[i] < n && nums[nums[i]-1] != nums[i]){
int tmp = nums[nums[i]-1];
nums[nums[i]-1] = nums[i];
nums[i] = tmp;
}
}
for (i = 0; i < n; i++){
if (nums[i] != i+1)
break;
}
return i+1;
}
};
Runtime: 3 ms, which beats 70.66% of cpp submissions.