首页 > 代码库 > leetcode:First Missing Positive分析和实现
leetcode:First Missing Positive分析和实现
题目大意:
传入整数数组nums,求nums中未出现的正整数中的最小值。要求算法在O(n)时间复杂度内实现,并且只能分配常量空间。
分析:
一般碰到这种问题,都先对数组进行排序,再遍历数组就可以找到最小的在nums中没有出现过的正整数。但是由于排序的时间复杂度一般为O(nlog2(n)),因此时间复杂度没有达到要求。
之后再转回排序的方式,有一种排序的方式称为桶排序,只要有足够的空间,就可以在O(n)的时间复杂度内完成排序过程。但事实是只能分配常量空间。
只能分配常量空间还要求时间复杂度为O(n),这时候我们就只能打起传入的参数nums的主意,能不能用nums来存储我们的中间结果呢?
我们要做的就是遍历nums,将每个在nums中出现的正整数t写入到nums[t-1]中。在完成了这个过程后,再遍历数组,直到找到一个下标i,使得nums[i]不等于i+1,显然i+1就是nums缺失的最小正整数。
下面给出伪代码:
for(i = 0; i < nums.length; i++)
num = nums[i]
rightPos = num - 1
while(rightPos >= 0 && rightPos < nums.length && nums[rightPos] != num)
temp = num[rightPos]
num[rightPos] = num
num = temp
rightPos = num - 1
上面就是第一阶段的代码,负责将每个在nums中出现的正整数t写入到nums[t-1]中。而当然对于一些负数和过大的正整数(大于n),由于无处可写就会直接被跳过,而这些整数也必然不会包含我们所要求的结果。
再说明一下为什么这段代码能在O(n)时间复杂度内完成。我们称一个下标i为正确的,当且仅当nums[i] = i + 1,而不正确的下标则称为错误的,显然在上面的代码逻辑中一旦一个下标i是正确的,那么就不会有值写入到nums[i]中(nums[rightPos] != num条件保证)。在不考虑内部while循环占用的时间的情况下,for循环总共的时间复杂度为O(n)毋庸质疑。而每次调用while循环,都会将一个错误值纠正为正确的值,而最多只会存在n个正确值,这就意味着while循环总共只会执行n次,而一次while循环内部的动作所耗费的时间复杂度为O(1),故总的时间复杂度就为"for循环不考虑while的时间复杂度"+"for循环内while的时间复杂度"=O(n)+O(n)=O(n)。
而上面这个过程只额外分配了固定的变量数目,因此空间复杂度为O(1)。由于递归也要占用栈空间,即空间复杂度会增加,但这里用while而非递归,因此空间复杂度不会被破坏。
给出Java的解决代码:
1 public class Solution { 2 public int firstMissingPositive(int[] nums) { 3 if(nums.length == 0) 4 { 5 return 1; 6 } 7 for(int i = 0, bound = nums.length; i < bound; i++) 8 { 9 int num = nums[i]; 10 int rightPos = num - 1; 11 while(rightPos >= 0 && rightPos < bound && nums[rightPos] != num) 12 { 13 int tmp = nums[rightPos]; 14 nums[rightPos] = num; 15 num = tmp; 16 rightPos = num - 1; 17 } 18 } 19 for(int i = 0, bound = nums.length; i < bound; i++) 20 { 21 if(nums[i] != i + 1) 22 { 23 return i + 1; 24 } 25 } 26 return nums.length + 1; 27 } 28 }
leetcode:First Missing Positive分析和实现