漫画算法-学习笔记(28)

漫画算法-小灰的算法之旅(28)

寻找缺失的整数

Q: 在一个无序数组里面有99个不重复的正整数,范围是1~100,唯独缺少1个1~100中的整数,如何找出这个缺失的整数?

方法一(哈希表)
思路

创建一个哈希表,以1到100这100个整数位key,然后遍历整个数组,每读到一个整数,就定位到哈希表中对应的key,然后删除这个Key.

由于数组中缺少1个整数,哈希表最终一定有99个Key被删除,从而剩下1个唯一的key。这个剩下的key就是哪个缺失的整数。

时间复杂度

假设数组长度为n,那么该解法的时间复杂度为O(n),空间复杂度为O(n)。

代码实现
func findLostNumberV1(nums []int) int {

	table := make(map[int]struct{}, 100)
	//生成一个哈希表
	for i := 1; i <= 100; i++ {
		table[i] = struct{}{}
	}
	//遇到匹配的key 删除对应的key
	for _, val := range nums {
		delete(table, val)
	}
	for i := range table {
		return i
	}
	return 0
}
func main() {

	array := createArray(100)
	lostNumber := findLostNumberV1(array)
	log.Println(lostNumber)

}

func createArray(length int) []int {
	array :=make([]int,length)
	for i :=0;i<length;i++ {
		if i==50 {
			continue
		}
		array[i]=i+1
	}
	return array
}

方法二(先排序后查找)
思路

先把数组元素从小到大进行排序,然后遍历已经有序的数组,如果发现某两个相邻元素并不连续,说明缺少的就是这两个元素之间的整数。

时间复杂度

假设数组长度为n,如果用时间复杂度为O(nlogn)的排序算法进行排序,那么该解法的时间复杂度为O(nlogn),空间复杂度为O(1).

代码实现
func findLostNumberV2(nums []int) int {
	//先排序
	quickSort(nums, 0, len(nums)-1)
	//再遍历
	for i := 0; i < len(nums); i++ {
		 temp :=nums[i]
		if temp != (i + 1) {
			return i + 1
		}
	}
	return 0
}

func quickSort(arr []int, startIndex, endIndex int) {

	//递归结束条件,startIndex >= endIndex
	if startIndex >= endIndex {
		return
	}
	// 得到基准元素位置
	pivotIndex := partition(arr, startIndex, endIndex)
	// 根据基准元素,分成两部分进行递归排序
	quickSort(arr, startIndex, pivotIndex-1)
	quickSort(arr, pivotIndex+1, endIndex)

}

// 双指针移动
func partition(arr []int, startIndex, endIndex int) int {
	// 获取第1个位置的元素作为基准元素
	pivot := arr[startIndex]
	left := startIndex
	right := endIndex
	for left != right {
		// 控制right指针比较并向左移动
		for left < right && arr[right] > pivot {
			right--
		}
		// 控制left指针比较并向右移动
		for left < right && arr[left] <= pivot {
			left++
		}
		// 交换left 和right指针所指向的元素
		if left < right {
			temp := arr[left]
			arr[left] = arr[right]
			arr[right] = temp
		}
	}
	//pivot 和指针重合点交换
	arr[startIndex] = arr[left]
	arr[left] = pivot
	return left
}
func main() {

	array := createArray(100)
	lostNumber := findLostNumberV1(array)
	log.Println(lostNumber)
	v2 := findLostNumberV2(array)
	log.Println(v2)

}

func createArray(length int) []int {
	array :=make([]int,length)
	for i :=0;i<length;i++ {
		if i==50 {
			continue
		}
		array[i]=i+1
	}
	for i :=0;i< len(array);i++ {
		if array[i]==0 {
			array=append(array[:i],array[i+1:]...)
		}
	}
	return array
}

方法三(累加求差)
思路

先算出1~100的累加和,然后再依次减去数组里的所有元素,最后的差值就是所缺少的整数。

时间复杂度

假设数组长度是n,那么该解法的时间复杂度是O(n),空间复杂度是O(1)

代码实现
func findLostNumberV3(nums []int) int {
	sum := (100+1)*100>>1
	for _, num := range nums {
		sum=sum-num
	}
	return sum
}

Q2: 问题扩展: 一个无序数组里面有若干个正整数,范围是1~100,其中99个整数都出现了偶数次,只有1个整数出现了奇数次,如何找到这个出现奇数次的整数呢?

方法一(异或运算)
思路

异或运算:在进行位运算时,相同位得0,不同位得1。

遍历整个数组,依次做异或运算。由于异或运算在进行位运算时,相同为0,不同为1,因此所有出现偶数次的整数都会互相抵消变成0,只有唯一出现奇数次的整数会被留下。

例如:给出无序数组{3,1,3,2,4,1,4}

异或运算像加法一样,满足交换律和结合律,所以这个数组元素的异或运算的结果:

异或运算: 3 xor 1 xor 3 xor 2 xor 4 xor 1 xor 4 
==       1 xor 1 xor 3 xor 3 xor 4 xor 4 xor 2
==       2
时间复杂度

假设数组长度为n,那么该解法的时间复杂度是O(n),空间复杂度是O(1)。

代码实现
// 异或运算求解
func findLostNumberV4(nums []int) int  {

	sum :=0
	for _, num := range nums {
		sum =sum^num
	}
	return sum
}

func main() {
	arr :=[]int{3,1,3,2,4,1,4}
	v4 := findLostNumberV4(arr)
	log.Println(v4)

}

Q3: 问题扩展

假设一个无序数组里有若干个正整数,范围是1~100,其中有98个整数出现了偶数次,只有2个整数出现了奇数次,如何找到这2个奇数次的整数呢?

方法一(分治法+异或运算)
思路

把2个出现了奇数次的整数命名为A和B。遍历整个数组,然后依次做异或运算,进行异或运算的最终结果,等同于A和B进行异或运算的结果。在这个结果中,至少会有一个二进制位是1(如果都是0,说明A和B相等,和题目不符)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值