一、题目
给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。
示例 1:
输入:nums = [4,3,2,7,8,2,3,1] 输出:[5,6]
示例 2:
输入:nums = [1,1] 输出:[2]
提示:
n == nums.length
1 <= n <= 105
1 <= nums[i] <= n
进阶:你能在不使用额外空间且时间复杂度为 O(n)
的情况下解决这个问题吗? 你可以假定返回的数组不算在额外空间内。
二、代码
class Solution {
public List<Integer> findDisappearedNumbers(int[] nums) {
// 要返回的答案
List<Integer> ans = new ArrayList<>();
// 过滤无效参数
if (nums == null || nums.length == 0) {
return ans;
}
for (int i = 0; i < nums.length; i++) {
// 从i位置出发,去做下标循环移动
walk(nums, i);
}
// 完成下标循环后,所有不满足要求的位置,就是缺少这个位置上应该放置的数字
// 因为完成下标循环后,就将所有的数都放到他应该放的位置了,剩下的就都是缺少的数字了
for (int i = 0; i < nums.length; i++) {
if (nums[i] != i + 1) {
ans.add(i + 1);
}
}
return ans;
}
public void walk(int[] nums, int i) {
// 整个流程其实是固定在i下标来进行的
// 将每一个不符合nums[i] == i + 1的数都交换到i位置来进行操作
// 所以这个循环是数字移动,但是下标不动
while (nums[i] != i + 1) {
// 此时i下标位置的数一定是不满足nums[i] == i + 1的
// 计算nums[i]这个数本来应该在什么下标位置 nums[i] == nexti + 1
int nexti = nums[i] - 1;
// 如果nexti位置的数已经符合要求了,那么本轮下标循环移动就结束了
if (nums[nexti] == nexti + 1) {
break;
}
// nexti位置的数字也不符合要求,那么我们就把i位置的数字交换到nexti位置上,这样原本i位置上的数字就合法了
// 将原本nexti位置上不合法的数字转移到i位置,再继续对i位置上新来的数字进行下标循环
swap(nums, i, nexti);
}
}
// 交换
public void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
三、解题思路
力争做到,i位置上放i+1。
时间复杂度O(1),额外空间复杂度O(1)