题目随便起的,
在刷力扣 41.缺失的第一个正数 这个题的时候,出现了解构赋值的问题,
对于[a,b] = [1,2]和[b,a]=[2,1]
按理说都是行的通的,和位置没有关系,本质上都是进行交换
可是当我在题目中
使用[nums[nums[i]-1], nums[i]] = [nums[i], nums[nums[i]-1]]
时是可以通过测试用例的,
使用[nums[i], nums[nums[i]-1]] = [nums[nums[i]-1], nums[i]]
会超时
41. 缺失的第一个正数
题目要求返回缺失的第一个正整数,那么我们可以采用“一个萝卜一个坑”的思想
将数组中的所有数字归位,当下标为[0,N]时,数字应该为[1,N+1]
那么数值为i的数应该放在下标为i-1的位置
比如数字:nums[i]
,它的下标应该为nums[i]-1
,
所以,反过来说,下标为nums[i]-1
的地方对应的数字应该为nums[nums[i]-1]
通过上面的推导,我们可以得出一个结论:nums[nums[i]-1] === nums[i]
于是,我们可以遍历一遍,将所有的数组交换到正确的位置,然后再进行一次遍历,找到nums[i] != i + 1
的数
var firstMissingPositive = function(nums) {
for(let i = 0; i < nums.length; i++){
while(nums[i] > 0 && nums[i] <= nums.length && nums[nums[i]-1] != nums[i] ){
// ok
const temp = nums[nums[i]-1];
nums[nums[i]-1] = nums[i];
nums[i] = temp;
// const temp = nums[i];
// nums[i] = nums[nums[i]-1];
// nums[nums[i]-1] = temp;
// [nums[i], nums[nums[i]-1]] = [nums[nums[i]-1], nums[i]]
// [nums[nums[i]-1], nums[i]] = [nums[i], nums[nums[i]-1]] ok
}
}
for(let i = 0; i < nums.length; i++){
if(nums[i] != i+1){
return i+1;
}
}
return nums.length + 1;
};
但是,[nums[i], nums[nums[i]-1]] = [nums[nums[i]-1], nums[i]]
这样写是错的
解释
首先,清楚
情况一:
const temp = nums[nums[i]-1];
nums[nums[i]-1] = nums[i];
nums[i] = temp;
// 等价于
[nums[nums[i]-1], nums[i]] = [nums[i], nums[nums[i]-1]]
情况二:
const temp = nums[i];
nums[i] = nums[nums[i]-1];
nums[nums[i]-1] = temp;
// 等价于
[nums[i], nums[nums[i]-1]] = [nums[nums[i]-1], nums[i]]
情况一:
对于情况一,
我们先暂存了 nums[nums[i]-1]
地址的值,然后更新nums[nums[i]-1]
地址的值,
因为此时nums[i]
的值没有变,所以 nums[nums[i]-1]
所指向的地址没有变,我们只是改变了该地址对应的值,
最后更新nums[i]
的值
情况二:
我们先暂存了nums[i]
的值,然后更新nums[i]
地址的值,当走到第三步更新nums[nums[i]-1]
地址的值时,因为nums[i]
的值发生了变化,那么相当于nums[nums[i]-1]这个地址发生了变化,最后我们将一个新地址的原有值改变了
而我们的初衷是交换nums[nums[i]-1]
和nums[i]
这两个地址的值,结果我们改变了一个新地址的值
画图模拟:
解决:
如果想让 [nums[i], nums[nums[i]-1]] = [nums[nums[i]-1], nums[i]]
正确表示,
可以这样:
const tmp = nums[i];
nums[i] = nums[nums[i] - 1];
nums[tmp -1] = tmp;