
作者 | 涛歌依旧 责编 | 张文
来源 | 转载自涛歌依旧(ID:ai_taogeyijiu_2021)
在之前的文章中,我们讨论过一个简单的题目: 求丢失的猪。
当时,题目中已经表明,只有一头猪丢失了。这种情况下,用异或是最佳算法,而且很好懂。
但是,如果逃跑的猪是多头呢?如何才能知道逃跑的猪猪们的编号?且看具体题目场景叙述。

题目场景如下:
有 n 只公猪,用车拉到菜市场去卖,猪身上分别贴了 1~n 的编号。发车之前,有些公猪的老婆流泪了,希望和猪老公一起上车,并和猪老公贴了相同编号。
车开到半路,突然,有些猪开始打歪主意了,想跳车逃跑。逃跑的规律是:单身公猪可以单独跳车逃跑,夫妻猪要么一起留在车上,要么同时跳车逃跑。
到了菜市场后,主人发现,有些猪逃跑了,震惊不已,想找出所有逃跑的公猪的编号。要求:时间复杂度为 O(n), 空间复杂度为 O(1),试编写代码求解。

天网恢恢,疏而不漏,这猪还是挺可怜的,逃跑了也要被查。
我们来具体看看是什么意思。假设到菜市场后,剩下的猪猪的编号是:
a = [4, 3, 2, 7, 8, 2, 3, 1]
那么很显然,溜走的公猪的编码是 5 和 6, 至于 5 和 6 是否有老婆,不得而知,也不必知。
显然,当猪猪很少时,用肉眼便知逃跑的猪猪。但是,当猪猪很多时,肉眼肯定看不出来。
由于车上就那么大点空间,所以要在空间复杂度为 O(1)的要求下解决问题,而且时间复杂度要求为 O(n).

有的朋友说,直接哈希表搞定,这显然不行,因为空间复杂度不符合的要求。
有的朋友说,排序一下就搞定,这显然也不行啊,因为时空复杂度不符合要求。
那怎么办呢?确实挺难的,但也不是不可能,采取的思路是:用负号标识存在性。即用 a[x-1]的负号,来标识 x 的存在性。如下表:
4 | 3 | 2 | 7 | 8 | 2 | 3 | 1 |
4 | 3 | 2 | -7 | 8 | 2 | 3 | 1 |
4 | 3 | -2 | -7 | 8 | 2 | 3 | 1 |
4 | -3 | -2 | -7 | 8 | 2 | 3 | 1 |
4 | -3 | -2 | -7 | 8 | 2 | -3 | 1 |
4 | -3 | -2 | -7 | 8 | 2 | -3 | -1 |
4 | -3 | -2 | -7 | 8 | 2 | -3 | -1 |
4 | -3 | -2 | -7 | 8 | 2 | -3 | -1 |
-4 | -3 | -2 | -7 | 8 | 2 | -3 | -1 |
有的朋友看到这里,依然很懵圈,不用着急,且听我解释,咱们来遍历数组 a 的每个元素。
针对 4,令 a[3]为负,即 a[3]=-7,所以,下次看到-7 时,就知道 4 是存在的。
针对 3,令 a[2]为负,即 a[2]=-2,所以,下次看到-2 时,就知道 3 是存在的。
针对 2,令 a[1]为负,即 a[1]=-3,所以,下次看到-3 时,就知道 2 是存在的。
略
略
略
略
针对-1, 知其原身必然是 1,故令 a[0]为负,即 a[0]=-4,所以,下次看到-4 时候,就知道 1 是存在的。
可以看到,a 数组的最后值是:
a = [-4, -3, -2, -7, 8, 2, -3, -1]
最后只有 8 和 2 是正数,而 8 和 2 的下标位置分是 4 和 5, 也就是说 x-1 的值是 4 和 5,所以 x 的值就是 5 和 6, 即 5 和 6 没有出现过,所以逃跑的公猪猪是 5 和 6.
确实挺巧妙,本质就是:用 a[x-1]的负号,来标识 x 的存在性。
话不多说,来看代码:
func findDisappearedNumbers(a []int) []int {
len := len(a)
var results []int
for i := 0; i < len; i++ {
if (a[taogeAbs(a[i]) - 1] > 0) {
a[taogeAbs(a[i]) - 1] = - a[taogeAbs(a[i]) - 1];
}
}
for i := 0; i < len; i++ {
if (a[i] > 0) {
results = append(results, i + 1)
}
}
return results
}
func taogeAbs(x int) int {
if x < 0 {
return -x
}
return x
}
在 leetcode 上进行了自测验证,结果 OK,能找出逃掉的公猪,以本文中的 a 数组为例,得到逃跑的公猪是 5 和 6:

实话说,如果完全没有见过这种思路,要在面试现场想出这种解法,几乎不太可能。所以还是要多刷题。

程序员如何避免陷入“内卷”、选择什么技术最有前景,中国开发者现状与技术趋势究竟是什么样?快来参与「2020 中国开发者大调查」,更有丰富奖品送不停!

☞腾讯、字节跳动展开拉锯战;网易云音乐称酷狗抄袭;谷歌不再开发云游戏 | 极客头条
☞估值飙至 280 亿美元,Databricks G 轮融资 10 亿美元,谁说开源不挣钱?
☞开源 = 打破商业垄断?
☞三年已投 1000 亿打造的达摩院,何以仗剑走天涯?
通过巧妙地利用数组元素的符号变化,解决了一道寻找失踪编号的问题。该问题要求在特定的时间和空间复杂度限制下,找出从集合中消失的元素。
2708

被折叠的 条评论
为什么被折叠?



