《剑指Offer》第二版之数组中重复的数字(二)

目录

问题:
在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。
思路:
从头到尾依次扫描这个数组中的每个数字。当扫描到下标为i的数字时,首先比较这个数字(用m表示)是不是等于i。如果是,则接着扫描下一个数字;如果不是,则再拿它和第m个数字进行比较。如果它和第m个数字相等,就找到了一个重复的数字(该数字在下标为i和m的位置都出现了);如果它和第m个数字不相等,就把第i个数字和第m个数字交换,把m放到属于它的位置。接下来再重复这个比较、交换的过程,直到我们发现一个重复的数字。
步骤:
1.数组的第0个数字(从0开始计数,和数组的下标保持一致)是2,与它的下标不相 等,于是把它和下标为2的数字1交换。交换后的数组是{1,3,2,0,2,5,3}。 2.此时第0个数字是1,仍然与它的下标不相等,继续把它和下标为1的数字3交换,得到数组{3,1,2,0,2,5,3}。 3.接下来继续交换第0个数字3和第3个数字0,得到数组{0,1,2,3,2,5,3}。 4.此时第0个数字的数值为0,接着扫描下一个数字。
代码:
package test;

public class FindArrayDuplicate {

	public static void main(String[] args) {
		int[] numbers = {2, 3, 1, 0, 2, 5, 3};
		System.out.println("找到重复数字: " + duplicate(numbers));
	}
	
	public static int duplicate(int[] numbers) {
		//如果数组为空或者数组长度小于0,则直接返回-1
		if(numbers == null || numbers.length <= 0) {
			return -1;
		}
		
		//如果数组数据不在0~n-1,则直接返回-1
		for (int i = 0; i < numbers.length; i++) {
			if(numbers[i] < 0 || numbers[i] > numbers.length - 1)
				return -1;
		}
		
		for (int i = 0; i < numbers.length; i++) {
			while(numbers[i] != i) {
				//拿它和第m个数字进行比较。如果它和第m个数字相等,就找到了一个重复的数字
				if(numbers[i] == numbers[numbers[i]]) {
					return numbers[i];
				}
				
				//如果它和第m个数字不相等,就把第i个数字和第m个数字交换,把m放到属于它的位置
				int temp = numbers[i];
				numbers[i] = numbers[temp];
				numbers[temp] = temp;
				
			}
		}
		return -1;
	}
}

注:该算法的时间复杂度为O(n),空间复杂度为O(1)。

猜你喜欢

转载自blog.csdn.net/chengxusheji113/article/details/89739264