数组中重复的数字|||数组中只出现一次的数

本文介绍两种典型数组问题的解决方法:一是如何找出数组中的任意一个重复数字,探讨了排序、哈希映射及原地置换等算法;二是如何在大多数元素重复的情况下找出仅出现一次的两个数字,利用异或操作实现高效查找。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.找出数组中重复的数字

题目描述:在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。

思路1:把数组进行排序,然后比对。改变了数组结构。

	public static ArrayList<Integer> findRepeatNumber(int[] arr){
		ArrayList<Integer> res=new ArrayList<>();
		if(arr==null||arr.length==0){
			return res;
		}
		Arrays.sort(arr);
		for(int i=1;i<arr.length;i++){
			if(arr[i-1]!=arr[i]){
				continue;
			}else{
				res.add(arr[i]);
			}
		}
		return res;
	}

思路2:使用hashmap,遍历挨个存进去,如果hashmap里面有了,那就找到了一个重复数字。但是要借助额外辅助空间。

思路3:因为题目说都是0~n-1范围内的,所以如果排序好的话,元素i应该在位置i,所以对于每一个元素,如果元素==位置,那么看下一个,如果不等于的话,就拿它和第i个元素进行比较,如果相等,那么就找到了一个重复数字,如果不想等,那么交换,让元素i去它该在的位置。这种方法也修改了数组。

	public static int findRepeatNumber2(int[] arr){
		if(arr==null||arr.length==0){
			return -1;
		}
		for(int i=0;i<arr.length;i++){
			if(arr[i]==i){
				continue;
			}
			while(arr[i]!=i){
				if(arr[i]==arr[arr[i]]){
					return arr[i];
				}
				swap(arr,i,arr[i]);
			}
		}
		return -1;
	}
	
	private static void swap(int[] arr, int i, int j) {
		int tmp=arr[i];
		arr[i]=arr[j];
		arr[j]=tmp;
	}

思路4:要求不修改数组,也不能用额外辅助空间。类似二分查找,统计数字范围在数组中出现的次数,比如数字1-n如果在数组中出现的次数超过n,那么一定有重复数字,不断缩小范围。

 

2.数组中只出现一次的数

题目描述:一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字。

思路:使用异或思想。异或运算的性质是,任何一个数字与它自己异或都是0.如果从头到尾异或数组中的每一个数字,那么最终结果就是只出现一次的两个数字异或结果,而且因为这两个数不一样,所以它的异或结果肯定不为0,肯定有一位是1,我们找到第一位是1的位置,根据这一位是不是1把数组分为两个数组,这样就会把两个只出现一次的数字分到了两个数组里面。再对两个数组分别异或,就可以得到只出现一次的数字。

import java.util.ArrayList;

//1到n
public class 数组中只出现一次的数 {
	public static ArrayList<Integer> findNumInArr(int[] arr){
		ArrayList<Integer> res=new ArrayList<>();
		if(arr==null||arr.length==0){
			return res;
		}
		int xorres=0;
		for(int i=0;i<arr.length;i++){
			xorres^=arr[i];
		}
		//找到xorres第一个为1的位数
		int index=findFirst1(xorres);
		ArrayList<Integer> arr1=new ArrayList<>();
		ArrayList<Integer> arr2=new ArrayList<>();
		for(int i=0;i<arr.length;i++){
			if(isBit1(arr[i],index)){ //如果第index位是1,那么就存到num1里面,如果第index位不是1,就存到num2里面
				arr1.add(arr[i]);
			}else{
				arr2.add(arr[i]);
			}
		}
		int rnum1=0;
		int rnum2=0;
		for(int i=0;i<arr1.size();i++){
			rnum1^=arr1.get(i);
		}
		for(int i=0;i<arr2.size();i++){
			rnum2^=arr2.get(i);
		}
		res.add(rnum1);
		res.add(rnum2);
		System.out.println(rnum1+" "+rnum2);
		return res;
	}

	private static boolean isBit1(int i, int index) {
		for(int j=0;j<index;j++){
			i=i>>1;
		}
		if((i&1)==1){
			return true;
		}
		return false;
	}

	private static int findFirst1(int xorres) {
		int indexbit=0;
		while((xorres&1)==0&&indexbit<8){
			xorres=xorres>>1;
			indexbit++;
		}
		return indexbit;
	}
	
	public static void main(String[] args){
		int[] arr={2,4,3,6,3,2,5,5};
		findNumInArr(arr);
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值