題目:
給定一個無序整型數組arr,找到數組中未出現的最小正整數。要求時間復雜度為O(N)空間復雜度為O(1)。
例如:
arr=[-1,2,3,4]。返回1。
arr=[1,2,3,4]。返回5。
分析:
這道題要理解最小正整數的意思,最小的正整數就是1,所以考察的方法就是在數組中找1,然后找2,依次找下去...。直到第一個沒有找到的數,這個數就是未出現的最小的正整數。但是這樣的時間復雜度很大,達到了O(n2)。
空間復雜度算法
再來看一個時間復雜度為O(N)的算法,新開辟一個數組,元素初始化為0。把原來的數組中的數字放到新的數組中,放置的位置要合適,也就是要在1234...這樣合適的位置。如果這個數小於1或者大於數組的長度,就把這個數忽略掉,不放到新的數組中。完成之后,從頭到尾遍歷新的數組,找到第一個值不等於下標+1的數,下標+1就是那個未出現的最小正整數。
舉個列子:原數組
新數組
然后從新數組的開始掃面整個數組,發現下標0的元素值不等於下標+1,所以下標+1也就是0+1就是未出現的最小的正整數。
原數組
新數組
可以看出第一個下標+1不等於對應的值的就是下標2,所以未出現的最小整數就是3。
這里注意,原數組中的第一個2放置到了合適的位置后,后面緊接着又來了一個2,直接把它扔掉就可以了。
縮減空間復雜度
上面的算法是把原數組copy到了一個新的數組,如果直接在原數組上修改位置呢?就減少了空間復雜度。但是這樣的弊端就是破壞了原來的數組。
方法:定義兩個變量
l表示已經[1~l]的正整數已經找到了合適的位置,l的初值為0;
上面的算法中,如果一個數字太大了,就會被扔掉。這里用r表示這個邊界,如果大於這個r的數就會被扔掉。r的初值為N表示[1-r]的元素都不會被扔掉, 大於r的就會被扔掉。但是這個r的值是變化的,如果[l+1~r]中有一個元素不合法,那么這個r就是減少1,因為最多已經不能放下[1~r]了,最多只能放下[1~r-1]了。
所以代碼實現:
int missMinNum(int arr[], int n) { int l = 0; int r = n; while(l < r) { if(arr[l] == l + 1)//在理想的位置 { l++; } else if(arr[l] > r || arr[l] <= l || arr[arr[l] - 1] == arr[l])//不合法的數據 { arr[l] = arr[--r]; } else//合法但是沒有在理想的位置上 { swap(arr, l, arr[l] - 1); } }//while return l + 1; }//missMinMun()