用100道题拿下你的算法面试(数组篇-13):寻找缺失的最小正整数

一、面试问题
给定一个包含正数和负数的无序数组,找出数组中缺失的最小正整数。
示例 1:
- 输入:arr[] = [2, -3, 4, 1, 1, 7]
- 输出:3
- 解释:3 是数组中缺失的最小正整数。
示例 2:
- 输入:arr[] = [5, 3, 2, 5, 1]
- 输出:4
- 解释:4 是数组中缺失的最小正整数。
示例 3:
- 输入:arr[] = [-8, 0, -1, -4, -3]
- 输出:1
- 解释:1 是数组中缺失的最小正整数。
二、【朴素解法】排序法 —— 时间复杂度 O (n*log n),空间复杂度 O (1)
(一) 解法思路
先对数组排序,并假设缺失的数字为 1。随后遍历数组,对每个元素 arr [i] 执行以下判断:
- 如果 arr [i] 等于缺失数字,则将缺失数字加 1。
- 如果 arr [i] 小于缺失数字,则继续查找缺失数字。
- 如果 arr [i] 大于缺失数字,则终止遍历并返回当前缺失数字。
(二) 使用6种语言实现
1. C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int missingNumber(vector<int> &arr) {
sort(arr.begin(), arr.end());
int res = 1;
for (int i = 0; i < arr.size(); i++) {
// 如果我们在数组中找到了 'res',
// 说明 'res' 不是缺失的数字,因此将其加 1
if (arr[i] == res)
res++;
// 如果当前元素大于 'res',
// 说明 'res' 无法在数组中找到,
// 因此它就是我们最终的答案
else if (arr[i] > res)
break;
}
return res;
}
int main() {
vector<int> arr = {2, -3, 4, 1, 1, 7};
cout << missingNumber(arr);
return 0;
}
2. C
#include <stdio.h>
int cmp(const int *a, const int *b) {
return (*a - *b);
}
int missingNumber(int arr[], int size) {
// 对数组进行排序
qsort(arr, size, sizeof(int), (int(*)(const void*, const void*))cmp);
// res 用于存储当前缺失的最小正整数,
// 初始值设为 1
int res = 1;
for (int i = 0; i < size; i++) {
// 如果我们在数组中找到了 'res',
// 说明 'res' 不是缺失的数字,因此将其加 1
if (arr[i] == res) {
res++;
}
// 如果当前元素大于 'res',
// 说明 'res' 无法在数组中找到,
// 因此它就是我们最终的答案
else if (arr[i] > res) {
break;
}
}
return res;
}
int main() {
int arr[] = {2, -3, 4, 1, 1, 7};
int size = sizeof(arr) / sizeof(arr[0]);
printf("%d", missingNumber(arr, size));
return 0;
}
3. Java
import java.util.Arrays;
class DSA {
static int missingNumber(int[] arr) {
Arrays.sort(arr);
// res 用于存储当前缺失的最小正整数,
// 初始值设为 1
int res = 1;
for (int i = 0; i < arr.length; i++) {
// 如果我们在数组中找到了 'res',
// 说明 'res' 不是缺失的数字,因此将其加 1
if (arr[i] == res) {
res++;
}
// 如果当前元素大于 'res',
// 说明 'res' 无法在数组中找到,
// 因此它就是我们最终的答案
else if (arr[i] > res) {
break;
}
}
return res;
}
public static void main(String[] args) {
int[] arr = {2, -3, 4, 1, 1, 7};
System.out.println(missingNumber(arr));
}
}
4. Python
def missingNumber(arr):
arr.sort()
# res 用于存储当前缺失的最小正整数,
# 初始值设为 1
res = 1
for num in arr:
# 如果我们在数组中找到了 'res',
# 说明 'res' 不是缺失的数字,因此将其加 1
if num == res:
res += 1
# 如果当前元素大于 'res',
# 说明 'res' 无法在数组中找到,
# 因此它就是我们最终的答案
elif num > res:
break
return res
if __name__ == "__main__":
arr = [2, -3, 4, 1, 1, 7]
print(missingNumber(arr))
5. C#
using System;
class DSA {
static int missingNumber(int[] arr) {
Array.Sort(arr);
// res 用于存储当前缺失的最小正整数,
// 初始值设为 1
int res = 1;
for (int i = 0; i < arr.Length; i++) {
// 如果我们在数组中找到了 'res',
// 说明 'res' 不是缺失的数字,因此将其加 1
if (arr[i] == res) {
res++;
}
// 如果当前元素大于 'res',
// 说明 'res' 无法在数组中找到,
// 因此它就是我们最终的答案
else if (arr[i] > res) {
break;
}
}
return res;
}
static void Main(string[] args) {
int[] arr = {2, -3, 4, 1, 1, 7};
Console.WriteLine(missingNumber(arr));
}
}
6. JavaScript
function missingNumber(arr) {
arr.sort((a, b) => a - b);
// res 用于存储当前缺失的最小正整数,
// 初始值设为 1
let res = 1;
for (let i = 0; i < arr.length; i++) {
// 如果我们在数组中找到了 'res',
// 说明 'res' 不是缺失的数字,因此将其加 1
if (arr[i] == res) {
res++;
}
// 如果当前元素大于 'res',
// 说明 'res' 无法在数组中找到,
// 因此它就是我们最终的答案
else if (arr[i] > res) {
break;
}
}
return res;
}
const arr = [2, -3, 4, 1, 1, 7];
console.log(missingNumber(arr));
(三) 代码输出和算法复杂度
输出:
3
时间复杂度:O(n*log n)
空间复杂度:O(1)
三、【优化解法】使用标记数组(访问数组)实现 —— 时间复杂度 O (n),空间复杂度 O (n)
(一) 解法思路
创建一个标记 / 访问数组,用于记录原始数组中哪些数字是存在的。遍历输入数组,对其中的每一个正整数,我们在访问数组中标记它对应的位置。标记完成后,遍历访问数组,找到第一个未被标记的位置。这个未被访问的下标,就是我们要找的最小缺失正整数。
注意:我们只标记 1 到 n 范围内的数字。
(二) 使用6种语言实现
1. C++
#include <iostream>
#include <vector>
using namespace std;
int missingNumber(vector<int> &arr) {
int n = arr.size();
// 用于标记元素是否出现过
vector<bool> vis(n, false);
for (int i = 0; i < n; i++) {
// 如果元素在 1 到 n 的范围内
// 就将其标记为已访问
if (arr[i] > 0 && arr[i] <= n)
vis[arr[i] - 1] = true;
}
// 查找原始数组中第一个未被访问的元素
for (int i = 1; i <= n; i++) {
if (!vis[i - 1]) {
return i;
}
}
// 如果 1 到 n 的所有元素都已访问
// 那么 n + 1 就是第一个缺失的正整数
return n + 1;
}
int main() {
vector<int> arr = {2, -3, 4, 1, 1, 7};
cout << missingNumber(arr);
}
2. C
#include <stdio.h>
int missingNumber(int *arr, int n) {
// 用于标记元素是否出现过
int *vis = (int *)calloc(n, sizeof(int));
for (int i = 0; i < n; i++) {
// 如果元素在 1 到 n 的范围内
// 就将其标记为已访问
if (arr[i] > 0 && arr[i] <= n)
vis[arr[i] - 1] = 1;
}
// 查找原始数组中第一个未被访问的元素
for (int i = 1; i <= n; i++) {
if (!vis[i - 1]) {
free(vis);
return i;
}
}
// 如果 1 到 n 的所有元素都已访问
// 那么 n+1 就是第一个缺失的正整数
free(vis);
return n + 1;
}
int main() {
int arr[] = {2, -3, 4, 1, 1, 7};
int n = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", missingNumber(arr, n));
return 0;
}
3. Java
import java.util.Arrays;
class DSA {
static int missingNumber(int[] arr) {
int n = arr.length;
// 用于标记元素是否出现过
boolean[] vis = new boolean[n];
for (int i = 0; i < n; i++) {
// 如果元素在 1 到 n 的范围内
// 就将其标记为已访问
if (arr[i] > 0 && arr[i] <= n)
vis[arr[i] - 1] = true;
}
// 查找原始数组中第一个未被访问的元素
for (int i = 1; i <= n; i++) {
if (!vis[i - 1]) {
return i;
}
}
// 如果 1 到 n 的所有元素都已访问
// 那么 n+1 就是第一个缺失的正整数
return n + 1;
}
public static void main(String[] args) {
int[] arr = {2, -3, 4, 1, 1, 7};
System.out.println(missingNumber(arr));
}
}
4. Python
def missingNumber(arr):
n = len(arr)
# 用于标记元素是否出现过
vis = [False] * n
for i in range(n):
# 如果元素在 1 到 n 的范围内
# 就将其标记为已访问
if 0 < arr[i] <= n:
vis[arr[i] - 1] = True
# 查找原始数组中第一个未被访问的元素
for i in range(1, n + 1):
if not vis[i - 1]:
return i
# 如果 1 到 n 的所有元素都已访问
# 那么 n+1 就是第一个缺失的正整数
return n + 1
if __name__ == "__main__":
arr = [2, -3, 4, 1, 1, 7]
print(missingNumber(arr))
5. C#
using System;
class DSA {
static int missingNumber(int[] arr) {
int n = arr.Length;
// 用于标记元素是否出现过
bool[] vis = new bool[n];
for (int i = 0; i < n; i++) {
// 如果元素在 1 到 n 的范围内
// 就将其标记为已访问
if (arr[i] > 0 && arr[i] <= n)
vis[arr[i] - 1] = true;
}
// 查找原始数组中第一个未被访问的元素
for (int i = 1; i <= n; i++) {
if (!vis[i - 1]) {
return i;
}
}
// 如果 1 到 n 的所有元素都已访问
// 那么 n+1 就是第一个缺失的正整数
return n + 1;
}
static void Main() {
int[] arr = { 2, -3, 4, 1, 1, 7 };
Console.WriteLine(missingNumber(arr));
}
}
6. JavaScript
function missingNumber(arr) {
let n = arr.length;
// 用于标记元素是否出现过
let vis = new Array(n).fill(false);
for (let i = 0; i < n; i++) {
// 如果元素在 1 到 n 的范围内
// 就将其标记为已访问
if (arr[i] > 0 && arr[i] <= n)
vis[arr[i] - 1] = true;
}
// 查找原始数组中第一个未被访问的元素
for (let i = 1; i <= n; i++) {
if (!vis[i - 1]) {
return i;
}
}
// 如果 1 到 n 的所有元素都已访问
// 那么 n+1 就是第一个缺失的正整数
return n + 1;
}
const arr = [2, -3, 4, 1, 1, 7];
console.log(missingNumber(arr));
(三) 代码输出和算法复杂度
输出:
3
时间复杂度:O(n)
空间复杂度:O(n)
四、【最优解法】使用循环排序 —— 时间复杂度 O (n),空间复杂度 O (1)
(一) 解法思路
该方法与循环排序的思想类似,将数组中的每个元素根据其值移动到正确的位置。对于每个数值 x(满足 1 ≤ x ≤ n),将其放到下标为 x - 1 的位置上。
最后,遍历数组,检查每个位置上的数字是否与预期一致。第一个数字与下标不匹配的位置,就是我们要找的最小缺失正整数。如果 1 到 n 的所有数字都在正确的位置上,那么下一个数字 n + 1 就是答案。










(二) 使用6种语言实现
1. C++
#include <iostream>
#include <vector>
using namespace std;
int missingNumber(vector<int> &arr) {
int n = arr.size();
for (int i = 0; i < n; i++) {
// 如果 arr[i] 在 [1, n] 范围内,且没有放在 (arr[i]-1) 下标处
while (arr[i] >= 1 && arr[i] <= n
&& arr[i] != arr[arr[i] - 1]) {
// 交换 arr[i] 和 arr[arr[i]-1]
// 将 arr[i] 放到它对应的正确位置
swap(arr[i], arr[arr[i] - 1]);
}
}
// 如果某个数字不在对应的位置上
// 它就是缺失的数字
for (int i = 1; i <= n; i++) {
if (i != arr[i-1]) {
return i;
}
}
// 如果 1 到 n 的所有数字都存在
// 那么 n + 1 就是最小的缺失正整数
return n + 1;
}
int main() {
vector<int> arr = {2, -3, 4, 1, 1, 7};
cout << missingNumber(arr);
return 0;
}
2. C
#include <stdio.h>
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int missingNumber(int arr[], int n) {
for (int i = 0; i < n; i++) {
// 如果 arr[i] 在 [1, n] 范围内,且没有放在 (arr[i]-1) 下标处
while (arr[i] >= 1 && arr[i] <= n
&& arr[i] != arr[arr[i] - 1]) {
// 交换 arr[i] 和 arr[arr[i]-1]
// 将 arr[i] 放到它对应的正确位置
swap(&arr[i], &arr[arr[i] - 1]);
}
}
// 如果某个数字不在对应的位置上
// 它就是缺失的数字
for (int i = 1; i <= n; i++) {
if (i != arr[i-1]) {
return i;
}
}
// 如果 1 到 n 的所有数字都存在
// 那么 n + 1 就是最小的缺失正整数
return n + 1;
}
int main() {
int arr[] = {2, -3, 4, 1, 1, 7};
int n = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", missingNumber(arr, n));
return 0;
}
3. Java
import java.util.*;
class DSA {
static int missingNumber(int[] arr) {
int n = arr.length;
for (int i = 0; i < n; i++) {
// 如果 arr[i] 在 [1, n] 范围内,且没有放在 (arr[i]-1) 下标处
while (arr[i] >= 1 && arr[i] <= n
&& arr[i] != arr[arr[i] - 1]) {
// 交换 arr[i] 和 arr[arr[i]-1]
// 将 arr[i] 放到它对应的正确位置
int temp = arr[i];
arr[i] = arr[arr[i] - 1];
arr[temp - 1] = temp;
}
}
// 如果某个数字不在对应的位置上
// 它就是缺失的数字
for (int i = 1; i <= n; i++) {
if (i != arr[i - 1]) {
return i;
}
}
// 如果 1 到 n 的所有数字都存在
// 那么 n + 1 就是最小的缺失正整数
return n + 1;
}
public static void main(String[] args) {
int[] arr = {2, -3, 4, 1, 1, 7};
System.out.println(missingNumber(arr));
}
}
4. Pyton
def missingNumber(arr):
n = len(arr)
for i in range(n):
# 如果 arr[i] 在 1 到 n 的范围内
# 且没有放在 (arr[i]-1) 下标处
while 1 <= arr[i] <= n and arr[i] != arr[arr[i] - 1]:
# 交换 arr[i] 和 arr[arr[i]-1]
# 将 arr[i] 放到它对应的正确位置
temp = arr[i]
arr[i] = arr[arr[i] - 1]
arr[temp - 1] = temp
# 如果某个数字不在对应的位置上
# 它就是缺失的数字
for i in range(1, n + 1):
if i != arr[i - 1]:
return i
# 如果 1 到 n 的所有数字都存在
# 那么 n + 1 就是最小的缺失正整数
return n + 1
if __name__ == '__main__':
arr = [2, -3, 4, 1, 1, 7]
print(missingNumber(arr))
5. C#
using System;
class GfG {
static int missingNumber(int[] arr) {
int n = arr.Length;
for (int i = 0; i < n; i++) {
// 如果 arr[i] 在 1 到 n 的范围内
// 且没有放在 (arr[i]-1) 下标处
while (arr[i] >= 1 && arr[i] <= n
&& arr[i] != arr[arr[i] - 1]) {
// 交换 arr[i] 和 arr[arr[i]-1]
// 将 arr[i] 放到它对应的正确位置
int temp = arr[i];
arr[i] = arr[arr[i] - 1];
arr[temp - 1] = temp;
}
}
// 如果某个数字不在对应的位置上
// 它就是缺失的数字
for (int i = 1; i <= n; i++) {
if (i != arr[i - 1]) {
return i;
}
}
// 如果 1 到 n 的所有数字都存在
// 那么 n + 1 就是最小的缺失正整数
return n + 1;
}
static void Main() {
int[] arr = { 2, -3, 4, 1, 1, 7 };
Console.WriteLine(missingNumber(arr));
}
}
6. JavaScript
function missingNumber(arr) {
let n = arr.length;
for (let i = 0; i < n; i++) {
// 如果 arr[i] 在 1 到 n 的范围内
// 且没有放在 (arr[i]-1) 下标处
while (arr[i] >= 1 && arr[i] <= n
&& arr[i] !== arr[arr[i] - 1]) {
// 交换 arr[i] 和 arr[arr[i]-1]
// 将 arr[i] 放到它对应的正确位置
let temp = arr[i];
arr[i] = arr[arr[i] - 1];
arr[temp - 1] = temp;
}
}
// 如果某个数字不在对应的位置上
// 它就是缺失的数字
for (let i = 1; i <= n; i++) {
if (i !== arr[i - 1]) {
return i;
}
}
// 如果 1 到 n 的所有数字都存在
// 那么 n + 1 就是最小的缺失正整数
return n + 1;
}
let arr = [2, -3, 4, 1, 1, 7];
console.log(missingNumber(arr));
(三) 代码输出和算法复杂度
输出:
3
时间复杂度:O(n)
空间复杂度:O(1)
五、【替代解法-1】通过取反数组元素 —— 时间复杂度 O (n),空间复杂度 O (1)
(一) 解法思路
首先将所有正整数移动到数组的左侧。然后,对于左侧的有效区间,通过将下标为 val - 1 的元素取反,来标记数值 val(满足 1 ≤ val ≤ k)已经出现过。这种标记方式能帮我们确定哪些数字是存在的。最后,遍历标记后的区间,找到第一个仍为正数的下标,这个位置就代表最小的缺失正整数。如果所有位置都被标记(取反),那么缺失的数字就是 k + 1。
(二) 使用6种语言实现
1. C++
#include <iostream>
#include <vector>
using namespace std;
int partition(vector<int> &arr) {
int pivotIdx = 0;
int n = arr.size();
for (int i = 0; i < n; i++) {
// 将正数移动到数组左侧
if (arr[i] > 0) {
swap(arr[i], arr[pivotIdx]);
pivotIdx++;
}
}
// 返回第一个非正数的下标
return pivotIdx;
}
int missingNumber(vector<int> &arr) {
int k = partition(arr);
// 遍历数组的正数部分
for (int i = 0; i < k; i++) {
// 取绝对值获取原始数值
int val = abs(arr[i]);
// 如果 val 在有效范围内,将下标 val-1 处的元素标记为负数
if (val - 1 < k && arr[val - 1] > 0) {
arr[val - 1] = -arr[val - 1];
}
}
// 查找第一个未被标记的正数下标
for (int i = 0; i < k; i++) {
if (arr[i] > 0) {
return i + 1;
}
}
// 如果 1 到 k 的所有数字都已标记
// 那么缺失的数字就是 k + 1
return k + 1;
}
int main() {
vector<int> arr = {2, -3, 4, 1, 1, 7};
cout << missingNumber(arr);
return 0;
}
2. C
#include <stdio.h>
int partition(int *arr, int n) {
int pivotIdx = 0;
for (int i = 0; i < n; i++) {
// 将正数移动到数组左侧
if (arr[i] > 0) {
int temp = arr[i];
arr[i] = arr[pivotIdx];
arr[pivotIdx] = temp;
pivotIdx++;
}
}
// 返回第一个非正数的下标
return pivotIdx;
}
int missingNumber(int *arr, int n) {
int k = partition(arr, n);
// 遍历数组的正数部分
for (int i = 0; i < k; i++) {
// 取绝对值获取原始数值
int val = abs(arr[i]);
// 如果 val 在有效范围内,将下标 val-1 处的元素标记为负数
if (val - 1 < k && arr[val - 1] > 0) {
arr[val - 1] = -arr[val - 1];
}
}
// 查找第一个未被标记的正数下标
for (int i = 0; i < k; i++) {
if (arr[i] > 0) {
return i + 1;
}
}
// 如果 1 到 k 的所有数字都已标记
// 那么缺失的数字就是 k + 1
return k + 1;
}
int main() {
int arr[] = {2, -3, 4, 1, 1, 7};
int n = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", missingNumber(arr, n));
return 0;
}
3. Java
import java.util.Arrays;
class DSA {
static int partition(int[] arr) {
int pivotIdx = 0;
int n = arr.length;
for (int i = 0; i < n; i++) {
// 将正数移动到数组左侧
if (arr[i] > 0) {
int temp = arr[i];
arr[i] = arr[pivotIdx];
arr[pivotIdx] = temp;
pivotIdx++;
}
}
// 返回第一个非正数的下标
return pivotIdx;
}
static int missingNumber(int[] arr) {
int k = partition(arr);
// 遍历数组的正数部分
for (int i = 0; i < k; i++) {
// 取绝对值获取原始数值
int val = Math.abs(arr[i]);
// 如果 val 在有效范围内,将下标 val-1 处的元素标记为负数
if (val - 1 < k && arr[val - 1] > 0) {
arr[val - 1] = -arr[val - 1];
}
}
// 查找第一个未被标记的正数下标
for (int i = 0; i < k; i++) {
if (arr[i] > 0) {
return i + 1;
}
}
// 如果 1 到 k 的所有数字都已标记
// 那么缺失的数字就是 k + 1
return k + 1;
}
public static void main(String[] args) {
int[] arr = {2, -3, 4, 1, 1, 7};
System.out.println(missingNumber(arr));
}
}
4. Python
def partition(arr):
pivotIdx = 0
n = len(arr)
for i in range(n):
# 将正数移动到数组左侧
if arr[i] > 0:
arr[i], arr[pivotIdx] = arr[pivotIdx], arr[i]
pivotIdx += 1
# 返回第一个非正数的下标
return pivotIdx
def missingNumber(arr):
k = partition(arr)
# 遍历数组的正数部分
for i in range(k):
# 取绝对值获取原始数值
val = abs(arr[i])
# 如果 val 在有效范围内,将下标 val-1 处的元素标记为负数
if val - 1 < k and arr[val - 1] > 0:
arr[val - 1] = -arr[val - 1]
# 查找第一个未被标记的正数下标
for i in range(k):
if arr[i] > 0:
return i + 1
# 如果 1 到 k 的所有数字都已标记
# 那么缺失的数字就是 k + 1
return k + 1
if __name__ == "__main__":
arr = [2, -3, 4, 1, 1, 7]
print(missingNumber(arr))
5. C#
using System;
class DSA {
static int Partition(int[] arr) {
int pivotIdx = 0;
int n = arr.Length;
for (int i = 0; i < n; i++) {
// 将正数移动到数组左侧
if (arr[i] > 0) {
int temp = arr[i];
arr[i] = arr[pivotIdx];
arr[pivotIdx] = temp;
pivotIdx++;
}
}
// 返回第一个非正数的下标
return pivotIdx;
}
static int missingNumber(int[] arr) {
int k = Partition(arr);
// 遍历数组的正数部分
for (int i = 0; i < k; i++) {
// 取绝对值获取原始数值
int val = Math.Abs(arr[i]);
// 如果 val 在有效范围内,将下标 val-1 处的元素标记为负数
if (val - 1 < k && arr[val - 1] > 0)
arr[val - 1] = -arr[val - 1];
}
// 查找第一个未被标记的正数下标
for (int i = 0; i < k; i++) {
if (arr[i] > 0) {
return i + 1;
}
}
// 如果 1 到 k 的所有数字都已标记
// 那么缺失的数字就是 k + 1
return k + 1;
}
static void Main() {
int[] arr = { 2, -3, 4, 1, 1, 7 };
Console.WriteLine(missingNumber(arr));
}
}
6. JavaScript
function partition(arr) {
let pivotIdx = 0;
const n = arr.length;
for (let i = 0; i < n; i++) {
// 将正数移动到数组左侧
if (arr[i] > 0) {
[arr[i], arr[pivotIdx]] = [arr[pivotIdx], arr[i]];
pivotIdx++;
}
}
// 返回第一个非正数的下标
return pivotIdx;
}
function missingNumber(arr) {
const k = partition(arr);
// 遍历数组的正数部分
for (let i = 0; i < k; i++) {
// 取绝对值获取原始数值
const val = Math.abs(arr[i]);
// 如果 val 在有效范围内,将下标 val-1 处的元素标记为负数
if (val - 1 < k && arr[val - 1] > 0) {
arr[val - 1] = -arr[val - 1];
}
}
// 查找第一个未被标记的正数下标
for (let i = 0; i < k; i++) {
if (arr[i] > 0) {
return i + 1;
}
}
// 如果 1 到 k 的所有数字都已标记
// 那么缺失的数字就是 k + 1
return k + 1;
}
// 测试代码
const arr = [2, -3, 4, 1, 1, 7];
console.log(missingNumber(arr));
(三) 代码输出和算法复杂度
输出:
3
时间复杂度:O(n)
空间复杂度:O(1)
六、【替代解法-2】通过标记索引 —— 时间复杂度 O (n),空间复杂度 O (1)
(一) 解法思路
首先检查数组中是否包含数字 1,如果不包含,答案就是 1。如果包含,就将所有超出范围 [1, n] 的数字替换为 1。接着再次遍历数组,通过在下标 x-1 处加上 n 的方式,标记每个数字 x 已经出现。最后再次遍历数组,查找第一个未被标记的下标,该位置对应的就是缺失的数字。
(二) 使用6种语言实现
1. C++
#include <iostream>
#include <vector>
using namespace std;
int missingNumber(vector<int> &arr) {
int n = arr.size();
bool flag = false;
// 检查数组中是否包含数字 1
for (int i = 0; i < n; i++) {
if (arr[i] == 1) {
flag = true;
break;
}
}
// 如果不存在 1,直接返回 1
if (flag == false)
return 1;
// 将所有超出范围的数替换为 1
for (int i = 0; i < n; i++) {
if (arr[i] <= 0 || arr[i] > n)
arr[i] = 1;
}
// 在数组内直接标记数字出现过
for (int i = 0; i < n; i++) {
arr[(arr[i] - 1) % n] += n;
}
// 查找第一个值小于等于 n 的下标
for (int i = 0; i < n; i++) {
if (arr[i] <= n)
return i + 1;
}
// 如果数组包含 1 到 n 的所有数字
return n + 1;
}
int main() {
vector<int> arr = {2, -3, 4, 1, 1, 7};
cout << missingNumber(arr);
return 0;
}
2. C
#include <stdio.h>
int missingNumber(int arr[], int n) {
int flag = 0;
// 检查数组中是否包含数字 1
for (int i = 0; i < n; i++) {
if (arr[i] == 1) {
flag = 1;
break;
}
}
// 如果不存在 1,直接返回 1
if (flag == 0)
return 1;
// 将所有超出范围的数替换为 1
for (int i = 0; i < n; i++) {
if (arr[i] <= 0 || arr[i] > n)
arr[i] = 1;
}
// 在数组内直接标记数字出现过
for (int i = 0; i < n; i++) {
arr[(arr[i] - 1) % n] += n;
}
// 查找第一个值小于等于 n 的下标
for (int i = 0; i < n; i++) {
if (arr[i] <= n)
return i + 1;
}
// 如果数组包含 1 到 n 的所有数字
return n + 1;
}
int main() {
int arr[] = {2, -3, 4, 1, 1, 7};
int n = sizeof(arr) / sizeof(arr[0]);
printf("%d", missingNumber(arr, n));
return 0;
}
3. Java
import java.util.*;
class DSA {
static int missingNumber(int[] arr) {
int n = arr.length;
boolean flag = false;
// 检查数组中是否包含数字 1
for (int i = 0; i < n; i++) {
if (arr[i] == 1) {
flag = true;
break;
}
}
// 如果不存在 1,直接返回 1
if (!flag)
return 1;
// 将所有超出范围的数替换为 1
for (int i = 0; i < n; i++) {
if (arr[i] <= 0 || arr[i] > n)
arr[i] = 1;
}
// 在数组内直接标记数字出现过
for (int i = 0; i < n; i++) {
arr[(arr[i] - 1) % n] += n;
}
// 查找第一个值小于等于 n 的下标
for (int i = 0; i < n; i++) {
if (arr[i] <= n)
return i + 1;
}
// 如果数组包含 1 到 n 的所有数字
return n + 1;
}
public static void main(String[] args) {
int[] arr = {2, -3, 4, 1, 1, 7};
System.out.println(missingNumber(arr));
}
}
4. Python
def missingNumber(arr):
n = len(arr)
flag = False
# 检查数组中是否包含数字 1
for i in range(n):
if arr[i] == 1:
flag = True
break
# 如果不存在 1,直接返回 1
if not flag:
return 1
# 将所有超出范围的数替换为 1
for i in range(n):
if arr[i] <= 0 or arr[i] > n:
arr[i] = 1
# 在数组内直接标记数字出现过
for i in range(n):
arr[(arr[i] - 1) % n] += n
# 查找第一个值小于等于 n 的下标
for i in range(n):
if arr[i] <= n:
return i + 1
# 如果数组包含 1 到 n 的所有数字
return n + 1
if __name__ == "__main__":
arr = [2, -3, 4, 1, 1, 7]
print(missingNumber(arr))
5. C#
using System;
class DFA {
static int missingNumber(int[] arr) {
int n = arr.Length;
bool flag = false;
// 检查数组中是否包含数字 1
for (int i = 0; i < n; i++) {
if (arr[i] == 1) {
flag = true;
break;
}
}
// 如果不存在 1,直接返回 1
if (!flag)
return 1;
// 将所有超出范围的数替换为 1
for (int i = 0; i < n; i++) {
if (arr[i] <= 0 || arr[i] > n)
arr[i] = 1;
}
// 在数组内直接标记数字出现过
for (int i = 0; i < n; i++) {
arr[(arr[i] - 1) % n] += n;
}
// 查找第一个值小于等于 n 的下标
for (int i = 0; i < n; i++) {
if (arr[i] <= n)
return i + 1;
}
// 如果数组包含 1 到 n 的所有数字
return n + 1;
}
static void Main() {
int[] arr = {2, -3, 4, 1, 1, 7};
Console.WriteLine(missingNumber(arr));
}
}
6. JavaScript
function missingNumber(arr) {
let n = arr.length;
let flag = false;
// 检查数组中是否包含数字 1
for (let i = 0; i < n; i++) {
if (arr[i] === 1) {
flag = true;
break;
}
}
// 如果不存在 1,直接返回 1
if (!flag) return 1;
// 将所有超出范围的数替换为 1
for (let i = 0; i < n; i++) {
if (arr[i] <= 0 || arr[i] > n) arr[i] = 1;
}
// 在数组内直接标记数字出现过
for (let i = 0; i < n; i++) {
arr[(arr[i] - 1) % n] += n;
}
// 查找第一个值小于等于 n 的下标
for (let i = 0; i < n; i++) {
if (arr[i] <= n) return i + 1;
}
// 如果数组包含 1 到 n 的所有数字
return n + 1;
}
let arr = [2, -3, 4, 1, 1, 7];
console.log(missingNumber(arr));
(三) 代码输出和算法复杂度
输出:
3
时间复杂度:O(n)
空间复杂度:O(1)

更多推荐
所有评论(0)