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

本文介绍了一种在不修改原始数组的情况下,寻找长度为n+1的数组中重复数字的算法。通过将数字范围分为两部分,并利用二分查找的思想,逐步缩小可能包含重复数字的区间,直至找到重复的数字。

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

题目:

  • 在一个长度为n+1的数组中所有数组都在1~n 的范围内,所以数中至少有一数字是重复的;请找出数组中任意一个重复的数字,但不能修改原数组;

 

例如:

  • 输入长度为8(n+1)的数组{2,3,5,4,3,2,6,7},那么对应的输出重复的数字是2或3;

 

分析:

  • 假如没有重复的数字,那么在1~n(1~7)的范围内就只会有n(7)个数字;由于数组包含超过n(7)个数字,所以一定包含了重复的数字;
  • 我们从1~n(7)的数字从中间的数字m(4)分为两部分,前面一半为1~m(1~4),后面的一半为m+1~n(5~7);如果1~m(4)的数字超过m(4),那么重复的数字一定在这里面;
  • 意思就是:如果1~4的这个范围的数,在数组的中个数超过了4,那么就一定有重复的数;
  • 否则,另一半里面,一定包含重复的数字;
  • 然后我们可以继续把包含重复的区间一分为二,直到找到一个重复的数字;
  • 这个过程类似二分查找

 

A3.java

package No2_Array;

 

import java.util.Arrays;

 

public class A3 {

 

public void duplicate(int []a,int []num){

if(a.length<=0||a==null){

return ;

}

A3 a3 = new A3();

 

int k = 0;

 

int left = 1;

int right = a.length-1;

//当相等的时候,就是一个数,如果这个数的count大于1,则是重复数字

while(left <= right){

 

int mid = (left+right)>>1;//mid = 4,相当于/2

//不是递归调用,先比较左边的(这个左边的一段数,不是数组左边的数字,而是从从小到大,左半边的数),如果左边的数字大于该段数字的范围,就包含重复的数字

int count = a3.check(a, left, mid);

 

//直到最后才会剩下一个数字,判断最后的这一个数的个数是否大于1

if(left == right){

if(count > 1){//判断的仅剩最后一个元素,而且出现的次数还大于1,那就是重复的元素了

num[k++] = left;//放到数组里面

break;

}

else{

break;//如果没有找到元素,也退出

}

}

不是最后一个数,就一直判断二分

//这个是比较前一半

if(count > (mid-left+1)){//代表这里面有重复,然后缩小范围继续拆分

right = mid;

 

}

//这个是比较后一半

else{

//没有重复

left = mid+1;

}

 

}

 

}

//找每一段在该范围内[pq]的个数

public int check(int num[],int p,int q){

 

if(num == null){

return 0;

}

//比较某一段的数字,出现在整个数组中的次数,如果大于该段数字的范围,就是含重复的数

int sum = 0;

for(int i = 0;i < num.length;i++){

if(num[i] >= p && num[i] <= q){

sum++;

}

}

return sum;

}

 

 

public static void main(String[] args) {

// TODO Auto-generated method stub

 

int a[] = new int[]{2,3,1,4,0,3,2};

//用于存重复的数

int []num = new int[a.length];

 

new A3().duplicate(a,num);

 

//还有一种方法打印,不需要用for循环

System.out.println(Arrays.toString(num));

}

 

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值