漫画算法-小灰的算法之旅(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相等,和题目不符)