数组中未出现的最小正整数(时间复杂度O(N),空间复杂度O(1))

【题目】

  给定一个无序整型数组arr,找到数组中未出现的最小正整数。 
  例如: 
  arr = [-1, 2, 3, 4],返回1 
  arr = [1, 2, 3, 4],返回5

【基本思路】

  整个过程可以做到时间复杂度O(N),空间复杂度O(1)。 
   
  生成变量left和right,left表示遍历到目前为止,数组中已经包含的正整数的范围是[1…left],初始时令left = 0表示没有arr目前没有包含任何正整数;right表示遍历到目前为止,在后续情况出现最优的情况下,arr可能包含的正整数的范围是[1, right],初始时令right = N,表示arr可能包含1~N的所有正整数。 arr[left]正确存储的值是left+1。
   
  利用left从左到右遍历数组:

  1. 如果arr[left] = left + 1。在没有遍历arr[left]之前,arr已经包含的正整数的范围是[1,left],此时出现了arr[left] = left + 1,说明arr包含的正整数的范围可以扩到[1, left+1],即令left + 1.

  2. 如果arr[left] <= left。在没有遍历arr[left]之前,arr中的正整数的范围已经是[1, left],所以需要的是[left+1, right]上的数,而此时arr[left] <= left,说明[left+1, right]上少了一个数,所以arr在后续最优的情况下,可能包含的正整数的范围缩小到[1, right-1],此时把arr最后位置的数arr[right-1]放在位置left上,下一步检查这个数,然后令right - 1.

  3. 如果arr[left] > right,与步骤2同理,把arr最后位置的数arr[right-1]放在位置left上,下一步检查这个数,然后令right - 1.

  4. 如果arr[arr[left]-1] = arr[left]。如果步骤2、3没中,说明arr[left]是在[left+1, right]范围上的,而且这个数应该放置在arr[left] - 1位置上,但是发现此时arr[left] - 1位置上的数已经为arr[left],说明这个数出现了两次,既然在[left+1, right]上出现了重复值,那么[left+1, right]范围上的数又少了一个,所以把arr最后位置的数arr[right-1]放在位置left上,下一步检查这个数,然后令right - 1.

  5. 如果步骤2、3、4都没中,说明发现了[left+1, right]上的数,并且未发生重复。那么arr[left]应该放在位置arr[left] - 1上,所以把left位置上的值和arr[left] - 1位置上的值交换,下一步继续遍历位置left上的数。
     
 C++源码:
int missNum(int arr[], int length)
{
	int left = 0;
	int right = length;

	while(left < right)
	{
		if(arr[left] == left + 1) 
		{
			left++;
		}
		else if(arr[left] < left+1 || arr[left] > right || arr[arr[left]-1] == arr[left])//不合法
		{
			arr[left] = arr[right - 1];
			right--;
		}
		else
		{
			swap(arr[left], arr[arr[left]-1]);
		}
	}
	return left+1;
}
来源



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值