算法-缺失的最小正数/数字

对于这类问题,我们一般可以在数组内内部排序得到,这里说的排序并不是真正的排序,而是将在数组范围内的元素放置到他应该在的位置为实现的。

比如,对于缺失最小正数来说,我们在位置i存放i+1的值

核心代码就这一部分

while(nums[i]>0&&nums[i]<nums.length&&nums[nums[i]-1]!=nums[i]){
	swap(nums,nums[i]-1,i);//将本元素位置放到它该在的位置,把那个位置的元素交换回来
}

对于最小缺失数字,我们将位置i的元素放入i的值

while(nums[i]>=0&&nums[i]<nums.length&&nums[nums[i]]!=nums[i]){
	swap(nums,nums[i],i);
}

最后我们在遍历数组,找到不符合条件的位置,返回我们需要的值

1、缺失的最小正数

这道算法题是非常经典的一道题了Leetcode-42,问题描述如下:

给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。
示例 1:
输入: [1,2,0]
输出: 3
示例 2:
输入: [3,4,-1,1]
输出: 2
示例 3:
输入: [7,8,9,11,12]
输出: 1

乍一看上去觉得这道题平平无奇,排个序就知道了,然而事情并没有那么简单,不然他咋能成为一道Hard题的?

这道题一般会要求我们在O(N)时间复杂度完成,要达到这一点,排序就不行了,有同学可能会说,用HashMap啊,当然,用hashMap也是可以的,但是如果要求我们必须要空间O(1)的算法,那就不适用了。使用Hash的的思想没错,不过我们可以原地使用数组实现。

我们只需要把符合数组范围的数据映射到数组中他应该在的位置即可,然后我们从数组的0位置遍历,直到遍历到不符合nums[i]==i+1的位置即可!i+1就是我们需要的值。当然,如果全都符合,那目标值就是数组长度+1了。

	public int firstMissingPositive(int[] nums) {
		for(int i=0;i<nums.length;i++){
			//这里首先要保证将符合数组范围内的数据放入到数组位置
			//nums[i]!=nums[nums[i]-1]这里解释一下,其实就是:nums[i]-1!=i
			while(nums[i]>0&&nums[i]<nums.length&&nums[i]!=nums[nums[i]-1]){
				swap(nums,nums[i]-1,i);
			}
		}
		for(int i=0;i<nums.length;i++){
			if(nums[i]!=i+1){
				return i+1;
			}
		}
		return nums.length+1;//所有数据都归位了
	}

	private void swap(int[] nums,int i,int j){
		int temp=nums[i];
		nums[i]=nums[j];
		nums[j]=temp;
	}

2、缺失数字

本题来源于Leetcode268题。其实268题有更巧妙的解法,但是那些精巧的解法往往很难想到,所以这里给出第二类解法,和缺失最小正数一样的解法

268. 缺失数字
给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。

示例 1:

输入: [3,0,1]
输出: 2
示例 2:

输入: [9,6,4,2,3,5,7,0,1]
输出: 8
说明:
你的算法应具有线性时间复杂度。你能否仅使用额外常数空间来实现?
public int missingNumber(int[] nums) {
	for(int i=0;i<nums.length;i++){
		while(nums[i]>=0&&nums[i]<nums.length&&nums[nums[i]]!=nums[i]){
			swap(nums,nums[i],i);
		}
	}
	for(int i=0;i<nums.length;i++){
		if(nums[i]!=i){
			return i;
		}
	}
	return nums.length;
}

3、找到所有数组中消失的数字

448. 找到所有数组中消失的数字

给定一个范围在  1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。

找到所有在 [1, n] 范围之间没有出现在数组中的数字。

您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。

示例:

输入:
[4,3,2,7,8,2,3,1]

输出:
[5,6]

根据上面的两道题,本题其实也迎刃而解了

    public List<Integer> findDisappearedNumbers(int[] nums) {
        for(int i=0;i<nums.length;i++){
            while(nums[nums[i]-1]!=nums[i]){
                swap(nums,nums[i]-1,i);
            }
        }
        List<Integer> list=new ArrayList<>();
        for(int i=0;i<nums.length;i++){
            if(nums[i]!=i+1){
                list.add(i+1);
            }
        }
        return list;
    }
    private void swap(int[] nums,int i,int j){
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值