第一個缺失數字
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.
思路:
桶排的思想
從頭到尾遍歷數組,在位置 i,希望放置的元素是 i+1, 如果不是,
就把 A[ i ] 和 A[ A[i] -1 ] 的元素,這樣就保證了 A[i]-1位置的元素是 A[i],
不斷重復上面這個過程,直到 A[ i ] == i+1 或者 A[i] 沒有辦法再交換,
A[i] 沒有辦法再交換的情況有:
A[i] <= 0: A[i]-1 是無效下標;
A[i] > n: A[i]-1 是無效下標;
A[i] == A[ A[i]-1]: 交換沒有意義。
這樣過後,有效的元素 i 一定放在了 A[i-1] 處,第一個 A[i] != i+1 的元素就是第一個缺少的正數了。
因為用的是桶排的思想,所以復雜度是 O(n).
public class Solution { public int firstMissingPositive(int[] A) { int n = A.length; for(int i=0; i<n; i++){ //此處看上去是兩層循環,但是在尋找A[i] == i+1 的過程中, //不斷將A[i]放在A[A[i]-1]處,循環到A[i]-1的時候就不用再處理,所以整體是O(n) while(A[i] != i+1){ if(A[i]<=0 || A[i]>n || A[i]==A[A[i]-1]) break; else{ //把A[i]放在A[i]-1處 int temp = A[i]; A[i] = A[temp-1]; A[temp-1] = temp; } } } for(int i=0; i<n; i++){ if(A[i] != i+1) return i+1; } return n+1; } }
FirstMissingPositive問題描述:給一個沒有排序的數組,找到第一個缺失的正數,例如nums={1,2,0}return3,nums={3,4,-1,1}return2
算法分析:既然是找正數,那麽肯定是從1開始的,那麽我們把1放在nums[0],以此類推,我們把數組中每個元素都放在它應該在的位置。那麽找到下標和數字不相符的元素,下標+1即為缺失的正數。
public static int firstMissingPositive(int[] nums) { int i = 0; //將nums中每一個元素都放在它所代表的數字的位置上,例如nums[1]=4,那麽nums[1]就應該放在第四個位置上,也就是nums[1]=nums[nums[1]-1] //排除負數 while(i < nums.length) { if(nums[i] <= 0 || nums[i] > nums.length || nums[i] == i + 1 || nums[i] == nums[nums[i]-1]) { i++; } else { int temp = nums[i]; nums[i] = nums[temp - 1]; nums[temp - 1] = temp; } } int j = 0; for(j = 0; j < nums.length; j ++) { if(nums[j] != j + 1) { return j+1; } } return j+1; }
《第一個缺失的正數》 http://www.cnblogs.com/masterlibin/p/5611822.html
《LeetCode112》 http://blog.csdn.net/javyzheng/article/details/40652409
《尋找第一個缺失數字》http://blog.csdn.net/lj_2_0_2/article/details/51336659
看完上述的3篇博文,總是有的地方考慮不清。直到看到一篇《【白話經典算法系列之十六】“基數排序”之數組中缺失的數字》 http://blog.csdn.net/morewindows/article/details/12683723 才豁然開朗。
以{1, 3, 6, -100, 2}為例來簡介這種解法:
從第一個數字開始,由於a[0]=1,所以不用處理了。
第二個數字為3,因此放到第3個位置(下標為2),交換a[1]和a[2],得到數組為{1, 6, 3, -100, 2}。由於6無法放入數組,所以直接跳過。
第三個數字是3,不用處理。
第四個數字是-100,也無法放入數組,直接跳過。
第五個數字是2,因此放到第2個位置(下標為1),交換a[4]和a[1],得到數組為{1, 2, 3, -100, 6},由於6無法放入數組,所以直接跳過。
此時“基數排序”就完成了,然後再從遍歷數組,如果對於某個位置上沒該數,就說明數組缺失了該數字。如{1, 2, 3, -100, 6}缺失的就為4。
這樣,通過第i個位置上就放i的“基數排序”就順利的搞定此題了。
1 // 【白話經典算法系列之十六】“基數排序”之數組中缺失的數字 2 // by MoreWindows( http://blog.csdn.net/MoreWindows ) 3 // 歡迎關註http://weibo.com/morewindows 4 #include <stdio.h> 5 void Swap(int &a, int &b) 6 { 7 int c = a; 8 a = b; 9 b = c; 10 } 11 int FindFirstNumberNotExistenceInArray(int a[], int n) 12 { 13 int i; 14 // 類似基數排序,當a[i]>0且a[i]<N時保證a[i] == i + 1 15 for (i = 0; i < n; i++) 16 while (a[i] > 0 && a[i] <= n && a[i] != i + 1 && a[i] != a[a[i] - 1]) 17 Swap(a[i], a[a[i] - 1]); 18 // 查看缺少哪個數 19 for (i = 0; i < n; i++) 20 if (a[i] != i + 1) 21 break; 22 return i + 1; 23 } 24 void PrintfArray(int a[], int n) 25 { 26 for (int i = 0; i < n; i++) 27 printf("%d ", a[i]); 28 putchar(‘\n‘); 29 } 30 int main() 31 { 32 printf(" 【白話經典算法系列之十六】“基數排序”之數組中缺失的數字\n"); 33 printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n"); 34 printf(" -- http://blog.csdn.net/morewindows/article/details/12683723 -- \n\n"); 35 36 const int MAXN = 5; 37 //int a[MAXN] = {1, 2, 3, 4, 7}; 38 //int a[MAXN] = {1, 3, 5, 4, 2}; 39 int a[MAXN] = {2, -100, 4, 1, 70}; 40 //int a[MAXN] = {2, 2, 2, 2, 1}; 41 PrintfArray(a, MAXN); 42 printf("該數組缺失的數字為%d\n", FindFirstNumberNotExistenceInArray(a, MAXN)); 43 return 0; 44 }
第一個缺失數字