剑指offer(50)数组中重复的数字

package java_jianzhioffer_algorithm;
/**
 * 题目:在一个长度为n的数组里的所有数字都在0到n-1的范围内。
 * 数组中某些数字是重复的,但不知道有几个数字是重复的。
 * 请找出数组中任意一个重复的数字。
 * eg:输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
 * @author hexiaoli
 *思考:
 *1)建立一个计数数组(或者哈希表做),出现一次,对应标号加1
 *2) 没有重复的情况,0-n-1范围内的数字,i应该出现在下标为i的位置
 *   从头到尾扫描数组,比较第i个位置元素m,若相等则扫描下一个,
 *   若不等比较m位置上的值是否和这个相等,若相等则找到。
 *引申:不允许对数组排序
 *    二分思想,将1-n按照m分成两部分,前面一半为0-m,后面一半为m+1-n
 *    若前面一半的数字超过m+1,说明重复的数组在前面一半,否则在后面一半
 */
public class MinNumberInrotateArray {
	public boolean duplicate1(int[] numbers,int length,int [] duplication) {
		//检查数组内数是否合法
		if(numbers == null || length ==0) {
			return false;
		}
		for(int i = 0; i<length ;i++) {
			if(numbers[i] < 0 || numbers[i] > length) {
				return false;
			}			
		}
		//只需扫描一次原序列,就统计出所有元素出现的次数
		int[] count = new int [length];
		for(int i = 0; i<length ;i++) {
				count[numbers[i]]+=1;
		}
		//再扫描一次数组,找到一个出现次数大于1的值即可
        for(int i = 0; i < length; i++){
            if(count[i] > 1){
                duplication[0] = i;
                System.out.println("duplication[0]:"+duplication[0]);
                return true;
            }
        }
        return false;
	}
	public boolean duplicate2(int[] numbers,int length,int [] duplication) {
		//检查数组内数是否合法
		if(numbers == null || length ==0) {
			return false;
		}
		for(int i = 0; i<length ;i++) {
			if(numbers[i] < 0 || numbers[i] > length) {
				return false;
			}			
		}
		int  temp = 0;
		for(int i = 0; i < length ;i++) {
			while(numbers[i]!=i){
				if(numbers[i]==numbers[numbers[i]]) {
					duplication[0]=numbers[i];
					System.out.println("duplication[0]:"+duplication[0]);
					return true;
				}else {
					temp = numbers[i];
					numbers[i] = numbers[temp];
					numbers[temp] = temp;
				}
			}
		}
		
		return false;
	}
	public boolean duplicate3(int[] numbers,int length,int [] duplication) {
		//检查数组内数是否合法
		if(numbers == null || length ==0) {
			return false;
		}
		for(int i = 0 ; i < length ; i++) {
			if(numbers[i] < 0 || numbers[i] > length) {
				return false;
			}			
		}
		// 记录一下首尾
		int start = 0;
		int end = length-1;
		while(end >= start) {
			int mid = ((end-start+1)>>1) + start;
			//统计前一半
			int count = countRange(numbers,length,start,mid);
			//首尾相等的话,则指向了单个元素
			if(end == start) {
				//如果这个元素统计值大于2,则是重复的值,并输出;否则跳出循环
				if(count > 1) {
					duplication[0] = start;
					System.out.println("duplication[0]:"+duplication[0]);
					return true;
				}else {
					break;
				}
			}
			if(count > (mid -start + 1)) {
				end = mid;
			}else {
				start = mid+1;
			}
		}	
		return false;
	}
	//统计数组中大于start小于end的元素个数
	public int countRange(int[] numbers,int length,int start,int end ) {
		int count = 0;
		if(numbers == null || length == 0) {
			return -1;
		}		
		for(int i = 0; i < length;i++) {
			if(numbers[i] >= start && numbers[i] <= end) {
				++count;
			}
		}
		return count;
	}
	
	public static void main(String[] args) {
		int[] numbers = {2,3,1,0,2,5,3};
		int length = numbers.length;
		MinNumberInrotateArray mia = new MinNumberInrotateArray();
		int[] duplication=new int [length];
		mia.duplicate1(numbers, length, duplication);
		mia.duplicate2(numbers, length, duplication);
		mia.duplicate3(numbers, length, duplication);
	}

}

猜你喜欢

转载自blog.csdn.net/hxl0925/article/details/89343899