二分法

原文首发自https://www.stdstring.com/2020/01/31/er-fen-fa/

准备知识

  • 基本的二分法该如何写
  • 第一个位置,最后一个位置该如何变化
  • Big O,时间复杂度,空间复杂度
  • 什么是递归,二分法用递归如何实现
  • 内存中的栈空间和堆空间有什么区别
  • 什么是 Stack Overflow,什么情况下会造成 Stack Overflow

常见的算法时间复杂度

复杂度可能对应的算法备注
O(1)位运算常数级复杂度,一般面试中不会有
O(logn)二分法,倍增法,快速幂算法,辗转相除法
O(n)枚举法,双指针算法,单调栈算法,KMP算法,Rabin Karp,Manacher’s Algorithm又称作线性时间复杂度
O(nlogn)快速排序,归并排序,堆排序
O(n^2)枚举法,动态规划,Dijkstra
O(n^3)枚举法,动态规划,Floyd
O(2^n)与组合有关的搜索问题
O(n!)与排列有关的搜索问题

二分法的优势

与哈希表的比较

查找一个元素是否存在于某个集合中,通常使用哈希表的算法,可以达到O(1)的时间复杂度,但是,
哈希表通常放在内存里,对于一个含有很多元素的集合来说,哈希表可能就比较吃力了。
此时,使用二分法,便可以显现出优势。

通用二分法模板

代码

public class Solution {
    /**
     * @param A an integer array sorted in ascending order
     * @param target an integer
     * @return an integer
     */
    public int findPosition(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        
        int start = 0, end = nums.length - 1;
        // 要点1: start + 1 < end
        while (start + 1 < end) {
	    // 要点2:start + (end - start) / 2
            int mid = start + (end - start) / 2;
            // 要点3:=, <, > 分开讨论,mid 不+1也不-1
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] < target) {
                start = mid;
            } else {
                end = mid;
            }
        }
        
        // 要点4: 循环结束后,单独处理start和end
        if (nums[start] == target) {
            return start;
        }
        if (nums[end] == target) {
            return end;
        }
        return -1;
    }
}

解析

Q: 为什么要用 start + 1 < end?而不是 start < end 或者 start <= end?

分析:

  • start < end ,结束循环时,筛选范围内还剩 1 个元素
  • start <= end, 结束循环时,筛选范围内没有元素了
  • start + 1 < end, 结束循环时,筛选范围内还剩 2 个元素

A: 为了避免死循环。二分法的模板中,整个程序架构分为两个部分:

  1. 通过 while 循环,将区间范围从 n 缩小到 2 (只有 start 和 end 两个点)。
  2. 在 start 和 end 中判断是否有解。
    start < end 或者 start <= end 在寻找目标最后一次出现的位置的时候,出现死循环。

Q: 为什么明明可以 start = mid + 1 偏偏要写成 start = mid?

A: 大部分时候,mid 是可以 +1 和 -1 的。在一些特殊情况下,比如寻找目标的最后一次出现的位置时,当 target 与 nums[mid] 相等的时候,是不能够使用 mid + 1 或者 mid - 1 的。因为会导致漏掉解。那么为了节省脑力,统一写成 start = mid / end = mid 并不会造成任何解的丢失,并且也不会损失效率——log(n) 和 log(n+1) 没有区别。

原文首发自https://www.stdstring.com/2020/01/31/er-fen-fa/

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值