• 二分法基本思路和实现


    🚀 优质资源分享 🚀

    学习路线指引(点击解锁)知识定位人群定位
    🧡 Python实战微信订餐小程序 🧡进阶级本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
    💛Python量化交易实战💛入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

    二分法基本思路和实现

    作者:Grey

    原文地址:

    博客园:二分法基本思路和实现

    CSDN: 二分法基本思路和实现

    在一个有序数组中,找某个数是否存在

    OJ 见:LeetCode 704. Binary Search

    思路:

    1. 由于是有序数组,可以先得到中点位置,中点可以把数组分为左右半边。
    2. 如果中点位置的值等于目标值,直接返回中点位置。
    3. 如果中点位置的值小于目标值,则去数组中点左侧按同样的方式寻找。
    4. 如果中点位置的值大于目标值,则取数组中点右侧按同样的方式寻找。
    5. 如果最后没有找到,则返回:-1。

    代码

    class Solution {
        public int search(int[] arr, int t) {
            if (arr == null || arr.length < 1) {
                return -1;
            }
            int l = 0;
            int r = arr.length - 1;
            while (l <= r) {
                int m = l + ((r - l) >> 1);
                if (arr[m] == t) {
                    return m;
                } else if (arr[m] > t) {
                    r = m - 1;
                } else {
                    l = m + 1;
                }
            }
            return -1;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    时间复杂度 O(logN)

    在一个有序数组中,找大于等于某个数最左侧的位置

    OJ见:LeetCode 35. Search Insert Position

    示例 1:
    输入: nums = [1,3,5,6], target = 5
    输出: 2

    说明:如果要在num这个数组中插入 5 这个元素,应该是插入在元素 3 和 元素 5 之间的位置,即 2 号位置。

    示例 2:
    输入: nums = [1,3,5,6], target = 2
    输出: 1

    说明:如果要在num这个数组中插入 2 这个元素,应该是插入在元素 1 和 元素 3 之间的位置,即 1 号位置。

    示例 3:
    输入: nums = [1,3,5,6], target = 7
    输出: 4

    说明:如果要在num这个数组中插入 7 这个元素,应该是插入在数组末尾,即 4 号位置。

    通过上述示例可以知道,这题本质上就是求在一个有序数组中,找大于等于某个数最左侧的位置,如果不存在,就返回数组长度(表示插入在最末尾位置)

    我们只需要在上例基础上进行简单改动即可,上例中,我们找到满足条件的位置就直接return

    if (arr[m] == t) {
        return m;
    }
    
    
    • 1
    • 2
    • 3
    • 4

    在本问题中,因为要找到最左侧的位置,所以,在遇到相等的时候,只需要先把位置记录下来,不用直接返回,然后继续去左侧找是否还有满足条件的更左边的位置。

    同时,在遇到arr[m] > t条件下,也需要记录下此时的m位置,因为这也可能是满足条件的位置。

    代码:

    class Solution {
        public static int searchInsert(int[] arr, int t) {
            int ans = arr.length;
            int l = 0;
            int r = arr.length - 1;
            while (l <= r) {
                int m = l + ((r - l)>>1);
                if (arr[m] >= t) {
                    ans = m;
                    r = m - 1;
                } else  {
                    l = m + 1;
                } 
            }
            return ans;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    整个算法的时间复杂度是O(logN)

    在排序数组中查找元素的第一个和最后一个位置

    OJ见:LeetCode 34. Find First and Last Position of Element in Sorted Array

    思路

    本题也是用二分来解,当通过二分找到某个元素的时候,不急着返回,而是继续往左(右)找,看能否找到更左(右)位置匹配的值。

    代码如下:

    class Solution {
        public static int[] searchRange(int[] arr, int t) {
            if (arr == null || arr.length < 1) {
                return new int[]{-1, -1};
            }
            return new int[]{left(arr,t),right(arr,t)};   
        }
        public static int left(int[] arr, int t) {
            if (arr == null || arr.length < 1) {
                return -1;
            }
            int ans = -1;
            int l = 0;
            int r = arr.length - 1;
            while (l <= r) {
                int m = l + ((r - l) >> 1);
                if (arr[m] == t) {
                   ans = m;
                   r = m - 1;
                } else if (arr[m] < t) {
                    l = m +1;
                } else {
                    // arr[m] > t
                    r = m - 1;
                }
            }
            return ans;
        }
        public static int right(int[] arr, int t) {
            if (arr == null || arr.length < 1) {
                return -1;
            }
            int ans = -1;
            int l = 0;
            int r = arr.length - 1;
            while (l <= r) {
                int m = l + ((r - l) >> 1);
                if (arr[m] == t) {
                   ans = m;
                   l = m + 1;
                } else if (arr[m] < t) {
                    l = m +1;
                } else {
                    // arr[m] > t
                    r = m - 1;
                }
            }
            return ans;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    时间复杂度 O(logN)

    局部最大值问题

    OJ见:LeetCode 162. Find Peak Element

    思路

    假设数组长度为N,首先判断0号位置的数和N-1位置的数是不是峰值位置。

    0号位置只需要和1号位置比较,如果0号位置大,0号位置就是峰值位置,可以直接返回。

    N-1号位置只需要和N-2号位置比较,如果N-1号位置大,N-1号位置就是峰值位置,可以直接返回。

    如果0号位置和N-1在上轮比较中均是最小值,那么数组的样子必然是如下情况:

    image

    由上图可知,[0..1]区间内是增长趋势, [N-2...N-1]区间内是下降趋势。

    那么峰值位置必在[1...N-2]之间出现。

    此时可以通过二分来找峰值位置,先来到中点位置,假设为mid,如果中点位置的值比左右两边的值都大:

    arr[mid] > arr[mid+1] && arr[mid] > arr[mid-1]
    
    
    • 1
    • 2

    mid位置即峰值位置,直接返回。

    否则,有如下两种情况:

    情况一:mid 位置的值比 mid - 1 位置的值小

    趋势如下图:

    image

    则在[1...(mid-1)]区间内继续二分。

    情况二:mid 位置的值比 mid + 1 位置的值小

    趋势是:

    image

    则在[(mid+1)...(N-2)]区间内继续上述二分。

    完整代码

    public class LeetCode\_0162\_FindPeakElement {
        public static int findPeakElement(int[] nums) {
            if (nums.length == 1) {
                return 0;
            }
            int l = 0;
            int r = nums.length - 1;
            if (nums[l] > nums[l + 1]) {
                return l;
            }
            if (nums[r] > nums[r - 1]) {
                return r;
            }
            l = l + 1;
            r = r - 1;
            while (l <= r) {
                int mid = l + ((r - l) >> 1);
                if (nums[mid] > nums[mid + 1] && nums[mid] > nums[mid - 1]) {
                    return mid;
                }
                if (nums[mid] < nums[mid + 1]) {
                    l = mid + 1;
                } else if (nums[mid] < nums[mid - 1]) {
                    r = mid - 1;
                }
            }
            return -1;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    时间复杂度O(logN)

    以上就是二分法的基本用法,更多地

    使用二分法来解决的问题

    更多

    算法和数据结构笔记

  • 相关阅读:
    Spring Cloud Gateway 服务网关的部署与使用详细介绍
    基于SSM的高校宿舍寝室管理系统
    人工智能算法工程师(高级)课程11-自然语言处理之NLP的语言模型-seq2seq模型,seq+注意力与代码详解
    【Github】 Github修改仓库的基本信息
    我的大学期末网页作业 仿学校网站制作实现 HTML+CSS西北大学新闻网带psd带js
    040:vue项目中 transition 动画实现推拉门效果
    【中阳期货】如何判断入场点
    Pytorch模型训练实用教程学习笔记:一、数据加载和transforms方法总结
    类的装饰器
    FS2119A同步升压IC输出3.3V和FS2119B同步升压IC输出5V
  • 原文地址:https://blog.csdn.net/qq_43479892/article/details/126515768