(no.23) Find the Duplicate Number 多种方法探讨
来源:互联网 发布:ipad有淘宝卖家版吗 编辑:程序博客网 时间:2024/06/05 06:23
题目描述
分析实现 法一
若不考虑空间复杂度必须为O(1)的条件,在满足1、3、4的条件下,对于找寻重复的数字来说,很简便的一种方法就是映射。将元素值作为新开数组的下标,进行出现次数的统计。
class Solution {public: int findDuplicate(vector<int>& nums) { int len=nums.size()+1; vector<int> log(len,0); int result=0; for(int i=0;i<len;i++){ log[nums[i]]++; } for(int i=0;i<len;i++){ if(log[i]>1){ result=i; break; } } return result; }};
分析实现 法二
现在,我们需要考虑空间复杂度必须为O(1)的条件,也即需要写出一个满足上述四个条件的代码,怎么入手呢?回顾法一,其成功在于以重复数字作为下标的元素被累加了两次及其以上,我们找到元素值大于1的,也就找到了重复数字。可是现在,不能创建个以N为大小的数组呀,我们怎样才能抓住下标元素被累加到了两次及其以上呢?
因为有重复的数字,那么对于value初始化为0,value = nums[value]来说,value会最终陷在一个循环里。如nums={1,3,4,2,2},那么value=1,3,2,4,2,4,2,4,…..。而这个循环里,就有我们的重复数字。
那现在问题就变为如何发现这个循环,并且如何从循环里拿到重复数字。所以便有了下面的代码:
class Solution {public: int findDuplicate(vector<int>& nums){ if (nums.size() > 1){ //开始起跑,slow一步一步跑,fast两步并一步跑 int slow = nums[0]; int fast = nums[nums[0]]; //确定它俩陷在了循环里 while (slow != fast){ slow = nums[slow]; fast = nums[nums[fast]]; } //fast重新开始一步一步地起跑,当与陷入循环里的slow相遇时,即为所求 fast = 0; while (fast != slow){ fast = nums[fast]; slow = nums[slow]; } return slow; } return -1; } };
法2 细节说明
这里我们引入另一个加速的循环,value = nums[nums[value]],如此,通过两个循环的碰撞便能发现了循环并拿到重复的元素。那为什么这两个循环一定会相撞呢?我们用物理学里的速度路程(s=vt)来论证。
我们把慢的循环叫slow,快的循环叫fast。因为是循环永无止境,所以追踪的路程s可以无限大。
现在,想让fast追上slow,fast的速度为vf,slow的速度为vs(vs结合本题的意思就是value = nums[value]计算一次),并且vf=2*vs。我们可以列出公式,vs*t=vf*t+dis。其中dis为一开始slow和fast相隔的距离。
从而,我们可以解出t=dis/vs。
现来看dis的取值,slow和fast最多相距n的距离。综上,它们一定会相撞。因为从物理学中知道,路程无限的条件下,快速度的一定会追上慢速度的。并且只要在O(n)的时间复杂度下,我们就能让两个循环相撞了。
分析实现 法3
之所以会想到法2,是受法1映射的思想影响。现在,我们从中跳出来,看看还有没有其他的办法。分治法。
我们要充分利用题目给的条件,“Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive)”
n+1个数,每个数的值还只能是从1到n中取,那么我随便说一个1到n中的数,如果数组中小于等于它的数的个数竟然大于该数值本身,那么肯定是有重复的。
举个例子,nums={4,3,6,5,4,1,2},我随便说个数:5,那么nums中小于等于5的元素个数为6,说明Duplicate Number的值比5小,就是因为Duplicate Number,才会造成数量反超的局面。
代码实现如下,使用二分搜索连缩小范围,
class Solution {public:int findDuplicate(vector<int>& nums){ int len=nums.size(); int low=1; int high=len-1; int mid,count; while(low<high){ mid=low+(high-low)/2; count=0; for(int i=0;i<len;i++){ if(nums[i]<=mid) //统计小于mid的元素个数 count++; } if(count<=mid) low=mid+1; else //说明有元素重复了不止一次 high=mid; } return low;}};
- (no.23) Find the Duplicate Number 多种方法探讨
- LeetCode No.287 Find the Duplicate Number
- Find the Duplicate Number
- Find the Duplicate Number
- Find the Duplicate Number
- Find the Duplicate Number
- Find the Duplicate Number
- Find the Duplicate Number
- Find the Duplicate Number
- Find the Duplicate Number
- Find the Duplicate Number
- Find the Duplicate Number
- Find the Duplicate Number
- Find The Duplicate Number
- Find the Duplicate Number
- Find the Duplicate Number
- Find the Duplicate Number
- Find the Duplicate Number
- 安卓复杂滑动案例 自定义behavior源码分析 实现头布局图片的缩放透明度变化,RecycleView的滑动布局,坐标变化
- LeetCode 62. Unique Paths
- linux云计算之Bashshell脚本编程视频教程!
- CMSeasy短信接口替换
- CLOB/BLOB与String互转。
- (no.23) Find the Duplicate Number 多种方法探讨
- 记录kolla实践历程
- java的>>和>>>右移运算符讲解
- Error500错误的解决方法
- robots.txt SEO 与搜索引擎
- Android中Fragment的懒加载
- Java JDK和eclipse
- jobdu 题目1153:括号匹配问题
- 捡拾日记:闭锁、栅栏