剑指 offer 03.数组中重复的数字

问题

找出数组中重复的数字。

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
来源:力扣(LeetCode)
链接:链接

题解

1.双重循环暴力解题(最简单,最费时)

思路:

当双重循环中nums[i] == nums[j]时 该值就为重复的数字

代码:

public int findRepeatNumber(int[] nums){
	for( int i = 0; i < nums.length; i++){
		for( int j = 0; j < nums.length; j++){
			if(nums[i] = nums[j])
				return nums[i];
		}
	}
	return -1;
}

复杂度分析

时间复杂度:O(n^2)
0<nums.length<10000, 当数组长度达到10w,代码的性能就很差了
空间复杂度:O(1)

2.HashMap解题

思路:

看见题目的第一反应就是用HashMap将nums中的值存到map的k,使用map.containsKey(Object k),
当返回true时,该K就是重复的数字(因为最近使用map.containsKey()比较多,所以选择这个Map解题,但是后来想想直接用Set更简单一些)

public int findRepeatNumber(int[] nums){
	Map<Integer,Integer> map = new HashMap<Integer,Integer>();
	for(int num : nums){
		if(map.containsKey(num))
			return num;
		map.put(num,0);
	}
	return -1;
}

复杂度分析

时间复杂度:O(n)
空间复杂度:O(n) 哈希查找的空间复杂度为O(1)

3.HashSet解题

思路:

同 HashMap

代码:

public int findRepeatNum(int[] nums){
	Set<Integer> set = new HashSet<Integer>();
	for(int num : nums){
		//set.add(T value) 若set中无该元素则存入set并返回true
		if(!set.add(num))
			return num;
	}
	return -1;
}

时间复杂度:O(n)
空间复杂度:O(n)

4.使用数组代替HashSet

思路

初始化一个临时数组,将元素组的值当做临时数组的下标,该值+1,若临时数组的值大于1,则该值就为重复的值。
虽然时间复杂度和空间复杂度和HashSet解题的相同,但是使用数组性能有很大提升,主要因为两个方面:
1. 哈希表底层是使用数组+红黑树组成的,而数组也是用不满的,有加载因子。所以使用数组代替哈希表可以节省空间。
2. 哈希表在判重的时候要经过哈希计算,可能存在哈希冲突,而数组可以直接通过index找到内存位置,所以性能更好

代码

poublic int findRepeatNum(int[] nums){
	int[] temp = new int[nums.length];
	for( int i = 0; i<nums.length; i++){
		temp[nums[i]++;
		if(temp[nums[i]]>1)
			return nums[i];
	}
	return -1;
}

时间复杂度:O(n)
空间复杂度:O(n)

5.在原数组上解题

思路

移动原数组,以下标 与 值 相等与否为判定条件,若不相等,则判定值与该值作为下标的值是否相等,若相等则为重复的数,若不相等互换。这样空间复杂度就为O(1)

代码

public int findRepeatNum(int[] nums){
	for(int i = 0; i<nums.length;i++){
		while(i!=nums[i]){
			if(nums[i] == nums[nums[i]]{
				return nums[i];
			}
			int temp = nums[nums[i]];
			nums[nums[i]] = nums[i];
			nums[i] = temp;
		}
	}
	return -1;
}

复杂度

时间复杂度:O(n)
空间复杂度:O(1)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值