算法设计思想(6)— 二分法(二分法代码模板、寻找左侧边界二分法、寻找右侧边界二分法)

1. 问题

【例题】循环输入,每组数据为给定 n 个元素的升序整型数组 nums 和一个值 target,要求实现一个函数查找 nums 中 target 的下标,如果查找不到则返回 -1.

2. 思路

思路

3. 代码

int find(int n, int a[], int target)
{
    int l = 0;
    int r = n - 1;
    while (l <= r)
    {
        int middle = (l + r) / 2;
        if (a[middle] < target)
        {
            l = middle + 1;
        }
        else if (a[middle] > target)
        {
            r = middle - 1;
        }
        else
        {
            return middle;
        }
    }
    return -1;
}

int main()
{
    int n, target, ret;
    std::cout << "input number of n " << std::endl;
    while (std::cin >> n)
    {
        int b[n] = {0};
        for (int i = 0; i < n; i++)
        {
            std::cin >> b[i];
        }

        std::cout << "input target " << std::endl;
        std::cin >> target;

        ret = find(n, b, target);
        std::cout << "location:" << ret << std::endl;
    }
    return 0;
}

4. 二分法模板

二分搜索的一个技巧:不要出现 else ,而是把所有的情况用 else if 写清楚,因为这样可以清楚的展现所有的细节。

func binarySearch(a []int, target int) int {
	left := 0
	right := len(a) - 1
	// 因为搜素区间是 [left, right],左右都是封闭的,所以循环时应该是 <=
	for left <= right {
		mid := left + (right-left)/2
		if a[mid] == target {
			return mid
		} else if a[mid] < target {
			left = mid + 1
		} else if a[mid] > target {
			right = mid - 1
		}
	}
	return -1
}

5. 寻找左侧边界的二分法

package main

import (
	"fmt"
)

func leftBinarySearch(a []int, target int) int {
	left := 0
	right := len(a) - 1
	// 因为搜素区间是 [left, right],左右都是封闭的,所以循环时应该是 <=
	for left <= right {
		mid := left + (right-left)/2
		if a[mid] == target {
			// 不要返回,收缩右边界,逐步锁定左侧边界
			right = mid - 1
		} else if a[mid] < target {
			left = mid + 1
		} else if a[mid] > target {
			right = mid - 1
		}
	}
	// 上面循环结束时 left = right + 1 ,所以当 target 比 a 中所有元素都大时,
	// 会存在 left 越界的情况
	if left >= len(a) || a[left] != target {
		return -1
	}
	return left
}

func main() {
	arr := []int{1, 2, 3, 4, 4, 7, 7, 8, 9}
	fmt.Println(leftBinarySearch(arr, 4))
}

6. 寻找右侧边界的二分法

package main

import (
	"fmt"
)

func rightBinarySearch(a []int, target int) int {
	left := 0
	right := len(a) - 1
	// 因为搜素区间是 [left, right],左右都是封闭的,所以循环时应该是 <=
	for left <= right {
		mid := left + (right-left)/2
		if a[mid] == target {
			// 不要返回,收缩左边界,逐步锁定右侧边界
			left = mid + 1
		} else if a[mid] < target {
			left = mid + 1
		} else if a[mid] > target {
			right = mid - 1
		}
	}
	// 上面循环结束时 left = right + 1 ,所以当 target 比 a 中所有元素都小时,
	// right 会被减小到 -1,会存在 right 越界的情况
	if right < 0 || a[right] != target {
		return -1
	}
	return right
}

func main() {
	arr := []int{1, 2, 3, 4, 4, 7, 7, 8, 9}
	fmt.Println(rightBinarySearch(arr, 4))
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值