剑指offer03.数组中重复的数字

题目

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

示例 1:

输入: [2, 3, 1, 0, 2, 5, 3]
输出:2 或 3

第一种解法

一个简单的暴力方法就是先把输入的数组排序.从排序的数组中找出重复的数字是一件容易的事情,只需要判断一个数字的下一个数字是否与本身相等即可
.但是排序一个长度为n的数组需要O(nlogn)的时间
时间复杂度较高,不可取

第二种解法

使用哈希表来解决这个问题.从头到尾按顺序扫描这个数组的每个数字.
每扫描到一个数字的时候.都可以用O(1)的时间来判断哈希表中是否存在了这个数字. 如果哈希表中没有这个数字就把他加入进去,下次再判断时就能找出来
时间复杂度 : O(n)
空间复杂度 : O(n)提高了时间复杂度的前提下是牺牲了一个大小为O(n)的哈希表为代价的

// 使用哈希表来储存数组中数字出现的次数
func findRepeatNumber(nums []int) int{
    
    
	// 先建造一个map, key为int类型存数组里面的值,value为bool类型存真假
	m := make(map[int]bool)
	// for range nums 取出值并且判断是否在哈希表里面存在
	// 若没有存在那么就是把这个值设为key,value设为true
	// 若下次再出现了这个值,那么就可以返回这个值了
	for _, num := range nums{
    
    
		if _,exist := m[num]; exist{
    
    
			return num
		}
		m[num] = true
	}
	return -1
}

第三种解法

有没有一种空间上为O(1)的更高效的解法呢?
在一个长度为 n 的数组 nums 里的所有数字都在 0 ~ n-1 的范围内 。
此说明含义:数组元素的 索引 和 值 是 一对多 的关系。
因此,可遍历数组并通过交换操作,使元素的 索引 与 值 一一对应(即 nums[i] = i )。因而,就能通过索引映射对应的值,起到与字典等价的作用。
遍历中,第一次遇到数字 x 时,将其交换至索引 x 处;而当第二次遇到数字 x 时,一定有 nums[x] = x ,此时即可得到一组重复数字。

算法流程:
遍历数组 nums ,设索引初始值为 i=0 :

若 nums[i]=i : 说明此数字已在对应索引位置,无需交换,因此跳过;
若 nums[nums[i]] = nums[i] : 代表索引 nums[i] 处和索引 ii 处的元素值都为 nums[i] ,即找到一组重复值,返回此值 nums[i] ;
否则: 交换索引为 i 和 nums[i] 的元素值,将此数字交换至对应索引位置。
若遍历完毕尚未返回,则返回 −1 。

func findRepeatNumber2(nums []int) int {
    
    
	// 效验参数的合法性
	if len(nums) <= 0 {
    
    
		return -1
	}
	for i := 0;i < len(nums);i++ {
    
    
		if nums[i] < 0 || nums[i] > len(nums) - 1{
    
    
			return -1
		}
	}
	var tmp int = 0
	for i := 0;i < len(nums);i++ {
    
    
		for nums[i] != i {
    
    
			if nums[i] == nums[nums[i]] {
    
    
				return nums[i]
			}
			tmp = nums[i]
			nums[i] = nums[tmp]
			nums[tmp] = tmp
		}
	}
	return -1
}

值得一提的东西

测试用例可能包含无效测试用例
如输入长度为n的数组中包含(0~n-1)之外的数字
传入空数组等等
所以我们需要先进行参数的校验合法性

猜你喜欢

转载自blog.csdn.net/m0_53804791/article/details/119494045
今日推荐