首页 > 其他分享 >力扣 41.缺少的第一个正整数

力扣 41.缺少的第一个正整数

时间:2024-06-05 13:58:22浏览次数:21  
标签:位置 正整数 当前 nums 元素 交换 41 力扣 数组

题目描述

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

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

示例 1:

输入:nums = [1,2,0]
输出:3
解释:范围 [1,2] 中的数字都在数组中。

示例 2:

输入:nums = [3,4,-1,1]
输出:2
解释:1 在数组中,但 2 没有。

示例 3:

输入:nums = [7,8,9,11,12]
输出:1
解释:最小的正数 1 没有出现。

提示:

  • 1 <= nums.length <= 105
  • -231 <= nums[i] <= 231 - 1

题解

考虑将每一个元素x放在对应位置的下标处,比如,元素值x等于3,就放在下标为2的位置,因此数组3,2,1在重新放置之后们就会成为:1,2,3,即元素x放在下标为x-1的位置。

遍历一遍数组,如果发现现在i位置的元素值x不等于i+1,说明现在需要进行元素交换,让元素x放在它本来应该放置的位置x-1处,可以使用自定义的交换函数change(nums,i,x-1),即让i位置元素和x-1位置元素进行交换。

但是注意,交换之前,我们需要确定,现在i位置元素是否是正整数,如果不是的话,对于一个负数或0来说,在我们最终的数组中实际是没有该元素的位置的,因此交换操作不需要对负数和0进行操作,如果遍历到负数或0直接跳过;

其次,如果现在数组大小是4,即下标范围值[0,3],但是某一个数组元素值为7,该元素需要放置在下标为6的位置,但是数组放不下,因此这种情况也不需要进行交换排序,直接跳过。

综上所述,最终需要进行排序的前提条件是:

1、当前元素大小小于等于数组大小

2、当前元素值>=1

3、当前元素没有放在它实际应该放置的位置,即nums[i]!=nums[nums[i]-1]

在一次交换之后,当前位置上是否就是应该放置的值,这也是不确定的,因此上面我们实现的是将i位置的值放在正确的位置上,但是交换之后的值是否在正确的位置上还是不确定的,因此还需要继续交换,所以这里判断是否需要交换的条件要使用while循环而不是if循环。

使用while循环进行是否可以进行交换的判断的时候,如果出现重复元素在原数组中出现,那么也可以正常进行判断交换,因为,一旦其中一个元素交换到正确的位置上,那么下一个元素进行while判断的时候,nums[i]!=nums[nums[i]-1的条件就不满足,自然不会造成死循环,同时这里使用的是判断当前位置的值是否放在正确位置,而不是当前位置是否放置正确元素,因为现在遍历到当前位置,能确定的就是当前位置的值,以及当前位置的元素应该放到哪里,但是不能确定当前位置应该放置的元素现在在数组的什么位置,因此该判断条件要这么写。

代码实现

 public static int firstMissingPositive(int[] nums) {
        //原地排序数组,将值为x的元素放在下标x-1的位置
        for (int i = 0; i < nums.length; i++) {
            while(nums[i]>=1&&nums[i]<=nums.length&&nums[i]!=nums[nums[i]-1]){
                check(nums,i,nums[i]-1);
            }

        }
        for (int j = 0; j < nums.length; j++) {
            if(nums[j]!=j+1){
                return j+1;
            }
        }
        return nums.length+1;
    }
    public static void check(int[] a,int i ,int j){
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }

知识点

对于这种数组交换来实现每一个元素都在自己应该在的位置的想法一开始觉得不能实现,因为觉得交换之后现在位置上的元素可能还是不满足要求,再进行交换,会不会将之前排好序的位置打乱,实际上,这样的担忧是不必要的,因为每个元素只有一个确定的位置,要么能够交换就交换的放置,要么因为在当前数组放不下该元素或者该元素小于1就不交换,总之,只要在while判断条件下进行的交换总能将新交换到当前位置的元素再交换到正确的位置,直到新交换到当前位置的元素已经不满足要交换的条件了,继续遍历下一个元素进行新一轮的交换即可。

标签:位置,正整数,当前,nums,元素,交换,41,力扣,数组
From: https://blog.csdn.net/qq_62622854/article/details/139467439

相关文章

  • 力扣-1049. 最后一块石头的重量 II
    1.题目题目地址(1049.最后一块石头的重量II-力扣(LeetCode))https://leetcode.cn/problems/last-stone-weight-ii/题目描述有一堆石头,用整数数组 stones表示。其中 stones[i]表示第i块石头的重量。每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分......
  • CF941
    后面应该就先打打ACM,大二下打完退役然后直接转职网安。临近期末非常脑残,前几天放弃自我意识加班加点把堆积的事情做完了,也一点都不感到轻松因为后面还要准备沙贝期末考试。想着把市赛和月赛的题先补一下,然后两个的题解都还没update,很伤心。干脆vp一场cf换换心情把!结果vp完更伤心了......
  • 【每周例题】 C++ 力扣 优势洗牌
    优势洗牌题目优势洗牌 题目分析1.采用双指针方法进行匹配2.依照题目所说,采用索引,首先需要填充索引,然后对索引进行升序排序。2.使用双指针进行匹配如果nums1[idx1[i]](即当前nums1中的元素)大于nums2[idx2[left]](即nums2中的当前最小元素),则将nums1[idx1[i]]赋值给ans[idx2[......
  • 【每周例题】C++ 力扣 旋转字符串
    旋转字符串 题目旋转字符串 题目分析方法1:模拟字符串1.采用双for循环去模拟字符串旋转,第一个for循环,模拟字符串循环位移;第二个for循环,进行逐个字符串检测2.使用if进行判断是否符合要求方法2:假设我们将goal字符串拆分为2个字符串,将其命名为R、L,我们将会得到以下式子go......
  • 力扣每日一题 6/4
    3067.在带权树网络中统计可连接服务器对数目[中等]题目:给你一棵无根带权树,树中总共有 n 个节点,分别表示 n 个服务器,服务器从 0 到 n-1 编号。同时给你一个数组 edges ,其中 edges[i]=[ai,bi,weighti] 表示节点 ai 和 bi 之间有一条双向边,边的权值为 we......
  • 力扣-494. 目标和
    1.题目题目地址(494.目标和-力扣(LeetCode))https://leetcode.cn/problems/target-sum/题目描述给你一个非负整数数组nums和一个整数target。向数组中的每个整数前添加 '+'或'-',然后串联起所有整数,可以构造一个表达式:例如,nums=[2,1],可以在2之前添加'+',......
  • 力扣每日一题 6/3
    1103.分糖果II[简单]题目:排排坐,分糖果。我们买了一些糖果 candies,打算把它们分给排好队的 n=num_people 个小朋友。给第一个小朋友1颗糖果,第二个小朋友2颗,依此类推,直到给最后一个小朋友 n 颗糖果。然后,我们再回到队伍的起点,给第一个小朋友 n +1 颗糖果,第二......
  • 算法第四天力扣第704题:二分查找
    704.二分查找的题目链接如下:https://leetcode.cn/problems/binary-search/https://leetcode.cn/problems/binary-search/  给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 ......
  • 力扣第五题 5.最长回文子串
    目录问题解题思路动态规划中心扩展官方解法1.动态规划2.中心扩展算法3.Manacher 算法问题解题思路我们的回文子串有两种情况,一种是左与右相同,一种是左与右+1的位置所以我们就可以根据这个条件判断是否为子串,然后再扩大判断。还可以使用中心扩展的方式,就判断左......
  • 打卡信奥刷题(40)用Scratch图形化工具信奥B3828 [NOIP2008 普及组] [NICA #2] 优秀正整
    [NICA#2]优秀正整数题目描述Aya定义符合如下条件的正整数xxx为优秀正整数:x......