一、概述
輸入一個數組,其元素均爲整數,輸出最小的未在數組中出現的整數。要求時間複雜度O(n),空間複雜度O(1)。
一看時間複雜度O(n),沒法排序做了,倒也是,這能排序做就不是hard題了。第一反應哈希,開了65536的數組,結果一個測試樣例是int的最大值,直接就把哈希爆了。想不出什麼好方法來做。只好去討論區看。這羣人可是真的牛逼。
二、分析
不得不說很久沒做題之後敏感性都差了很多,一看時間複雜度n空間複雜度1第一反映應該就是在原數組上動刀,遍歷數遍。
這題和之前PAT上的一道題差不多,關鍵在於排序。
其具體思路如下:
對於一個輸入數組,例如“35128697”,最終排出來的應該是“12395678”,然後發現本來是4的地方應該是9,就找出了缺失的4。
那麼現在的問題就是。找這個4要排序,但是最牛逼的算法也只能是nlogn,不符合要求,怎麼辦?
那我們來看一下,普通的排序算法,時間話費爲nlogn是爲什麼:是因爲每個元素都要花費logn的時間去找到它自己的位置。但是我們需要所有元素的位置麼?比如輸入n個元素,我們最多需要知道最大元素爲n的位置,n+1都不需要,就能夠找出想要的答案。那麼問題就轉換成部分元素排序。怎麼排?交換位置。如下圖:
首先看位置1,位置1處爲3,實際上是在數組的第0號元素,但爲了表述方便,我們稱之爲位置1,由於位置1處不爲1,因此將3與位置3的元素互換,從而位置1爲1,位置3爲3;
然後往下移動,位置2處爲5,從而位置2與位置5處的元素互換,位置2處元素變爲8;
然後位置2與位置8互換,位置2處元素變爲7;
然後位置2與位置7互換,位置2處變爲9;
位置2沒法與位置9互換,因爲沒有位置9,繼續往下;
位置3處爲3,繼續往下;
位置4處爲2,位置4與位置2互換,位置4變爲9,往下;
位置5、6、7、8均正確,不換了。
然後從頭遍歷,發現位置4處元素不對,返回4。
觀察整個循環,我們可以得出,swap最多進行n次,因爲swap每進行一次,就有一個元素回到正確位置,而我們最多需要n個正確位置的元素,因此時間複雜度爲O(n)。
代碼如下:
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
for(int i=0;i<nums.size();i++)
{
while(nums[i]>0&&nums[i]<=nums.size()&&nums[nums[i]-1]!=nums[i])
swap(nums[i],nums[nums[i]-1]);
}
for(int i=0;i<nums.size();i++)
if(nums[i]!=i+1)
return i+1;
return nums.size()+1;
}
};
三、總結
你問我學到了啥?
我只能說我學到了在只求前n個元素有序時候的O(n)寫法,這種把問題轉化的能力太難學了,是天資。
如何能夠從“找第一個未出現的元素”轉換到“令前n個元素有序”,這個思想太難了。