剑指OFFER笔记_03_1_寻找数组中重复的数字_JAVA实现

题目:寻找数组中重复的数字

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

题设条件中值得关注的点

  1. 数字的范围被数组长度所约束。这意味着如果一个数组中没有重复的数字,将其从小到大排序,得到的数组将会是一个数组下标和值相同的数组。如这样的:{0,1,2,3,4,5,6}

  2. 题目暂时不需要将所有重复的数字都给列出来,所以只要检测到一个重复的数字,将其输出即可。

书中的算法思想

如果将一个数组按从小到大的顺序排序,一定可以完成任务,但是我们不需要将整个数组排序,只需要在排序的过程中发现第一个重复的数就可以了。

  1. 设置 i = 0
  2. 从数组的下标为 i 的元素开始检测,如果 i = nums.length,则跳到第5步。
  3. 如果当前元素的值和数组下标相同,意味着当前下标的值已经找到,可以向后检索,i++,回到第2步。
  4. 如果当前元素的值和数组下标不同,将当前的值与当前的值作为数组下标的值比较,若不同则交换(如nums[0]=3,则将nums[0]与nums[3]的值交换)并返回第2步。若相同则将当前值返回,因为已经出现了重复的元素,过程全部结束。
  5. 到达此步,说明整个数组已经整理完毕,并且没有出现重复的数字,所以返回 -1

用例解析

选题目中给的用例就可以理解这个思想:
数组取{2,3,1,0,2,5,3}

下标0123456
nums[]2310253
nums[]1320253
nums[]1320253
nums[]3120253
nums[]3120253
nums[]0123253
nums[]0123253
nums[]0123253
nums[]0123253
nums[]0123253
nums[]0123253

检查nums[0],值为2,将nums[0]=2nums[2]=1比较,值不同,交换。
检查nums[0],值为1,将nums[0]=1nums[1]=3比较,值不同,交换。
检查nums[0],值为3,将nums[0]=3nums[3]=0比较,值不同,交换。
此时nums[0]=0,i++,检查下一个。
检查nums[1],值为1,i++,检查下一个。
检查nums[2],值为2,i++,检查下一个。
检查nums[3],值为3,i++,检查下一个。
检查nums[4],值为2,将nums[4]=2nums[2]=2比较,值相同,出现重复值,返回nums[4]或者nums[2]均可(因为值相同)

代码

函数主体部分代码

package q01;

public class Question01 {
	
	//空的构造函数
	public Question01() {		
	}
	
	/**
	 * 判断numbers数组中是否存在重复出现的数,若有则存入duplication 返回true,否则返回false
	 * @param nums	待检测数组
	 * @param length	numbers数组的长度
	 * @param duplication	存放重复出现的数的数组
	 * @return
	 */
	public int duplicate(int[] nums)
	{
		int result = -1;		
		//若待检测数组为空,或长度<0,一定是有错误,应该return -1,表示异常;
		if(nums == null || nums.length <= 0)
		{
			return result;
		}
		int length = nums.length;
		//根据题目要求,数组中存放的数是在0~n-1之间的,若有数不在此范围,应该return -1,表示异常;
		for (int i = 0; i < nums.length; i++) {
			if(nums[i] < 0 || nums[i] > length - 1)
			{
				return result;
			}
		}
		
		//依次检索数组中的元素
		for(int i = 0; i < nums.length; i++)
		{
			//持续对当前元素进行操作,直到值与下标相同或者发现重复元素为止
			while (nums[i] != i)
			{
				//若值与以此值为下标的值相同,则返回该值
				if (nums[i] == nums[nums[i]])
				{
					return nums[i];
				}
				//若不同,则交换
				int temp = nums[i];
				nums[i] = nums[nums[i]];
				//此行注释掉的代码是我一开始写的时候犯的低级错误,写出来提醒一下各位。
				//因为此时的nums[i]已经发生了改变,不能再用nums[nums[i]]去调用了,否则会出现死循环。
				//nums[nums[i]] = temp;
				nums[temp] = temp;
			}
		}
		//返回默认的结果0,表示没有重复
		return 0;
	}
}

测试部分代码

package q01;

public class TestApp {
	public static void main(String[] args) {
		Question01 e = new Question01();
		//空数组,检测应为-1
		int[] nums1 = null;
		//数组中存在负数,检测应为-1
		int[] nums2 = {2,1,5,4,-2,3};
		//数组中存在数大于array.length-1,检测应为-1
		int[] nums3 = {3,2,5,2};
		//符合题目要求的数组,应当返回0,
		int[] nums4 = {2,1,3,0,4};
		//符合题目要求的数组,应当返回2
		int[] nums5 = {2,1,3,0,2};
		
		int result1 = e.duplicate(nums1);
		System.out.println("result1: " + result1);
		int result2= e.duplicate(nums2);
		System.out.println("result2: " + result2);
		int result3 = e.duplicate(nums3);
		System.out.println("result3: " + result3);
		int result4 = e.duplicate(nums4);
		System.out.println("result4: " + result4);
		int result5 = e.duplicate(nums5);
		System.out.println("result5: " + result5);
	}
}

运行结果

运行结果

LeetCode提交结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值