• 二分查找


    一、寻找一个数

    1.左闭右闭

    func search(nums []int, target int) int {
        lf, rt := 0, len(nums)-1
        for lf <= rt{
            mid := lf + (rt-lf)/2
            if nums[mid] < target{
                lf = mid + 1
            }else if nums[mid] > target{
                rt = mid - 1
            }else if nums[mid] == target{
                return mid
            }
        }
        return -1
    }
    

    2.左闭右开

    func search(nums []int, target int) int {
        lf, rt := 0, len(nums) // 左闭右开
        // 不用等于为了避免lf=rt=len(nums)越界
        for lf < rt{ 
            mid := lf + (rt-lf)/2
            if nums[mid] < target{
                lf = mid + 1 
            }else if nums[mid] > target{
                rt = mid // 区别
            }else if nums[mid] == target{
                return mid 
            }
        }
        // lf < len(nums)避免越界 如1,2,3,4中找8,此时lf=4越界
        // nums[lf] == target lf==right这种情况漏了
        if lf < len(nums) && nums[lf] == target{ 
            return lf
        }
        return -1
    }
    

    二、寻找边界

    常用左闭右开方法,该方法更好理解,不容易出错!

    1.左闭右开

    // 左边界 左闭右开
    func leftBound(nums []int, target int) int {
    	if len(nums) == 0 {
    		return -1
    	}
    	lf, rt := 0, len(nums) // 左闭右开
    	for lf < rt {
    		mid := lf + (rt-lf)/2
    		if nums[mid] < target {
    			lf = mid + 1
    		} else if nums[mid] > target {
    			rt = mid
    		} else if nums[mid] == target {
    			rt = mid
    		}
    	}
    	// target比nums中的所有数都要大的时候 lf >= len(nums)
    	// 如果nums中不存在与target相等的数 但有小于target的数时会出现lf < len(nums) && nums[lf] != target
    	if lf < len(nums) && nums[lf] == target {
    		return lf
    	}
    	return -1
    }
    
    // 右边界 左闭右开
    func rightBound(nums []int, target int) int {
    	if len(nums) == 0 {
    		return -1
    	}
    	lf, rt := 0, len(nums) // 左闭右开
    	for lf < rt {
    		mid := lf + (rt-lf)/2
    		if nums[mid] < target {
    			lf = mid + 1
    		} else if nums[mid] > target {
    			rt = mid
    		} else if nums[mid] == target {
    			lf = mid + 1
    		}
    	}
    	// target比nums中的左右数都要小的时候 lf-1 < 0
    	// 如果nums中不存在与target相等的数 但有小于target的数时会出现lf-1 >= 0 && nums[lf-1] != target
    	// 因为nums[mid] == target时lf=mid+1,所以结束循环时lf=右边界+1
    	if lf-1 >= 0 && nums[lf-1] == target {
    		return lf - 1 
    	}
    	return -1
    }
    

    2.左闭右闭

    越界现象

    // 寻找左边界 左闭右闭
    func leftBound(nums []int, target int) int {
    	lf, rt, mid := 0, len(nums)-1, 0
    	for lf <= rt {
    		mid = (lf + rt) >> 1
    		if target < nums[mid] {
    			rt = mid - 1
    		} else if target > nums[mid] {
    			lf = mid + 1
    		} else {
    			rt = mid - 1 // 右边界等于中间值--
    		}
    	}
    	if lf >= len(nums) || nums[lf] != target{
    	    return -1
    	}
    	return lf
    }
    
    // 寻找右边界 左闭右闭
    func rightBound(nums []int, target int) int {
    	lf, rt, mid := 0, len(nums)-1, 0
    	for lf <= rt {
    		mid = (lf + rt) >> 1
    		if target < nums[mid] {
    			rt = mid - 1
    		} else if target > nums[mid] {
    			lf = mid + 1
    		} else {
    			lf = mid + 1 // 左边界等于中间值++
    		}
    	}
    	if rt >= 0 && nums[rt] == target {
    		return rt
    	}
    	return -1
    }
    
    

    参考链接

  • 相关阅读:
    微信授权,重定向两次
    Newtonsoft.Json 序列化 排除指定字段或只序列化指定字段
    各大快递公司面单号准确性验证的正则表达式,来自淘宝开放平台,时间是20181206,
    微信小程序web-view(webview) 嵌套H5页面 唤起微信支付的实现方案
    HTTP请求头及其作用 转
    sql server 只读帐号设置能读取存储过程,view等内容。
    PhantomJS命令行选项
    XML实体注入漏洞
    XmlDocument 避免XXE
    Centos7.6安装redis
  • 原文地址:https://www.cnblogs.com/lsyy2020/p/14826584.html
Copyright © 2020-2023  润新知