专栏名称: 吴师兄学算法
和程序员小吴一起从初学者的角度学习算法,以动画的形式呈现解题的思路。每周四篇原创文章,期待你的鉴赏!
目录
相关文章推荐
微观三农  ·  总书记谈“三农”,强调这些关键词 ·  昨天  
微观三农  ·  评论丨持续整治乱占耕地问题 ·  昨天  
微观三农  ·  2025年华南地区春花生生产技术指导意见 ·  2 天前  
51好读  ›  专栏  ›  吴师兄学算法

「图解」缺失的第一个正数

吴师兄学算法  · 公众号  ·  · 2019-11-22 12:15

正文

点击蓝色“ 五分钟学算法 ”关注我哟

加个“ 星标 ”,天天中午 12:15,一起学算法

来源 | 五分钟学算法


今天分享的题目来源于 LeetCode 第 41 号问题:缺失的第一个正数。

题目描述

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

示例 1:

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

示例 2:

输入: [3,4,-1,1]
输出: 2

示例 3:

输入: [7,8,9,11,12]
输出: 1

说明:

你的算法的时间复杂度应为O( n ),并且只能使用常数级别的空间。

题目解析

这道题使用桶排序的思路,即 “一个萝卜一个坑”,就可以解决。可以就使用题目中的例子,在纸上写写画画,就能得出思路,只不过在编码上需要注意一些细节。

我们可以把数组进行一次“排序”,“排序”的规则是: 如果这个数字 i 落在“区间范围里”,i 就应该放在索引为 i - 1 的位置上 ,下面具体解释。

1、数字 i 落在“区间范围里”;

例如: [3, 4, -1, 1] ,一共 4 个数字,那么如果这个数组中出现 “1”、“2”、“3”、“4”,就是我们重点要关注的数字了;
又例如: [7, 8, 9, 11, 12] 一共 5 个数字,每一个都不是 “1”、“2”、“3”、“4”、“5” 中的一个,因此我们无须关注它们;

2、 i 就应该放在索引为 i - 1 的位置上;

这句话也可以这么说 “ 索引为 i 的位置上应该存放的数字是 i + 1 ”。

就看上面那张图,数字 1 应该放在索引为 0 的位置上,数字 3 应该放在索引为 2 的位置上,数字 4 应该放在索引为 3 的位置上。一个数字放在它应该放的位置上,我们就认为这个位置是“和谐”的,看起来“顺眼”的。

按照以上规则排好序以后,缺失的第 1 个正数一下子就看出来了,那么“最不和谐”的数字的索引 +1,就为所求。

那如果所有的数字都不“和谐”,数组的长度 +1 就为所求。

动画描述

图片描述

以下是上面 gif 图的静态图。

LeetCode 第 41 题:缺失的第一个正数-1

LeetCode 第 41 题:缺失的第一个正数-2

LeetCode 第 41 题:缺失的第一个正数-3

LeetCode 第 41 题:缺失的第一个正数-4

LeetCode 第 41 题:缺失的第一个正数-5

LeetCode 第 41 题:缺失的第一个正数-6

LeetCode 第 41 题:缺失的第一个正数-7

LeetCode 第 41 题:缺失的第一个正数-8

代码实现

public class Solution {

    // 关键字:桶排序,什么数字就要放在对应的索引上,其它空着就空着
    // 最好的例子:[3,4,-1,1]
    // 整理好应该是这样:[1,-1,3,4],
    // 这里 1,3,4 都在正确的位置上,
    // -1 不在正确的位置上,索引是 1 ,所以返回 2
    // [4,3,2,1] 要变成 [1,2,3,4]
    // 这里负数和大于数组长度的数都是"捣乱项"。
    public int firstMissingPositive(int[] nums) {
        int len = nums.length;

        for (int i = 0; i             // 前两个是在判断是否成为索引
            // 后一个是在判断,例如 3 在不在索引 2 上
            // 即 nums[i] ?= nums[nums[i]-1] 这里要特别小心
            while (nums[i] > 0 && nums[i] <= len && nums[nums[i] - 1] != nums[i]) {
                // 第 3 个条件不成立的索引的部分是 i 和 nums[i]-1
                swap(nums, nums[i] - 1, i);
            }
        }

        // 调试代码
        // System.out.println(Arrays.toString(nums));

        for (int i = 0; i             // [1,-2,3,4]
            // 除了 -2 其它都满足:i+1 = num[i]
            if (nums[i] - 1 != i) {
                return i + 1






请到「今天看啥」查看全文