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题

《剑指Offer——不修改数组找出重复的数字》代码

[题目2]不修改数组找出重复的数字

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