【题3数组中重复的数字】
【题目1】
在一个长度为n的数组里的所有数字都在0-n-1的范围内,数组中某些数字是重复的,但不知道每个数字重复了几次,请找出数组中任意一个重复的数字,例如,如果输入长度为7的数组,{2,3,1,0,2,5,3},那么对应的输出是2或者3
【方法】
1.
(1)先把输入数组排序
(2)从头到尾扫描排序后的数组
(3)排一个长度为n的数组需要O(nlogn)
2哈希表
(1) 从头到尾按顺序扫描数组的每个数字
(2) 每扫描一个用O(1)时间判断哈希表里是否已经包含该数字
(3) 若包含则一个重复数字,若不包含则插入到哈希表
3数字都在0~n-1范围内排序之后,i将对应下标i的位置
重排数组
(1)扫描到下标i的数字时,比较这个数字(m)是否=i
(2)若等于,扫描下一个。不等则与第m个数字比较
(3)如果与第m个数字相等,则 有一个重复数字
(4)把第i个数字与第m个数字交换,把m放到属于他的位置
实现
package ti3;
/**
*
* 题目:在一个长度为n的数组里的所有数字都在0到n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,
* 也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7的数组{2, 3, 1, 0, 2, 5, 3},
* 那么对应的输出是重复的数字2或者3。
* test1:数组输入无效!
test2:数组中无重复数字!
test3:数字大小超出范围!
test4:重复数字为:2
*/
public class FindDuplication {
/**
* 找到数组中一个重复的数字
* 返回-1代表无重复数字或者输入无效
*/
public int getDuplicate(int[] arr){
if(arr == null || arr.length <= 0){
System.out.println("数组输入无效");
return -1;
}
for(int a:arr){
if(a < 0 || a > arr.length - 1){
System.out.println("数字大小超出范围");
return -1;
}
}
for(int i = 0;i < arr.length;i++){
int temp;
while(arr[i] != i){
if(arr[arr[i]] == arr[i]){
return arr[i];
}
//交换arr[arr[i]]和arr[i]
temp = arr[i];
arr[i] = arr[temp];
arr[temp] = temp;
}
}
System.out.println("数组中无重复的数字");
return -1;
}
//测试代码
//数组为null
public void test1()
{
System.out.println("test1");
int[] a = null;
int dup = getDuplicate(a);
if(dup >= 0){
System.out.println("重复数字为"+dup);
}
}
//数组无重复数字
public void test2()
{
System.out.println("test2");
int[] a = {0,1,2,3};
int dup = getDuplicate(a);
if(dup >= 0){
System.out.println("重复数字为"+dup);
}
}
//数组数字越界
public void test3()
{
System.out.println("test3");
int[] a = {1,2,3,4};
int dup = getDuplicate(a);
if(dup >= 0){
System.out.println("重复数字为"+dup);
}
}
//重复数字为2
public void test4()
{
System.out.println("test4");
int[] a = {1,2,3,2,4};
int dup = getDuplicate(a);
if(dup >= 0){
System.out.println("重复数字为"+dup);
}
}
public static void main(String[] args) {
FindDuplication f = new FindDuplication();
f.test1();
f.test2();
f.test3();
f.test4();
}
}
【题目2不修改数组找出重复的数字】
在一个长度尾n+1的数组里的所有数字都在1~n的范围内,所有数组中至少有一个数字时重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。例如,输入长度为8的数组{2,3,5,4,3,2,6},那么对应 的输出是重复的数字2或3
注意:不能修改原数组
方法:
1.
(1)创建一个长度为n+1的辅助数组,逐一把原数组的每个数字复制到辅助数组
(2)若原数组中被复制的数字为m,则复制到辅助数组下标为m的位置
2.
(1)把从1~n数字从 中间的数字m分为2部分,1-m,m+1~n
(2)如果1~m数字的数目超过了m则这个一半包含重复的数字
否则,另一半m+1~n区间里一定包含重复的数字
(3)继续一分为二
实现
package ti3;
public class DuplicationInArrayNotEdit {
private int countRange(int[] array,int length,int start,int end){
if(start < 0 ||end > length-1)throw new IllegalArgumentException("Wrong Arguments");
int count = 0;
for(int i = 0;i<length;++i){
if(array[i]<=end && array[i]>= start)++count;
}
return count;
}
public int returnOneDuplication(int[] array){
if(array == null) throw new IllegalArgumentException("Wrong Arguments");
int length = array.length;
int start = 1;
int end = length - 1;
while(start <= end){
int middle = ((end-start)>>1)+start;
int count = countRange(array,length,start,middle);
if(start == end){
if(count >1)return start;
else break;
}
if(count>middle - start+1)end = middle;
else start = middle +1;//注意这个+1
}
return -1;
}
public static void main(String[] args) {
DuplicationInArrayNotEdit duplicationInArrayNotEdit = new DuplicationInArrayNotEdit();
int[] Array = new int[] {2,3,5,4,3,2,6,7};
System.out.println(duplicationInArrayNotEdit.returnOneDuplication(Array));
}
}
参考:
1.《剑指offer》
2.https://www.cnblogs.com/yongh/p/9318604.html
3.https://blog.csdn.net/w13261711130/article/details/79973502