《剑指Offer》-3-数组中重复的数字
思路
题目很简单,有多种思路可以实现
- 最直接的可以嵌套两个 for 循环,挨个与后面所有的元素比,返回第一个重复的数字,缺点是时间复杂度
O(N^2^)
- 可以利用数据结构,比如 set ,遍历一遍,不存在就往里面放,存在就返回,时间
O(N)
、空间O(N)
- 有没有时间
O(N)
,空间O(1)
的做法?
我觉得这道题完全可以出难一点,可以返回有哪些数字重复了,分别重复了几次
经评论区提醒,或许考察的是与面试官的沟通能力,对不同解法的衡量取舍:
比如时间优先可以用 set 轻松解决,也只需要一次遍历,如果是进阶要求可以用hashmap记录次数,再遍历map输出
O(1)空间复杂度就原地排序,然后再遍历一遍输出第一个重复的,我第一个想到的是快排,当然也可以直接sort()
《剑指Offer》上给出的巧妙解法是利用数组下标和交换,当然这里的前提是所有数字都在 0~n-1 的范围内
长度为 n 的数组,且所有数字的范围都在 0~n-1范围内,在没有重复的情况下,那么正好可以将每个数字和下标建立映射关系:数字==下标,且正好一一对应
但是,题目中是存在重复数字的,而且不知道有几个数字是重复的,也不知道每个数字重复几次
所以,如果仍旧按照原本的映射关系来看,必然是有位置映射为空,有的位置映射2个或者2个以上
我们这么做:
- 遍历整个数组,通过交换位置来将映射关系建立起来,使数字一一归位
- 检查 i 与 nums[i],如果相等说明i已经之它应在的位置了
- 如果不相等,说明需要移动,再检查 nums[i] 和 nums[nums[i]]
- 如果不相等,就交换,将i归位,放到他应该在的地方
- 如果相等,说明它应该在的位置已经有元素了,(而且不能是它本身),即:重复了
看起来效果很棒
int findRepeatNumber(vector<int>& nums) { int res = nums[0]; int i = 0; while (i < nums.size()) { if (i != nums[i]) { if (nums[nums[i]] != nums[i]) { swap(nums[i], nums[nums[i]]); } else { res = nums[i]; break; } } else i++; } return res; }
本文作者:YaosGHC
本文链接:https://www.cnblogs.com/yaocy/p/17095012.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步