¶题意
给定一个长度为$n$的数组$a$,对其中的所有正数求mex。要求时间复杂度$O(n)$,额外空间复杂度$O(1)$。
¶做法
排序,时间复杂度不行。
桶排序,空间复杂度不行。
显然只能对$a$数组本身进行原地的操作 (in place),最后希望能根据$a[i]$的取值判断出$i$是否存在于原数组中。
那就按下标顺序从小到大依次标记。设当前下标为$i$,如果$a[i]\gt i$,就先标记$a[a[i]]$,然后再覆盖$a[a[i]]$处的值来标记$a[i]$的存在;而如果$a[i]\le i$,直接对$a[a[i]]$进行标记即可。
下一个难点是用什么值来标记。显然可以取不在原数组中的任意值,但是$O(n)$算不出来,而原数组的取值范围又是整个int区间,不能用max+1,min-1这个trick。我的做法就是用n+1来标记,但需要把原数组中的n+1都先改成n+2(一开始没意识到要改,wa了一次),因为可以知道答案一定是小于等于n+1的,所以大于等于n+1的数的取值是无所谓的。
1 | class Solution { |
看了题解才意识到这是置换的做法。
此外还有一种正负的做法(或者称为哈希):显然负数是没用的,所以可以用负号作为标记的手段,与此同时绝对值保留为原取值,这样都不用担心覆盖的问题,不需要进行置换,更好写了。本质有点类似压位,反正就是在一个int的32bit里表达更多的信息。