Given an unsorted integer array, find the smallest missing positive integer.
Example 1:
Input: [1,2,0] Output: 3
Example 2:
Input: [3,4,-1,1] Output: 2
Example 3:
Input: [7,8,9,11,12] Output: 1
Note:
Your algorithm should run in O(n) time and uses constant extra space.
分析:题目意思很明确,要求找数组中没有出现的最小的正整数。
一个最原始的思路,就是从1开始递增,挨个判断是否在数组中。因此需要用一个list保存一下原数组元素,才能用contains方法。
1 class Solution { 2 public int firstMissingPositive(int[] nums) { 3 List<Integer> list = new ArrayList<>(); 4 for ( int n:nums ) 5 list.add(n); 6 for ( int i = 1 ; ; i ++ ){ 7 if (!list.contains(i) ) return i; 8 } 9 } 10 }
运行时间7ms,但是这种方法,时间复杂度是O(n),空间复杂度是O(n)。不符合要求。
第二个思路:参考了网上大神的代码,毕竟是hard,求解太巧妙了。
这道题要求用线性时间和常量空间,思想借鉴到了Counting sort中的方法,参见Counting sort - Wikipedia。既然不能用额外空间,那就只有利用数组本身,跟Counting sort一样,利用数组的index来作为数字本身的索引,把正数按照递增顺序依次放到数组中。即让A[0]=1, A[1]=2, A[2]=3, ... , 这样一来,最后如果哪个数组元素违反了A[i]=i+1即说明i+1就是我们要求的第一个缺失的正数。对于那些不在范围内的数字,我们可以直接跳过,比如说负数,0,或者超过数组长度的正数,这些都不会是我们的答案。
代码如下:
1 class Solution { 2 public int firstMissingPositive(int[] nums) { 3 //把所有数字放回对应的index; 4 int start = 0; 5 while(start < nums.length) { 6 if(nums[start] <= 0 || nums[start] == start + 1 || nums[start] > nums.length) { 7 start++; 8 } else if(nums[nums[start] - 1] != nums[start]){ 9 swap(nums, start, nums[start] - 1); 10 } else { 11 start++; 12 } 13 } 14 start = 0; 15 while(start < nums.length) { 16 if(nums[start] == start + 1) { 17 start++; 18 } else { 19 break; 20 } 21 } 22 return start + 1; 23 } 24 private void swap(int[] nums, int l, int r) { 25 int tmp = nums[l]; 26 nums[l] = nums[r]; 27 nums[r] = tmp; 28 } 29 }