【牛客刷题记录】【JAVA】二分查找

news2024/12/24 22:16:08

(1) 二分查找

链接
二分查找需要序列是有序的,否则二分查找会失效。原理就是如果找的值比mid小,那么[mid,R]的内容就不需要再查找了,反之如果大于mid位置的值,则在[L,mid]内的值也不需要再查找。同时将L/R的值进行修改。注意循环结束的条件为L<=R。

public int search (int[] nums, int target) {
        // write code here
        if(nums.length==0 || nums.length==1&&nums[0]!=target){
            return -1;
        }
        int L=0, R=nums.length;
        while(L<=R){
            int mid=(L+R)/2;
            if(nums[mid]==target){
                return mid;
            }else if(nums[mid]<target){
                L=mid+1;
            }else{
                R=mid-1;
            }
        }

        return -1;
    }

(2)寻找峰值

链接
最普通的方法就是O(n),即从头到尾遍历,找到山峰就返回。

public int findPeakElement (int[] nums) {
        // write code here
        if(nums.length==1){
            return 0;
        }
        int i;
        for(i=0; i<nums.length; i++){
            if(i==0 && nums[i]>nums[i+1]){
                break;
            }else if(i==nums.length-1 && nums[i]>nums[i-1]){
                break;
            }else if(i>0 && nums[i]>nums[i-1] && nums[i]>nums[i+1]){
                break;
            }
        }
       return i;
    }

但如果使用二分查找的方法,就会更快,即O(logN)。当然,我们需要证明一下正确性:

  • 如果 nums[mid] 大于 nums[mid + 1],则在 mid 左侧(包括 mid)必定存在一个峰值。这是因为如果 nums[mid] 是一个下降点,那么在左侧必定存在一个局部最大值。
    在这里插入图片描述
    例如上图,mid大于mid+1的位置,那么右侧是可能没有峰值的。但左侧必定存在峰值。要么就是mid为峰值,要么就是mid-1更大,而就需要比较mid-2。(有一点递归的意思),而我们的设定是nums[-1] = nums[n] = −∞,因此左侧必定出现峰值。
  • 如果 nums[mid] 小于 nums[mid + 1],则在 mid 右侧(不包括 mid)必定存在一个峰值。这是因为如果 nums[mid] 是一个上升点,那么在右侧必定存在一个局部最大值。
    正确性可以得到了,那么我们就可以写代码,用二分查找的思路:
public int findPeakElement (int[] nums) {
        // write code here
        int left = 0;
        int right = nums.length - 1;

        while (left < right) {
            int mid = (right + left) / 2;

            if (nums[mid] > nums[mid + 1]) {
                // 峰值在左边
                right = mid;
            } else {
                // 峰值在右边
                left = mid + 1;
            }
        }

        return left;
    }

注意,一定会存在峰值,因此不需要我们特殊去判断是否为峰值,结束循环返回结果即可,这样可以让代码非常整洁。注意,和二分查找不一样,我们更新right不能为mid-1,否则可能找不到峰值。如下所示:
在这里插入图片描述

(3) 数组中的逆序对

链接
最简单的方法自然就是遍历,但这样的时间复杂度会很大,肯定不是优选。
我们可以用归并排序的思路。
假设我们有以下未排序的数组:

[8, 4, 2, 1]

我们想要计算这个数组中的逆序对的数量。逆序对是指数组中的两个数字,如果它们的原始位置是i和j,且i < j但A[i] > A[j],那么它们就构成一个逆序对。

让我们使用归并排序的过程来计算逆序对:

  • 第一步:分解

将数组分解为更小的数组:

[8, 4] [2, 1]

继续分解:

[8] [4] [2] [1]
  • 第二步:合并并计算逆序对

现在我们开始合并这些数组,并在合并过程中计算逆序对。

合并 [8] 和 [4]:

比较 8 和 4,发现 8 > 4,因此它们构成一个逆序对。我们将逆序对的数量增加 1,得到 1。
合并后的数组是 [4, 8]。
合并 [2] 和 [1]:

比较 2 和 1,发现 2 > 1,因此它们构成一个逆序对。我们将逆序对的数量增加 1,得到 2。
合并后的数组是 [1, 2]。
现在我们有 [4, 8] 和 [1, 2] 两个已排序的数组,接下来合并这两个数组:

比较 4 和 1、4 和 2,逆序数加2。
比较 8 和 1、8 和 2,逆序数夹2.因此最终逆序数为6.
最终合并后的数组是 [1, 2, 4, 8]。

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型一维数组
     * @return int整型
     */private static final int MOD = 1000000007;

    public int InversePairs(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int[] copy = new int[nums.length];
        System.arraycopy(nums, 0, copy, 0, nums.length);
        return (int) mergeSort(nums, copy, 0, nums.length - 1);
    }

    private long mergeSort(int[] nums, int[] copy, int start, int end) {
        if (start >= end) {
            return 0;
        }
        int mid = start + (end - start) / 2;
        long left = mergeSort(copy, nums, start, mid) % MOD;
        long right = mergeSort(copy, nums, mid + 1, end) % MOD;
        int i = mid, j = end;
        int copyIndex = end;
        long count = 0;
        while (i >= start && j > mid) {
            if (nums[i] > nums[j]) {
                count += j - mid;
                copy[copyIndex--] = nums[i--];
                if (count >= MOD) {
                    count %= MOD;
                }
            } else {
                copy[copyIndex--] = nums[j--];
            }
        }
        while (i >= start) {
            copy[copyIndex--] = nums[i--];
        }
        while (j > mid) {
            copy[copyIndex--] = nums[j--];
        }
        for (i = start; i <= end; i++) {
            nums[i] = copy[i];
        }
        return (left + right + count) % MOD;
    }

}

(4) 旋转数组的最小数字

链接

我们可以把数组分为两部分,如图所示:
在这里插入图片描述
旋转数组的特点这两个子数组也是非递减的,这也就可以推断出,mid的值可能大于最右端的值,也可以小于(先不讨论等于)。

  • 如果大于最右端的值,则意味着现在的mid指向的位置在第一个子数组中
  • 如果小于最右端的值,则意味着现在的mid指向的位置在第二个子数组中。
    如果是第一种情况,则需要移动left,这样就可以逼近最小值。如果是第二种情况,就移动right,这样可以逼近最小值。
    如果出现相同元素,例如:
22212

这样是无法确定怎么移动的,我们可以将right左移。

public int minNumberInRotateArray (int[] nums) {
        // write code here
        int left = 0, right = nums.length - 1, mid = 0;
        while (left <= right) {
            mid = (left + right) / 2;
            if (nums[mid] > nums[right]) {
                left = mid + 1;
            } else if (nums[mid] < nums[right]) {
                right = mid;
            } else {
                // 当 nums[mid] 和 nums[right] 相等时,无法确定最小值的位置
                // 将右指针左移一位
                right--;
            }
        }
        return nums[mid];
    }

(5) 比较版本号

链接
可以用双指针,在while里比较每两个.之间值的大小。每次都循环直到达到最大长度或者遇到.,然后计算出两个.中间值的大小,并且进行比较。如果一个版本已经遍历完但另一个还没有,也可以继续循环,这就相当于遍历完的版本号后面多出的0,因为我们的tmp设置都为0,所以不影响比较。

version1:2.0.0.1
version2:2

比如这个用例,在version2遍历完后仍可以继续执行whileversion1中间的两个0在计算时得到的tmp1都为0,这与tmp2相等,因此相当于version2也为2.0.0.0

public int compare (String version1, String version2) {
        // write code here
        int len1=version1.length(), len2=version2.length();
        int i=0, j=0;

        while(i<len1 || j<len2){
            long tmp1=0;
            while(i<len1 && version1.charAt(i)!='.'){
                tmp1= tmp1*10 + (version1.charAt(i)-'0');
                i++;
            }
            
            long tmp2=0;
            while(j<len2 && version2.charAt(j)!='.'){
                tmp2= tmp2*10 + (version2.charAt(j)-'0');
                j++;
            }
            i++;j++; // 跳过'.'
            if(tmp1!=tmp2){
                return tmp1<tmp2? -1: 1;
            }

        }

        return 0;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2181970.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机毕业设计 基于深度学习的短视频内容理解与推荐系统的设计与实现 Python+Django+Vue 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

景联文科技入选《2024中国AI大模型产业图谱2.0版》数据集代表厂商

近日&#xff0c;大数据产业领域头部媒体数据猿携手上海大数据联盟联合发布了备受瞩目的《2024中国AI大模型产业图谱2.0版》。以大数据与AI为代表的智能技术为主要视角&#xff0c;聚焦全产业链&#xff0c;为业内提供更为专业直观的行业指导。 景联文科技凭借高质量数据集&…

第十一届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)(大学组)

一.题目分析 &#xff08;1&#xff09;.题目 &#xff08;2&#xff09;.题目分析 1.计时分析 只要遇到Vmin&#xff0c;就将计时时间重置为0&#xff0c;直到遇到Vmax结束计时 2.按键功能分析 a.B1显示和功能页面相互切换 b.B2每次按下Vmax加0.1&#xff0c;加到3.3V&a…

怀孕之天赋共享:其实人身体没变,完全是天赋共享

关于怀孕天赋共享&#xff0c;有人说&#xff0c;是不是怀孕导致身体变化&#xff1f; 并没有。下面这个就是案例。你总不能说&#xff0c;小孩生下来身体立即改变吧&#xff1f;

【大模型系列篇】动手部署实践国产文生图模型-腾讯混元DiT

首个中英双语DiT架构&#xff0c;混元-DiT&#xff0c;高性能细粒度中文理解-多分辨率扩散Transformer模型。 腾讯提出的混元DiT&#xff0c;是一个基于Diffusion transformer的文本到图像生成模型&#xff0c;此模型具有中英文细粒度理解能力。为了构建混元DiT&#xff0c;精心…

plt绘画三维曲面

目录 前言实战 前言 如果想绘画三维曲面&#xff0c;需导入Axes3D 模块&#xff0c;具体语法可参考&#xff1a; from mpl_toolkits.mplot3d import Axes3D问题的关键是需要三维坐标对象与figure相关联&#xff0c;这里可以使用如下两种方法&#xff0c;亲测可用&#xff01;…

安卓使用memtester进行内存压力测试

memteser简介 memtester 是一个用于测试内存可靠性的工具。 它可以对计算机的内存进行压力测试&#xff0c;以检测内存中的错误&#xff0c;例如位翻转、随机存取错误等。memtester 可以在不同的操作系统上运行&#xff0c;并且可以针对不同大小的内存进行测试。 下载源码 m…

企业微信hook协议接口,群发,标签,客户管理。

服务提供了丰富的API和SDK&#xff0c;可以在企微的功能之上进行应用开发和功能扩展 自建应用可以调用企微hook或协议提供的接口来实现数据交互&#xff0c;可以直接调用hook或协议接口提供的功能来进行消息的发送与接收、用户管理、应用管理等操作&#xff0c;通过接口可以实…

用Python实现运筹学——Day 8: 对偶理论的经济解释

一、学习内容 1. 对偶价格的经济含义 对偶价格&#xff08;Dual Price&#xff09;&#xff0c;也称为影子价格&#xff08;Shadow Price&#xff09;&#xff0c;反映了在线性规划问题中的某个约束条件下&#xff0c;单位资源的边际价值。影子价格是对每一单位资源的增加所带…

1.7 编码与调制

欢迎大家订阅【计算机网络】学习专栏&#xff0c;开启你的计算机网络学习之旅&#xff01; 文章目录 前言前言1 基本术语2 常用的编码方法2.1 不归零编码2.2 归零编码2.3 反向归零编码2.4 曼彻斯特编码2.5 差分曼彻斯特编码 3 常用的调制方法3.1 调幅&#xff08;AM&#xff09…

plt等高线图的绘制

目录 np.meshgrid()plt.contour()实战 np.meshgrid() np.meshgrid 是 NumPy 中的一个函数&#xff0c;用于生成多维坐标网格。它通常用于在多维空间中创建坐标点的组合&#xff0c;以便进行向量化的计算或者绘制三维图形。 基本语法&#xff1a; X, Y np.meshgrid(x, y) 参…

车视界系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;汽车品牌管理&#xff0c;汽车颜色管理&#xff0c;用户管理&#xff0c;汽车信息管理&#xff0c;汽车订单管理系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;汽车信息&#xff0c;我…

【C++】多态练习题(面试常考)

学习之前&#xff0c;建议观看&#xff1a;【C】多态&#xff1a;深度剖析&#xff08;多态、虚函数、抽象类、底层原理&#xff09;_c 多态和虚函数,虚函数的实现原理-CSDN博客https://blog.csdn.net/2301_80555259/article/details/142178677?spm1001.2014.3001.5501 一.概念…

echarts X轴出现小数点问题解决方案

问题描述 当X轴数据较小时&#xff0c;X轴的坐标会用小数点将数据撑开&#xff0c;使其均匀显示&#xff0c;如下图所示&#xff1a; 因业务需要不希望出现小数点&#xff0c;该怎么解决呢&#xff1f; 查找一番&#xff0c;解决方案如下&#xff1a; xAxis: {minInterval:…

2-108 基于matlab的模板匹配法实现车牌识别

基于matlab的模板匹配法实现车牌识别&#xff0c;包含完整的字符库和案例车牌。选择待识别车牌&#xff0c;对车牌图像进行边缘检测、腐蚀、平滑、定位彩色、滤波、最小化区域等一系列操作&#xff0c;分割出字符区域&#xff0c;并与全字符模板库比较&#xff0c;得到最终的车…

【LeetCode每日一题】——95.不同的二叉搜索树 II

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 回溯 二【题目难度】 中等 三【题目编号】 95.不同的二叉搜索树 II 四【题目描述】 给你一…

NASA数据集:ATLAS/ICESat-2 L3B 每日和每月网格化海冰自由面高度,第 4 版

目录 简介 摘要 代码 引用 网址推荐 0代码在线构建地图应用 机器学习 ATLAS/ICESat-2 L3B Daily and Monthly Gridded Sea Ice Freeboard, Version 4 简介 ATLAS/ICESat-2 L3B Daily and Monthly Gridded Sea Ice Freeboard, Version 4数据是由NASA的ATLAS&#xff08…

idea.vmoptions 最佳配置

1. 推荐的 idea64.exe.vmoptions 配置&#xff1a; -Xms1024m -Xmx4096m -XX:ReservedCodeCacheSize512m -XX:UseG1GC -XX:SoftRefLRUPolicyMSPerMB50 -XX:CICompilerCount4 -XX:HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -Dsun.io.useCanonCachesfalse -Dj…

【React 】入门Day01 —— 从基础概念到实战应用

目录 一、React 概述 二、开发环境创建 三、JSX 基础 四、React 的事件绑定 五、React 组件基础使用 六、组件状态管理 - useState 七、组件的基础样式处理 快速入门 – React 中文文档 一、React 概述 React 是什么 由 Meta 公司开发&#xff0c;是用于构建 Web 和原生…

RabbitMQ的应用问题

一、幂等性保障 幂等性是数学和计算机科学中某些运算的性质, 它们可以被多次应⽤, ⽽不会改变初始应⽤的结果 数学上的幂等性&#xff1a; f(x)f(f(x)) |x| 数据库操作幂等性&#xff1a; 数据库的 select 操作. 不同时间两次查询的结果可能不同, 但是这个操作是符合幂等性…