go 二分查找、上下边界

一、上下界

上边界 upper:表示 >= target 的位置

下边界 lower:表示 <= target 的位置

绝对上边界 abs_upper:表示 > target 的位置,与上边界的关系:lower = abs_upper - 1

绝对下边界 abs_lower:表示 < target 的位置,与下边界的关系:upper = abs_lower + 1

二、二分查找

1、标准库的二分查找

// len(nums) 表示未找到
func upperBound0(nums []int, target int) int {
	//upper := sort.SearchInts(nums, target)
	upper := sort.Search(len(nums), func(i int) bool {
		return nums[i] >= target
	})

	return upper
}

// -1表示未找到
func lowerBound0(nums []int, target int) int {
	lower := sort.Search(len(nums), func(i int) bool {
		return nums[i] > target  // 绝对上界限
	}) - 1

	return lower
}

2、二分查找 

<= 结果是可能是:i=j (同时位于相等位置)、i!=j (j位于下边界,i位于上边界)
 <  结果是可能是:i=j (同时位于相等位置)、i=j (同时位于下边界)、i=j (同时位于上边界)

mid = (l + r) / 2 存在越界问题

mid = int(uint(l + r) >> 1)  标准库的高效写法

方式一:<=

func upperBound1(nums []int, target int) int {
	l, r := 0, len(nums)-1

    // <= 结果是可能是:i=j (同时位于相等位置)、i!=j (j位于下边界,i位于上边界)
    // <  结果是可能是:i=j (同时位于相等位置)、i=j (同时位于下边界)、i=j (同时位于上边界)

	for l <= r {
		mid := (l + r) / 2
		if nums[mid] == target {
			return mid
		}
		if nums[mid] > target {
			r = mid - 1
		} else {
			l = mid + 1
		}
	}

	return l
}

​
func lowerBound1(nums []int, target int) int {
	l, r := 0, len(nums)-1

    // <= 结果是可能是:i=j (同时位于相等位置)、i!=j (j位于下边界,i位于上边界)
    // <  结果是可能是:i=j (同时位于相等位置)、i=j (同时位于下边界)、i=j (同时位于上边界)

	for l <= r {
		mid := (l + r) / 2
		if nums[mid] == target {
			return mid
		}
		if nums[mid] > target {
			r = mid - 1
		} else {
			l = mid + 1
		}
	}

	return r
}

方式二:<

func upperBound2(nums []int, target int) int {
	l, r := 0, len(nums)-1

	// <= 结果是可能是:i=j (同时位于相等位置)、i!=j (j位于下边界,i位于上边界)
	// <  结果是可能是:i=j (同时位于相等位置)、i=j (同时位于下边界)、i=j (同时位于上边界)

	for l < r {
		mid := (l + r) / 2
		if nums[mid] == target {
			return mid
		}
		if nums[mid] > target {
			r = mid - 1
		} else {
			l = mid + 1
		}
	}

	//l是上边界
	if nums[l] >= target {
		return l
	}

	//l+1是上边界
	return l + 1
}


func lowerBound2(nums []int, target int) int {
	l, r := 0, len(nums)-1

	// <= 结果是可能是:i=j (同时位于相等位置)、i!=j (j位于下边界,i位于上边界)
	// <  结果是可能是:i=j (同时位于相等位置)、i=j (同时位于下边界)、i=j (同时位于上边界)

	for l < r {
		mid := (l + r) / 2
		if nums[mid] == target {
			return mid
		}
		if nums[mid] > target {
			r = mid - 1
		} else {
			l = mid + 1
		}
	}

	//l是下边界
	if nums[l] <= target {
		return l
	}

	//l-1是下边界
	return l - 1
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值