标签:
题目链接:https://leetcode.com/problems/find-the-duplicate-number/
题目描述:
一个数组包含n+1个数字, 这n+1个数字是1-n之间的数字,并且只有一个数字出现重复(不一定只出现2次,可能重复多次),要求不能改变数组的数字,找出重复的数字
分析:
n+1个数字包含1-n之间的数字,肯定会出现重复,如果重复的数字只出现两次,那么问题比较容易解决,只要用n+1个数字的和减去1-n个数字的和,得到的就是重复出现的数字。
但是本题中说明了出现的数字不一定出现2次,排序的方法可以再nlog(n)时间内解决,但是题目要求不能改变数组。
实际上如果可以改变数组可以用桶排序的方法在O(n)方法内解决。
或者可以用额外的内存可以用一个n+1标记数字出现的次数在O(n)方法内解决。
设置一个下标,每次下标变动为当前下标处值。如果这么不断变换的话这条转换链上除了第一个节点之外,其他节点都表示出现过一个数字(这个下标是上一个下标处的的数组值)。
假如这条转化链上存在环并且环的起点不是第一个节点的话,环的起点就是出现重复的数字。
至于怎么保证环的起点不是第一个数字,我们可以用0这个下标作为起点,应为所有的数字都是1-n所以转换链上不可能在出现0。
#include <map> #include <vector> #include <algorithm> #include <cstring> #include <cstdlib> #include <cstdio> #include <stack> #include <iostream> using namespace std; int findDuplicate(vector<int>& nums) { int len = nums.size(); if (1 == len) return nums[0]; int low = 0, fast = 0; do { low = nums[low]; fast = nums[fast]; fast = nums[fast]; } while(fast != low); low = 0; while(low != fast) low = nums[low], fast = nums[fast]; return low; } int main() { vector<int> nums; int n; //freopen("in.dat", "r", stdin); while(scanf("%d", &n) == 1) { nums.push_back(n); }; cout<<findDuplicate(nums)<<endl; return 0; }
标签:
原文地址:http://www.cnblogs.com/li-xingtao/p/4978268.html