返回顶部
首页 > 资讯 > 后端开发 > Python >详解Java中二分法的基本思路和实现
  • 148
分享到

详解Java中二分法的基本思路和实现

2024-04-02 19:04:59 148人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

目录在一个有序数组中,找某个数是否存在在一个有序数组中,找大于等于某个数最左侧的位置在排序数组中查找元素的第一个和最后一个位置局部最大值问题在一个有序数组中,找某个数是否存在 思路

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

思路:

  • 由于是有序数组,可以先得到中点位置,中点可以把数组分为左右半边。
  • 如果中点位置的值等于目标值,直接返回中点位置。
  • 如果中点位置的值小于目标值,则去数组中点左侧按同样的方式寻找。
  • 如果中点位置的值大于目标值,则取数组中点右侧按同样的方式寻找。
  • 如果最后没有找到,则返回:-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;
    }
}

时间复杂度 O(logN)

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

示例 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;
}

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

同时,在遇到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;
    }
}

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

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

思路

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

代码如下:

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;
    }
}

时间复杂度 O(logN)

局部最大值问题

思路

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

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

N-1号位置只需要和N-2号位置比较,如果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)]区间内继续上述二分。

完整代码

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;
    }
}

时间复杂度O(logN)

到此这篇关于详解Java中二分法的基本思路和实现的文章就介绍到这了,更多相关Java二分法内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 详解Java中二分法的基本思路和实现

本文链接: https://lsjlt.com/news/165945.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 详解Java中二分法的基本思路和实现
    目录在一个有序数组中,找某个数是否存在在一个有序数组中,找大于等于某个数最左侧的位置在排序数组中查找元素的第一个和最后一个位置局部最大值问题在一个有序数组中,找某个数是否存在 思路...
    99+
    2024-04-02
  • Java实现二叉树的基本操作详解
    目录1. 二叉树结点的构成2. 二叉树的遍历2.1 前序遍历2.2 中序遍历2.3 后序遍历3. 获取整棵二叉树的节点个数4. 获取二叉树叶子节点的个数5. 获取第K层节点的个数6....
    99+
    2022-11-13
    Java二叉树操作 Java二叉树
  • java实现手机短信验证的基本思路
    本文实例为大家分享了java实现手机短信验证的具体代码,供大家参考,具体内容如下整体流程: 客户填入手机号,通过客户端点击获取验证码按钮,验证手机号是否有效,有效则客户端发送请求到后台服务器,客户端开始倒计时60s,不通过则返回; 服...
    99+
    2023-05-30
    java 手机短信 验证
  • C语言顺序表的基本结构与实现思路详解
    目录一、顺序表的概念与结构1、线性表的解释2、顺序表概念解释二、顺序表的思路及代码实现详解1.静态顺序表的实现2.动态顺序表思路及代码实现2.1 动态顺序表的整体思路2.2 定义结构...
    99+
    2023-02-13
    C语言顺序表 C语言顺序表的创建
  • Java方法递归的思路详解
    目录前言一、什么是方法递归二、什么场景下能用递归三、如何写出递归代码-重点总结前言 今天给老铁们回顾一下递归的思路以及方法,也是给自己的一个归纳总结。 一、什么是方法递归 所谓的方法...
    99+
    2024-04-02
  • PHP laravel实现基本路由配置详解
    目录1.路由的基本介绍2.有效的路由方法3.路由重定向4.路由参数5.路由分组6.兜底路由7.频率限制8.获取当前访问路由属性在使用laravel之前我一直在使用thinkphp还有...
    99+
    2022-11-13
    PHP laravel路由配置 laravel 路由配置 PHP laravel
  • 基于redis实现的点赞功能设计思路详解
    前言 点赞其实是一个很有意思的功能。基本的设计思路有大致两种, 一种自然是用mysql等 数据库直接落地存储, 另外一种就是利用点赞的业务特征来扔到redis(或memcache)中, 然后离线刷回mysq...
    99+
    2022-06-04
    详解 思路 功能设计
  • Java二分查找算法实例详解
    在本文中,我们将介绍二进制搜索相对于简单线性搜索的优势,并介绍它在 Java 中的实现。 1. 需要有效的搜索 假设我们在wine-selling业务和数以百万计的买家每天都访问我们...
    99+
    2022-11-13
    Java 二分查找算法
  • 详解Java 二叉树的实现和遍历
    目录什么是二叉树二叉树建树前序建树中序建树后序建树二叉树的遍历什么是二叉树 简单理解为对于一个节点来说,最多拥有一个上级节点,同时最多具备左右两个下级节点的数据结构。 由于很多排序算...
    99+
    2024-04-02
  • java算法之二分查找法的实例详解
    java算法之二分查找法的实例详解原理假定查找范围为一个有序数组(如升序排列),要从中查找某一元素,如果该元素在此数组中,则返回其索引,否则返回-1。通过数组长度可取出中间位置元素的索引,将其值与目标值比较,如果中间位置元素值大于目标值,则...
    99+
    2023-05-31
    java 算法 二分查找法
  • Java基于ShardingSphere实现分库分表的实例详解
    目录一、简介二、项目使用1、引入依赖2、数据库3、实体类4、mapper5、yml配置6、测试类7、数据一、简介   Apache ShardingSphere ...
    99+
    2024-04-02
  • SQL Server使用脚本实现自动备份的思路详解
    因服务器安装的SQL Server版本不支持自动定时备份,需自行实现,大概思路为: 创建备份数据库的脚本 创建批处理脚本执行步骤一中的脚本 创建Window...
    99+
    2024-04-02
  • java 中基本算法之希尔排序的实例详解
    java 中基本算法之希尔排序的实例详解希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。希尔排序是把记录...
    99+
    2023-05-31
    java 希尔排序 ava
  • 基于SpringBoot+Vue的毕业设计与实现——Java毕设思路分享
    毕设选题经验分享:很多互联网专业的小伙伴们在选择自己的毕设主题的时候不知道做什么,在这时候就可以结合生活日常和当下较为流行的事物,通过对往年毕设的项目进行总结归纳,主题基本上都离不开旅游管理、移动办公...
    99+
    2023-10-08
    java spring boot idea vue.js 后端
  • Java栈和基础队列的实现详解
    目录栈(stack)栈支持的三个核心操作:栈的常见实际应用:栈的实现队列无论是哪种队列,都必须支持三个核心操作:基础队列的实现 栈和队列:都是线性表,都是基于List基础上...
    99+
    2024-04-02
  • redis实现共同好友的思路详解
    目录背景共同好友实现思路交集并集差集更多set命令说明:背景 ​ 微信朋友圈的点赞、评论,只能看到自己好友的信息。这就涉及到了一个共同好友的概念,通过redis的set集...
    99+
    2024-04-02
  • Android Compose实现伸缩ToolBar的思路详解
    目录ScrollableAppBar效果图主要思路布局预览实现过程ScrollableAppBar 效果图 当列表向上移动时,会先带动ToolBar向上位移,等ToolB...
    99+
    2024-04-02
  • Java将时间按月份分段的实现思路与方法
    前言 有时候我们得到一段时间,需要将时间按照月份将这一段时间来分段。比如开始时间为 2020/07/15 至 2021/07/05 按照月份来将数据分组展示,所以需要将这端时间分为...
    99+
    2024-04-02
  • 详谈Java中的二进制及基本的位运算
    二进制是计算技术中广泛采用的一种数制。二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”,由18世纪德国数理哲学大师莱布尼兹发现。当前的计算机系统使用的基本上是二进制系统,数据在计算机中主要...
    99+
    2023-05-31
    java 二进制 位运算
  • 详解Java实现分治算法
    目录一、前言二、分治算法介绍三、分治算法经典问题3.1、二分搜索3.2、快速排序3.3、归并排序(逆序数)3.4、最大子序列和3.5、最近点对四、结语一、前言 在学习分治算法之前,问...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作