AcWing之找出不改变数组找到重复的数字
題目
給定一個長度為 n+1 的數組nums,數組中所有的數均在 1~n 的范圍內,其中 n≥1。請找出數組中任意一個重復的數,但不能修改輸入的數組。樣例
給定 nums = [2, 3, 5, 4, 3, 2, 6, 7]。 返回 2 或 3。思考題:
如果只能使用 O(1) 的額外空間,該怎么做呢?方法一(使用了O(n)的空間):
class Solution { public:int duplicateInArray(vector<int>& nums) {int n = nums.size(); int nums2[n]={}; //用此數組類存儲重復的數字。 n個數,哪個重復 nums2[n]++ for(auto x: nums) {nums2[x]++;if(nums2[x] >= 2) {return x;}}} };方法二(時間復雜度O(n),空間復雜度O(1))
class Solution { public:int duplicateInArray(vector<int>& nums) {int l = 1, r = nums.size()-1;int mid = (l + r)/2; // 劃分的區間:[l, mid], [mid + 1, r]int s = 0;while(l<r) {for(auto x:nums) { //查看nums數組中每個數值大小在其中一個區間的個數。 如在[1, mid]中的數字有多少if (x>=l && x<=mid)s+=1;if(s>mid-l+1) r=mid;else l=mid+1;}return r; } };心得
方法一: 利用nums2數組記錄每個數的個數。 ++
方法二: 抽屜原理,逐漸縮小區間,查看n+1個空間n個數字,哪一側多一個數字。
(分治,抽屜原理) O(nlogn)O(nlogn)
這道題目主要應用了抽屜原理和分治的思想。
然后我們采用分治的思想,將每個數的取值的區間[1, n]劃分成[1, n/2]和[n/2+1, n]兩個子區間,然后分別統計兩個區間中數的個數。
注意這里的區間是指 數的取值范圍,而不是 數組下標。
劃分之后,左右兩個區間里一定至少存在一個區間,區間中數的個數大于區間長度。
這個可以用反證法來說明:如果兩個區間中數的個數都小于等于區間長度,那么整個區間中數的個數就小于等于n,和有n+1個數矛盾。
因此我們可以把問題劃歸到左右兩個子區間中的一個,而且由于區間中數的個數大于區間長度,根據抽屜原理,在這個子區間中一定存在某個數出現了兩次。
依次類推,每次我們可以把區間長度縮小一半,直到區間長度為1時,我們就找到了答案。
復雜度分析
時間復雜度:每次會將區間長度縮小一半,一共會縮小 O(logn)O(logn) 次。每次統計兩個子區間中的數時需要遍歷整個數組,時間復雜度是 O(n)O(n)。所以總時間復雜度是 O(nlogn)O(nlogn)。
空間復雜度:代碼中沒有用到額外的數組,所以額外的空間復雜度是 O(1)O(1)。
作者:yxc
鏈接:https://www.acwing.com/solution/AcWing/content/693/
來源:AcWing
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
總結
以上是生活随笔為你收集整理的AcWing之找出不改变数组找到重复的数字的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LeetCode之最大正方形
- 下一篇: AcWing之找出数组中重复的数字