算法小解:41. 缺失的第一个正数

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

提示:

  • 1 <= nums.length <= 10^5
  • -2^31 <= nums[i] <= 2^31 - 1

哈希表存储

解:缺失的第一个正数一定会在[1, nums.length + 1]中,比如nums = [1, 2, 3]中缺失的第一个正数为nums.length + 1。将整数存储在哈希表(空间复杂度为O(N)不符合常数级额外空间)中,然后再[1, nums.length + 1]中寻找不存在哈希表的数。

思路:liweiwei1419

class Solution {
    // 利用哈希表
    public int firstMissingPositive(int[] nums) {
        // [1, nums.length + 1]中一定有一个是最小缺失正数
        HashMap<Integer, Integer> map = new HashMap<>(nums.length);
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > 0)
                map.put(nums[i], i);
        }
        for (int i = 1; i <= nums.length; i++) {
            if (!map.containsKey(i))
                return i;
        }
        return nums.length + 1;
    }
}

自定义哈希(f(nums[i]) = nums[i] - 1)

解:遍历nums,根据f(nums[i]) = nums[i] - 1,nums[i] - 1为新的坐标,如果0 <= nums[i] - 1 < nums.length,交换nums[i] 和 nums[f(nums[i])]。之后再顺序遍历数组,如果nums[i] != i + 1就是缺失的第一个正数。

  1. 转换规则定义:

    • 对于数组 nums 中的每个元素 nums[i],定义一个函数 f(nums[i]) = nums[i] - 1
    • 这个函数的作用是将 nums[i] 转换为一个新的索引 nums[i] - 1
  2. 交换操作:

    • 如果 0 <= nums[i] - 1 < nums.length,即新计算出的索引在数组范围内,则交换 nums[i] 和 nums[nums[i] - 1]。这个操作旨在将每个元素移动到它应该在的位置。
  3. 找缺失的正数:

    • 在完成上述交换操作后,再次顺序遍历数组 nums
    • 如果发现 nums[i] != i + 1,则 i + 1 即为缺失的第一个正数。这是因为正常情况下,第一个缺失的正数应该是从 1 开始递增的,而 nums[i] 不等于 i + 1 表示 i + 1 缺失。
class Solution {
    public int firstMissingPositive(int[] nums) {
        // [1, nums.length + 1]中一定有一个是最小缺失正数
        for (int i = 0; i < nums.length; i++) {
            // 确保每次交换都能将 nums[i] 放到正确的位置上,直到无需交换为止。
            while (nums[i] - 1 >= 0 && nums[i] - 1 < nums.length && nums[nums[i] - 1] != nums[i]) {
                swap(nums, i, nums[i] - 1);
            }
        }
        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 a_idx, int b_idx) {
        int tmp = nums[a_idx];
        nums[a_idx] = nums[b_idx];
        nums[b_idx] = tmp;
    }
}

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值