算法细节问题分析

愚者千虑,必有一得

二分查找

https://blog.csdn.net/xushiyu1996818/article/details/102482609

左右开闭问题

值的查找

最简单最直观的方式,这种情况下,如果值不存在在数组中,l,r 会逐渐收靠到数组的边界,直到跳出范围

func binSearch0(nums []int, target int) (index int) {
	l, r := 0, len(nums)-1
	for l <= r {
		//搜索区间为[0,len(nums)-1]
		m := l + (r-l)/2
		if nums[m] == target {
			return m
		} else if nums[m] < target {
			l = m + 1
		} else {
			r = m - 1
		}
	}
	return -1
}

存在循环的情况

上面这种情况,稍微修改就会产生几种常见的会产生循环的情况

a. l,r 赋值时,没有将m剔除下一次查找范围
func binSearch0(nums []int, target int) (index int) {
	l, r := 0, len(nums)-1
	for l <= r {
		m := l + (r-l)/2
		if nums[m] == target {
			return m
		} else if nums[m] < target {
			l = m 
		} else {
			r = m
		}
	}
	return -1
}

这种情况下通常会产生循环的情况 r-l =1
m = l + (r-l)/2 => m =l;然后恰好,nums[m]< target;l = m=> l = l;

搜索范围

当 l < r 而不是 l<=r 时,二分查找的范围实际上是两边开区间(0,l),放弃了查询l==r的情况,这种情况可以通过打补丁实现

func binSearch0(nums []int, target int) (index int) {
	l, r := 0, len(nums)-1
	for l < r {
		//搜索区间为[0,len(nums)-1]
		m := l + (r-l)/2
		if nums[m] == target {
			return m
		} else if nums[m] < target {
			l = m + 1
		} else {
			r = m - 1
		}
	}
	return nums[l]==target?l:-1
}

边界查找问题

边界查找的实质就是,寻找某个target第一次和最后一次出现的index

寻找左边界

func leftBound(nums []int, target int) (index int) {
	l, r := 0, len(nums)
	for l < r {
		m := l + (r-l)/2
		if nums[m] == target {
			r = m 
		} else if nums[m] < target {
			l = m + 1
		} else {
			r = m
		}
	}
	return l
}

寻找右边界

func leftBound(nums []int, target int) (index int) {
	l, r := 0, len(nums)
	for l < r {
		m := l + (r-l)/2
		if nums[m] == target {
			l = m + 1 
		} else if nums[m] < target {
			l = m + 1
		} else {
			r = m
		}
	}
	return l-1
}



# 快排
![](https://img2020.cnblogs.com/blog/895672/202108/895672-20210811144136935-2145787125.png)
1. 左边界和右边界谁在前决定了最终停在哪个元素上,因为枢轴默认取得第一个元素,因此最好和停在小于arr[p]的首个元素交换,因此最好和r交换
2. l<r 可能会导致停在同一个指针上最后再交换一次导致排序错误

# 插入排序
posted @ 2021-07-23 14:43  Fake_coder  阅读(31)  评论(0编辑  收藏  举报