二分法相关使用

这篇具有很好参考价值的文章主要介绍了二分法相关使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

在线OJ:704. 二分查找

有序数组下的二分思路如下:

  • 由于这里是有序数组, 我们可以可以先得到中点位置, 中点可以把数组分为左右两边;
  • 如果中点位置的值等于目标值, 直接返回中点位置;
  • 如果中点位置的值小于目标值, 则去数组中点左侧按同样的方式查找;
  • 如果中点位置的值大于目标值, 则取数组中点右侧按同样的方式查找;
  • 如果最后没有找到, 则返回 -1.

代码实现如下:

class Solution {
    public int search(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        int left = 0;
        int right = nums.length - 1;
        int mid = 0;
        while (left < right) {
            mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return -1;
    }
}

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

在线OJ: 35. 搜索插入位置

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

这个题只需要在 1 代码基础上进行简单改动即可, 在 1 中, 我们找到满足条件的位置就直接返回了; 而在本题中, 因为要找到最左侧的位置, 所以, 在遇到 nums[mid] >= target 的时候, 不用直接返回, 而是先把位置 mid 记录下来, 然后继续去左侧找是否还有满足条件的更左边的位置.

代码实现如下:

class Solution {
    public int searchInsert(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        int left = 0;
        int right = nums.length - 1;
        int mid = 0;
        int ans = nums.length;
        while (left <= right) {
            mid = left + (right - left) / 2;
            if (nums[mid] >= target) {
                ans = mid;
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return ans;
    }
}

3. 在一个有序数组中, 找小于等于某个数最右侧的位置

和 2 的实现基本是一样的, 就不赘述了, 代码如下:

/**
 * 有序数组中找到 <=num 最右的位置
 */
public static int mostRightIndex(int[] arr, int num) {
    if (arr == null || arr.length == 0) {
        return -1;
    }
    int left = 0;
    int right = arr.length - 1;
    int mid = 0;
    int ans = -1;
    while (left <= right) {
        mid = left + (right - left) / 2;
        if (arr[mid] <= num) {
            ans = mid;
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return ans;
}

4. 局部最大值问题

在线OJ:162. 寻找峰值

思路如下:

题目中已经说明, 对于所有有效的 i 都有nums[i] != nums[i + 1], 所以, 不会出现相邻相等的情况.

假设数组长度为 N, 首先判断 0 号位置的数和 N-1 号位置的数是不是峰值位置; 0 号位置只需要和 1 号位置比较, 如果 0 号位置大; 0 号位置就是峰值位置 (0 号位置位置左边没有元素, 可以认为是无穷小), 可以直接返回.

N-1 号位置只需要和 N-2 号位置比较, 如果 N-1 号位置大, N-1 号位置就是峰值位置 (N-1 号位置右边没有元素, 可以认为是无穷大), 可以直接返回.

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

二分法相关使用

由上图可知, 0 到 1 这段是增长趋势, N-2 到 N-1 这段是下降趋势, 那么峰值位置必在[1…N-2]之间出现;

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

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

则 mid 位置就是峰值位置, 直接返回即可.

否则, 有如下两种情况:

  • 情况一, mid 位置的值比 mid - 1 位置的值小, 趋势如下图, 此时可以在[1...(mid-1)]区间内继续二分;

二分法相关使用

  • 情况二, mid 位置的值比 mid + 1 位置的值小, 趋势如下图, 此时可以在[(mid+1)...(N-2)]区间内继续二分;

二分法相关使用

如果最后都没找到, 返回 -1 即可.

代码实现如下:

class Solution {
    public int findPeakElement(int[] arr) {
        int len = arr.length;
        if (arr == null || len == 0) {
            return -1;
        }
        if (len == 1) {
            return 0;
        }
        if (arr[0] > arr[1]) {
            return 0;
        }
        if (arr[len - 1] > arr[len - 2]) {
            return len - 1;
        }

        int left = 1;
        int right = len - 2;
        int mid= 0;
        while (left <= right) {
            mid = left + (right-left) / 2;
            if (arr[mid] > arr[mid-1] && arr[mid] > arr[mid + 1]) {
                return mid;
            }
            if (arr[mid] < arr[mid - 1]) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return -1;
    }
}

补充一下如果想要实现找局部最小值的话, 思路是一样的, 把代码符号改改就行了, 代码如下:文章来源地址https://www.toymoban.com/news/detail-467501.html

/**
 * 局部最小值问题
 * arr数组中的元素直接一定是相邻不相等的元素
 * 可以是无序的
 */
// 返回任意一个局部最小值即可
public static int oneMinIndex(int[] arr) {
    int len = arr.length;
    if (arr == null || len == 0) {
        return -1;
    }
    if (len == 1) {
        return 0;
    }
    if (arr[0] < arr[1]) {
        return 0;
    }
    if (arr[len - 1] < arr[len - 2]) {
        return len - 1;
    }

    int left = 1;
    int right = len - 2;
    int mid= 0;
    while (left <= right) {
        mid = (left + right) / 2;
        if (arr[mid] > arr[mid - 1]) {
            right = mid - 1;
        } else if (arr[mid] > arr[mid + 1]) {
            left = mid + 1;
        } else {
            return mid;
        }
    }
    
    return -1;
}

到了这里,关于二分法相关使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 二分法MATLAB代码

    本质是通过不断进行区间压缩来获取函数零点。 二分法的终止条件:区间长度小于等于精度要求 。 流程: 如下图所示:

    2024年02月05日
    浏览(46)
  • 二分法简单题

    2024年01月24日
    浏览(55)
  • 初探二分法

    智能化校园:深入探讨云端管理系统设计与实现(一) 智能化校园:深入探讨云端管理系统设计与实现(二) 题目:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 提示: 你可以

    2024年01月25日
    浏览(59)
  • 【算法】—二分法详解

    ①定义: 二分查找算法也称折半搜索算法,对数搜索算法,是一种在 有序数组 中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素

    2024年02月09日
    浏览(52)
  • 【二分查找】一文带你掌握二分法 (附万能模板)

    一、简介 哪怕没有学过编程的同学,也许不知道二分法这个名字,但也一定接触过它的核心思想。不了解的同学也没关系,我用一句话就能概括出它的精髓: 将一个区间一分为二,每次都舍弃其中的一部分。 二分法能够极大地降低我们在解决问题时的时间复杂度。假如你要

    2024年01月19日
    浏览(58)
  • 【剑指Offer】二分法例题

    链表是数据结构中重要的一个章节,他的重要性也不言而喻,在未来不管是笔试还是面试都会遇到这类的题目,所以接下来我就会把一些链表的常考的题目全部整理出来供大家学习指正。 题目链接 描述: 给定一个长度为n的数组nums,请你找到峰值并返回其索引。数组可能包

    2023年04月13日
    浏览(45)
  • 非线性方程二分法

    优点:算法直观、简单、总能保证收敛;局限:收敛速度慢、一般不单独用它求根,仅为了获取根的粗略近似 设 f ( x ) f(x) f ( x ) 在 [ a , b ] [a,b] [ a , b ] 上连续、严格单调、满足条件 f ( a ) f ( b ) 0 f(a)f(b)0 f ( a ) f ( b ) 0 则在区间 [ a , b ] [a,b] [ a , b ] 内必有一根 x ∗ x^* x ∗ 。通

    2024年02月04日
    浏览(48)
  • 牛顿法、割线法、二分法

    牛顿法求解非线性方程组 割线法求解非线性方程组 二分法求解根号3  另外,今天上机课写程序时,发现不同的起始点可以收敛到不同的零点。也许这是一个新的值得研究的地方。 看来,计算数学也是这样,光听理论无法实现大的突破,也没法产生好的想法,必须在实践应用

    2024年02月05日
    浏览(51)
  • 1241:二分法求函数的零点

    【题目描述】 有函数:f(x)=x5−15x4+85x3−225x2+274x−121 已知f(1.5)0,f(2.4)0 且方程f(x)=0在区间[1.5,2.41.5,2.4] 有且只有一个根,请用二分法求出该根。 【输入】 (无) 【输出】 该方程在区间[1.5,2.41.5,2.4]中的根。要求四舍五入到小数点后66位。 【输入样例】 【输出样例】 【AC代码】

    2024年01月25日
    浏览(36)
  • Leetcode刷题笔记——二分法

    二分法是搜索算法中极其典型的方法,其要求输入序列有序并可随机访问。算法思想为 输入:有序数组nums,目的数值target 要求输出:如果target存在在数组中,则输出其index,否则输出-1 将原数组通过[left,right]两个索引划分范围,初值left=0,right=数组的最后一个元素 当left = r

    2024年02月10日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包