AcWing15:不修改数组找出重复的数字

Posted 劭兮劭兮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AcWing15:不修改数组找出重复的数字相关的知识,希望对你有一定的参考价值。

问题

原题链接

原题链接不修改数组找出重复的数字

个人思路

自己思路

双层for循环,把整个数组遍历一遍,每一个元素都与其后面的元素比较,如果有相等的元素,结束循环;

java实现
class Solution 
    // public int duplicateInArray(int[] nums) 
        
    // 
    
    public static void main(String[] args) 
		int[] nums = 2,3,5,4,3,2,6,7;
		duplicateInArray(nums);
	
	
	public static int duplicateInArray(int[] nums) 
		int temp=0;
		
        for(int i = 0;i<nums.length-1;i++) 
        	for(int j=i+1;j<nums.length;j++) 
        		if(nums[i] == nums[j]) 
        			temp = nums[i];
        		
        	
        
        return temp;
    

大佬思路

(自己的解题思路比较菜,所以一般会学习一下大佬的思路)

(分治,抽屉原理) O(nlogn)
抽屉原理:n+1 个苹果放在 n 个抽屉里,那么至少有一个抽屉中会放两个苹果。
一共有 n+1 个数,每个数的取值范围是1到n,所以至少会有一个数出现两次。
采用分治的思想,将每个数的取值的区间[1, n]划分成[1, (n+1)/2]和[(n+1)/2+1, n]两个子区间,然后分别统计两个区间中数的个数。
注意:这里的区间是指 数的取值范围,而不是 数组下标。

划分之后,左右两个区间里一定至少存在一个区间,区间中数的个数大于区间长度。(这个可以用反证法来说明:如果两个区间中数的个数都小于等于区间长度,那么整个区间中数的个数就小于等于n,和有n+1个数矛盾。)

因此我们可以把问题划归到左右两个子区间中的一个,而且由于区间中数的个数大于区间长度,根据抽屉原理,在这个子区间中一定存在某个数出现了两次。

依次类推,每次我们可以把区间长度缩小一半,直到区间长度为1时,我们就找到了答案。

复杂度分析

  • 时间复杂度:每次会将区间长度缩小一半,一共会缩小 O(logn)次;每次统计两个子区间中的数时需要遍历整个数组,时间复杂度是O(n) ; 所以总时间复杂度是 O(nlogn)。
  • 空间复杂度:代码中没有用到额外的数组,所以额外的空间复杂度是 O(1)O(1)。
JAVA实现一
class Solution 
    
    public static void main(String[] args) 
		int[] nums = 2,3,5,4,3,2,6,7;
		duplicateInArray(nums);
	
	
	public static int duplicateInArray(int[] nums) 
		
		int start = 1;
		int end = nums.length-1;
		while(start<end) 
			int mid = (end+start)/2;	
			int count=0;
	        for(int i = 0;i<nums.length;i++) 
	        	if(nums[i]>=start && nums[i]<=mid) 
	        		count++;
	        	
	        
	        if(count > mid-start+1) 
	        	end = mid;
	        else 
	        	start = mid + 1;
	        
		
        return end;
    


JAVA实现二
class Solution 
    
    public static void main(String[] args) 
		int[] nums = 2,3,5,4,3,2,6,7;
		duplicateInArray(nums);
	
	
	public static int duplicateInArray(int[] nums) 
		
		int start = 1;
		int end = nums.length-1;
		while(start<end) 
			int mid = (end+start)/2;	
			int count=0;
	        for(int i = 0;i<nums.length;i++) 
	        	if(nums[i]<=end && nums[i]>=mid+1) 
	        		count++;
	        	
	        
	        if(count > end-mid) 
	        	start = mid + 1;
	        else 
	        	end = mid;
	        
		
        return end;
    


C++实现
class Solution 
public:
    int duplicateInArray(vector<int>& nums) 
        int start = 1,end = nums.size()-1;
		while(start < end)
			int mid = (start + end)/2;
			int count = 0;
			for(auto x : nums)
				if(x>=start && x<=mid)
					count++;
				
			
			if(count > mid - start +1)
				end = mid;
			else
				start = mid+1;
			
		
		return start; 
    
;
C实现
int duplicateInArray(int *nums, int numsSize)
    int start = 1;
    int end = numsSize -1;
    while(start<end)
    	int mid = (start+end)/2;
    	int count = 0;
    	for(int i=0;i<numsSize;i++)
    		if(nums[i] >= mid+1 && nums[i] <= end)
    			count++;
			
		
		if(count > end - mid)
			start = mid+1;
		else
			end = mid;
		
	
	return start;

小记:
原题链接:不修改数组找出重复的数字

以上是关于AcWing15:不修改数组找出重复的数字的主要内容,如果未能解决你的问题,请参考以下文章

剑指Offer打卡目录(Java实现)

AcWing14:找出数组中重复的数字

ACwing13题

面试题3:不修改数组找出重复的数字

不修改数组找出重复的数字

不修改数组找出重复的数字(c语言)