笔试面试题目:求逃跑的猪猪们

本文,我们还是来聊面试问题。在之前的文章中,我们讨论过一个简单的题目: 求丢失的猪。

当时,题目中已经表明,只有一头猪丢失了。这种情况下,用异或是最佳算法,而且很好懂。

但是,如果逃跑的猪是多头呢?如何才能知道逃跑的猪猪们的编号?且看具体题目场景叙述。

图片

题目场景如下:

有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的每个元素。

  1. 针对4,令a[3]为负,即a[3]=-7,所以,下次看到-7时,就知道4是存在的。

  2. 针对3,令a[2]为负,即a[2]=-2,所以,下次看到-2时,就知道3是存在的。

  3. 针对2,令a[1]为负,即a[1]=-3,所以,下次看到-3时,就知道2是存在的。

  4. 针对-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:

图片

实话说,如果完全没有见过这种思路,要在面试现场想出这种解法,几乎不太可能。但如果看过我前面文章,是能发现这种巧妙方法的。

腾讯、阿里、字节跳动的面试题,很难当场想出解法。所以,题还是要刷。刷题比刷抖音有趣多了,能培养和拓展思维,预防脑袋生锈。

最后,希望大家在刷题中,找到乐趣,你会感叹原来还能这样啊,顺便地,能拿到更好的offer,工资翻倍,福利多多,祝大家面试顺利。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值