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

本文探讨了如何在数组中找到最小的缺失正整数,介绍了一种时间复杂度为O(n)且仅使用常数级别空间的方法。通过巧妙地重新排列数组元素,实现了高效的查找过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

leetcode中的一道题,

首先考虑两次循环,    

int firstMissingPositive(vector<int>& nums) {
        int res = 1;
        for (int j = 0; j<nums.size(); j++) {
            for (int i = 0; i<nums.size(); i++) {
                if (res == nums[i]) {
                    res++;
                    break;
                }
            }
        }
        return res;
    }

但是时间复杂度为O(n^2),

然后思考其他方法,可以考虑用哈希表,具体是把每个原数组的值对应的哈希表中的位置的值改变,但这内存使用增大,

但这给我们提供了一定的方向,为什么不可以遍历原数组一次,把每个数组的值移动到对应的下表下呢,完全遍历一次后,在遍历一次,第一个不与下标对应的就是我们要找的值了!

下面是我们的代码:

    int firstMissingPositive(vector<int>& nums) {
        for (int i = 0; i < nums.size(); i++) {
            while (nums[i] > 0 && nums[i] <= nums.size()&&nums[i]!=nums[nums[i]-1]){
                swap(nums[i], nums[nums[i] - 1]);
            }
        }
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] != i + 1) {
                return i + 1;
            }
        }
        return nums.size() + 1;
    }

但是两次提交第一次时间复杂度为O(n^2)的在leetcode上只有4ms,但是第二个有20毫秒唉,

可能是由于n不够大??

<think>好的,我现在要解决这个问题:给定一个排序整数数组nums,找出其中没有出现的最小正整数。根据用户的要求,我需要按照提供的模板来回答,包括需求分析、算法思路、代码实现、复杂度分析和测试案例。首先,我得仔细分析题目,明确输入输出以及具体要求。 首先,需求分析部分。输入是一个排序整数数组,可能包含负数、零和重复的数字。输出是缺失的最小正整数,也就是在1,2,3,...这个序列中第一个没有出现在数组中的数。比如,如果数组是[1,2,0],那么答案是3;如果是[3,4,-1,1],答案是2。题目要求时间复杂度是O(n),并且只能使用常数级别的额外空间。这意味着不能使用哈希表等需要额外空间的结构,否则空间复杂度会超过限制。 接下来是算法思路。我需要想一个方法,在O(n)的时间复杂度下,并且不使用额外空间。常见的思路可能是将数组本身作为哈希表来使用。因为我们要找的是最小正整数,所以这个数一定在1到n+1之间,其中n是数组的长度。因为如果数组包含了1到n的所有数,那么缺失的就是n+1,否则就是第一个在1到n之间没出现的数。 所以,我需要将数组中的每个元素放到它对应的位置上。例如,如果元素是3,就放到索引2的位置(因为索引从0开始)。如果元素是x,且x在1到n之间,就交换到x-1的位置。这样,遍历数组后,每个正整数x应该出现在x-1的位置。之后,再次遍历数组,第一个位置i上的数不是i+1的话,就返回i+1。如果所有位置都符合,返回n+1。 这个思路的关键点在于原地交换元素,利用数组本身的空间来记录哪些数字出现过。需要注意处理重复元素和超出范围的数,比如负数或者大于n的数,这些可以忽略不管,因为它们不影响1到n的范围内的结果。 然后,我需要考虑如何实现这个交换过程。遍历数组,对于每个元素,如果它在1到n的范围内,并且它不在正确的位置上,就进行交换。例如,当前元素是nums[i],如果nums[i]的值在1到n之间,并且nums[nums[i]-1]不等于nums[i],则交换它们的位置,并继续检查交换后的nums[i]是否需要再次交换。这里需要用循环来处理,直到当前元素不在1到n的范围或者已经处于正确的位置为止。 接下来是代码实现部分。我需要编写一个C++函数,接受一个整数数组,返回缺失的最小正整数。注意数组可能为空,或者包含负数等情况。需要处理这些边界情况。 在复杂度分析中,时间复杂度是O(n),因为每个元素最多被交换两次到正确的位置,所以总体是线性时间。空间复杂度是O(1),因为没有使用额外的数据结构,只是在原数组上操作。 测试案例需要覆盖不同的情况,比如包含1的情况,不包含1的情况,所有数都出现的情况,有重复数的情况等等。例如: 测试案例1:输入[1,2,0],输出3。 测试案例2:输入[3,4,-1,1],输出2。 测试案例3:输入[7,8,9,11,12],输出1。 测试案例4:输入[1],输出2。 测试案例5:输入[1,1],输出2。 现在,我需要按照模板的结构来组织这些内容。确保每个部分都清晰明了,代码正确,注释详细。同时,数学推导部分可能需要用LaTeX公式,比如说明为什么结果在1到n+1之间。 可能的数学表达式如: - 结果范围:设数组长度为n,则缺失的最小正整数必定属于集合$\{1, 2, \ldots, n+1\}$。 - 这是因为如果数组恰好包含1到n的所有数,则答案是n+1;否则,答案是在1到n之间缺失的第一个数。 在代码实现中,需要注意循环交换的条件,避免死循环。例如,当交换两个相同的数时,可能导致无限循环,所以需要检查交换的位置是否已经存在正确的数。 最后,测试函数需要构造不同的测试案例,并验证输出是否正确。确保代码的可运行性,包括处理输入数组的构建,调用解决方案类,输出结果等。</think>#### 1. 需求分析 **输入**:排序整数数组`nums`(可能含负数、零、重复值) **输出**:出现的最小正整数 **要求**:时间复杂度$O(n)$,空间复杂度$O(1)$ --- #### 2. 算法思路 **核心思想**:利用数组自身作为哈希表,将数值$x$映射到位置$x-1$ **数学推导**: - 最小出现正整数必在集合$\{1, 2, \dots, n+1\}$中 - 若数组包含$1 \sim n$,则答案为$n+1$,否则为$1 \sim n$中的第一个缺失数 **步骤**: 1. 遍历数组,将每个数$x$交换到位置$x-1$(仅当$1 \leq x \leq n$时) 2. 再次遍历数组,第一个不满足`nums[i] == i+1`的位置即为答案 --- #### 3. C++实现 ```cpp #include <vector> #include <algorithm> // 使用swap函数 class Solution { public: int firstMissingPositive(std::vector<int>& nums) { int n = nums.size(); // 原地哈希:将数值x放到x-1的位置 for (int i = 0; i < n; ++i) { // 当nums[i]在有效范围内,且目标位置的数尚正确时,持续交换 while (nums[i] > 0 && nums[i] <= n && nums[nums[i] - 1] != nums[i]) { std::swap(nums[i], nums[nums[i] - 1]); } } // 查找第一个不匹配的位置 for (int i = 0; i < n; ++i) { if (nums[i] != i + 1) { return i + 1; } } return n + 1; // 所有位置均匹配时返回n+1 } }; // 测试函数 #include <iostream> void test() { Solution sol; std::vector<std::vector<int>> testCases = { {1,2,0}, // 预期输出3 {3,4,-1,1}, // 预期输出2 {7,8,9,11,12}, // 预期输出1 {1}, // 预期输出2 {1,1} // 预期输出2 }; for (auto& nums : testCases) { int res = sol.firstMissingPositive(nums); std::cout << "输入数组: ["; for (int num : nums) std::cout << num << ","; std::cout << "\b] => 最小缺失正整数: " << res << std::endl; } } int main() { test(); return 0; } ``` --- #### 4. 复杂度分析 - **时间复杂度**:$O(n)$ 每个元素最多被交换两次(例如元素被交换到正确位置后不再移动) - **空间复杂度**:$O(1)$ 仅使用常量额外空间(原地操作) --- #### 5. 关键点 - **循环条件**:交换时必须检查目标位置的数值是否已正确 - **边界处理**:忽略负数及超过$n$的数值 - **终止条件**:当数组包含$1 \sim n$时返回$n+1$ --- #### 测试案例输出示例 ``` 输入数组: [1,2,0] => 最小缺失正整数: 3 输入数组: [3,4,-1,1] => 最小缺失正整数: 2 输入数组: [7,8,9,11,12] => 最小缺失正整数: 1 输入数组: [1] => 最小缺失正整数: 2 输入数组: [1,1] => 最小缺失正整数: 2 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值