1.了解数据结构和算法

news2024/12/24 2:26:54

1.了解数据结构和算法

1.1 二分查找

        二分查找(Binary Search)是一种在有序数组中查找特定元素的搜索算法。它的基本思想是将数组分成两半,然后比较目标值与中间元素的大小关系,从而确定应该在左半部分还是右半部分继续查找。这个过程不断重复,直到找到目标值或确定它不存在于数组中。

1.1.1 二分查找的实现

(1)循环条件使用 "i <= j" 而不是 "i < j" 是因为,在二分查找的过程中,我们需要同时更新 i 和 j 的值。当 i 和 j 相等时,说明当前搜索范围只剩下一个元素,我们需要检查这个元素是否是我们要找的目标值。如果这个元素不是我们要找的目标值,那么我们可以确定目标值不存在于数组中。

如果我们将循环条件设置为 "i < j",那么当 i 和 j 相等时,我们就无法进入循环来检查这个唯一的元素,这会导致我们无法准确地判断目标值是否存在。

因此,在二分查找的循环条件中,我们应该使用 "i <= j",以确保我们在搜索范围内包含所有可能的元素。

(2)如果你使用 "i + j / 2" 来计算二分查找的中间值,可能会遇到整数溢出的问题。这是因为在 Java 中,整数除法(/)对整数操作时会向下取整,结果仍然是一个整数。例如,如果 ij 都是很大的数,且它们相加结果大于 Integer.MAX_VALUE(即 2^31 - 1),那么直接将它们相加再除以 2 就会导致溢出,因为中间结果已经超出了 int 类型的最大值(会变成负数)。

public static void main(String[] args) {
         int[]arr={1,22,33,55,88,99,117,366,445,999};
        System.out.println(binarySearch( arr,1));//结果:0
        System.out.println(binarySearch( arr,22));//结果:1
        System.out.println(binarySearch( arr,33));//结果:2
        System.out.println(binarySearch( arr,55));//结果:3
        System.out.println(binarySearch( arr,88));//结果:4
        System.out.println(binarySearch( arr,99));//结果:5
        System.out.println(binarySearch( arr,117));//结果:6
        System.out.println(binarySearch( arr,366));//结果:7
        System.out.println(binarySearch( arr,445));//结果:8
        System.out.println(binarySearch( arr,999));//结果:9
        System.out.println(binarySearch( arr,1111));//结果:-1
        System.out.println(binarySearch( arr,-1));//结果:-1

    }
    /**
     * @Description
     * @Author LY
     * @Param [arr, target] 待查找升序数组,查找的值
     * @return int 找到返回索引,找不到返回-1
     * @Date 2023/12/8 16:38
     **/


    
    public static int binarySearch(int[] arr, int target){
        //设置 i跟j 初始值
        int i=0;
        int j= arr.length-1;
        //如果i>j,则表示并未找到该值
        while (i<=j){
            int m=(i+j)>>>1;
//            int m=(i+j)/2;
            if (target<arr[m]){
                //目标在左侧
                j=m-1;
            }else if(target>arr[m]){
                //目标在右侧
                i=m+1;
            }else{
                //相等
                return m;
            }
        }
        return -1;
    }

 1.1.2 二分查找改动版

        方法 binarySearchAdvanced 是一个优化版本的二分查找算法。它将数组范围从 0 到 arr.length 进行划分(改动1),并且在循环条件中使用 i < j 而不是 i <= j (改动2)。这种修改使得当目标值不存在于数组中时,可以更快地结束搜索。此外,在向左移动右边界时,只需将其设置为中间索引 m 而不是 m - 1 (改动3)。

        这些改动使 binarySearchAdvanced 在某些情况下可能比标准二分查找更快。然而,在实际应用中,这些差异通常很小,因为二分查找本身的复杂度已经很低(O(log n))。

/**
     * @return int 找到返回索引,找不到返回-1
     * @Description 二分查找改动版
     * @Author LY
     * @Param [arr, target] 待查找升序数组,查找的值
     * @Date 2023/12/8 16:38
     **/


    public static int binarySearchAdvanced(int[] arr, int target) {
        int i = 0;
//        int j= arr.length-1;
        int j = arr.length;//改动1
//        while (i<=j){
        while (i < j) {//改动2
            int m = (i + j) >>> 1;
            if (target < arr[m]) {
//                j = m - 1;
                j = m; //改动3
            } else if (arr[m] < target) {
                i = m + 1;
            } else {
                return m;
            }
        }
        return -1;
    }

 1.2 线性查找

        线性查找(Linear Search)是一种简单的搜索算法,用于在无序数组或列表中查找特定元素。它的基本思想是从数组的第一个元素开始,逐一比较每个元素与目标值的大小关系,直到找到目标值或遍历完整个数组。

(1)初始化一个变量 index 为 -1,表示尚未找到目标值。
(2)从数组的第一个元素开始,使用循环依次访问每个元素:
(3)如果当前元素等于目标值,则将 index 设置为当前索引,并结束循环。

(4)返回 index。(如果找到了目标值返回其索引;否则返回 -1 表示未找到目标值)

 /**
     * @return int 找到返回索引,找不到返回-1
     * @Description 线性查找
     * @Author LY
     * @Param [arr, target] 待查找数组(可以不是升序),查找的值
     * @Date 2023/12/8 16:38
     **/


    public static int LinearSearch(int[] arr, int target) {
        int index=-1;
        for (int i = 0; i < arr.length; i++) {
            if(arr[i]==target){
                index=i;
                break;
            }
        }
        return index;
    }

1.3 衡量算法第一因素

时间复杂度:算法在最坏情况下所需的基本操作次数与问题规模之间的关系。

1.3.1 对比

假设每行代码执行时间都为t,数据为n个,且是最差的执行情况(执行最多次):

二分查找:

二分查找执行时间为:5L+4:
既5*floor(log_2(x)+1)+4
执行语句执行次数
int i=0;1
int j=arr.length-1;1
return -1;1
循环次数为:floor(log_2(n))+1,之后使用L代替
i<=j;L+1
int m= (i+j)>>>1;L
artget<arr[m]L
arr[m]<artgetL
i=m+1;L

线性查找:

线性查找执行时间为:3x+3
执行语句执行次数
int i=0;1
i<a.length;x+1
i++;x
arr[i]==targetx
return -1;1

对比工具:Desmos | 图形计算器

对比结果:

随着数据规模增加,线性查找执行时间会逐渐超过二分查找。

1.3.2 时间复杂度

        计算机科学中,时间复杂度是用来衡量一个算法的执行,随着数据规模增大,而增长的时间成本(不依赖与环境因素)。

时间复杂度的标识:

        假设要出炉的数据规模是n,代码总执行行数用f(n)来表示:

                线性查找算法的函数:f(n)=3*n+3。

                二分查找算法函数::f(n)=5*floor(log_2(x)+1)+4。

为了简化f(n),应当抓住主要矛盾,找到一个变化趋势与之相近的表示法。

1.3.3 渐进上界

渐进上界代表算法执行的最差情况:

        以线性查找法为例:

                f(n)=3*n+3

                g(n)=n

        取c=4,在n0=3后,g(n)可以作为f(n)的渐进上界,因此大O表示法写作O(n)

        以二分查找为例:

                5*floor(log_2(n)+1)+4===》5*floor(log_2(n))+9

                g(n)=log_2(n)

                O(log_2(n))

1.3.4 常见大O表示法

按时间复杂度,从低到高:

(1)黑色横线O(1):常量时间复杂度,意味着算法时间并不随数据规模而变化。

(2)绿色O(log(n)):对数时间复杂度。

(3)蓝色O(n):线性时间复杂度,算法时间与规模与数据规模成正比。

(4)橙色O(n*log(n)):拟线性时间复杂度。

(5)红色O(n^2):平方时间复杂度。

(6)黑色向上O(2^n):指数时间复杂度。

(7)O(n!):这种时间复杂度非常大,通常意味着随着输入规模 n 的增加,算法所需的时间会呈指数级增长。因此,具有 O(n!) 时间复杂度的算法在实际应用中往往是不可行的,因为它们需要耗费大量的计算资源和时间。

1.4 衡量算法第二因素

空间复杂度:与时间复杂度类似,一般也用O衡量,一个算法随着数据规模增大,而增长的额外空间成本。

1.3.1 对比

以二分查找为例:

二分查找占用空间为:4字节
执行语句执行次数
int i=0;4字节
int j=arr.length-1;4字节
int m= (i+j)>>>1;4字节
二分查找占用空间复杂度为:O(1)

性能分析:

        时间复杂度:

                最坏情况:O(log(n))。

                最好情况:待查找元素在数组中央,O(1)。

        空间复杂度:需要常熟个数指针:i,j,m,额外占用空间是O(1)。

1.5 二分查找改进

在之前的二分查找算法中,如果数据在数组的最左侧,只需要执行L次 if 就可以了,但是如果数组在最右侧,那么需要执行L次 if 以及L次 else if,所以二分查找向左寻找元素,比向右寻找元素效率要高。

(1)左闭右开的区间,i指向的可能是目标,而j指向的不是目标。

(2)不在循环内找出,等范围内只剩下i时,退出循环,再循环外比较arr[i]与target。

(3)优点:循环内的平均比较次数减少了。

(4)缺点:时间复杂度:θ(log(n))。

1.6 二分查找相同元素

1.6.1 返回最左侧

当有两个数据相同时,上方的二分查找只会返回中间的元素,而我们想得到最左侧元素就需要对算法进行改进。(Leftmost)

 public static void main(String[] args) {
        int[] arr = {1, 22, 33, 55, 99, 99, 99, 366, 445, 999};
        System.out.println(binarySearchLeftMost1(arr, 99));//结果:4
        System.out.println(binarySearchLeftMost1(arr, 999));//结果:9
        System.out.println(binarySearchLeftMost1(arr, 998));//结果:-1


    }
    /**
     * @return int 找到相同元素返回返回最左侧查找元素索引,找不到返回-1
     * @Description 二分查找LeftMost
     * @Author LY
     * @Param [arr, target] 待查找升序数组,查找的值
     * @Date 2023/12/8 16:38
     **/
    public static int binarySearchLeftMost1(int[] arr, int target) {
        int i = 0;
        int j = arr.length - 1;
        int candidate = -1;
        while (i <= j) {
            int m = (i + j) >>> 1;
            if (target < arr[m]) {
                j = m - 1;
            } else if (arr[m] < target) {
                i = m + 1;
            } else {
//                return m;  查找到之后记录下来
                candidate=m;
                j=m-1;
            }
        }
        return candidate;
    }

1.6.2 返回最右侧

当有两个数据相同时,上方的二分查找只会返回中间的元素,而我们想得到最右侧元素就需要对算法进行改进。(Rightmost)

​

    public static void main(String[] args) {
        int[] arr = {1, 22, 33, 55, 99, 99, 99, 366, 445, 999};
        System.out.println(binarySearchRightMost1(arr, 99));//结果:6
        System.out.println(binarySearchRightMost1(arr, 999));//结果:9
        System.out.println(binarySearchRightMost1(arr, 998));//结果:-1


    }
    /**
     * @return int 找到相同元素返回返回最右侧侧查找元素索引,找不到返回-1
     * @Description 二分查找RightMost
     * @Author LY
     * @Param [arr, target] 待查找升序数组,查找的值
     * @Date 2023/12/8 16:38
     **/
    public static int binarySearchRightMost1(int[] arr, int target) {
        int i = 0;
        int j = arr.length - 1;
        int candidate = -1;
        while (i <= j) {
            int m = (i + j) >>> 1;
            if (target < arr[m]) {
                j = m - 1;
            } else if (arr[m] < target) {
                i = m + 1;
            } else {
//                return m;  查找到之后记录下来
                candidate=m;
                i = m + 1;
            }
        }
        return candidate;
    }

​

1.6.3 优化

将leftMost优化后,可以在未找到目标值的情况下,返回大于等于目标值最靠左的一个索引。

/**
     * @return int 找到相同元素返回返回最左侧查找元素索引,找不到返回i
     * @Description 二分查找LeftMost
     * @Author LY
     * @Param [arr, target] 待查找升序数组,查找的值
     * @Date 2023/12/8 16:38
     **/
    public static int binarySearchLeftMost2(int[] arr, int target) {
        int i = 0;
        int j = arr.length - 1;
        while (i <= j) {
            int m = (i + j) >>> 1;
            if (target <= arr[m]) {
                j = m - 1;
            } else {
                i = m + 1;
            }
        }
        return i;
    }

将rightMost优化后,可以在未找到目标值的情况下,返回小于等于目标值最靠右的一个索引。

1.6.4 应用场景

1.6.4.1 查排名

(1)查找排名:
        在执行二分查找时,除了返回目标值是否存在于数组中,还可以记录查找过程中遇到的目标值的位置。如果找到了目标值,则直接返回该位置作为排名;如果没有找到目标值,但知道它应该插入到哪个位置才能保持数组有序,则可以返回这个位置作为排名。

         leftMost(target)+1
(2)查找前任(前驱):
        如果目标值在数组中存在,并且不是数组的第一个元素,那么其前任就是目标值左边的一个元素。我们可以在找到目标值之后,再调用一次二分查找函数,这次查找的目标值设置为比当前目标值小一点的数。这样就可以找到目标值左侧最接近它的元素,即前任。

         leftMost(target)-1
(3)查找后任(后继):
        如果目标值在数组中存在,并且不是数组的最后一个元素,那么其后任就是目标值右边的一个元素。类似地,我们可以在找到目标值之后,再调用一次二分查找函数,这次查找的目标值设置为比当前目标值大一点的数。这样就可以找到目标值右侧最接近它的元素,即后任。

         rightMost(target)+1

(3)最近邻居:

        前任和后任中,最接近目标值的一个元素。

1.6.4.2 条件查找元素

(1)小于某个值:0 ~ leftMost(target)-1

(2)小于等于某个值:0 ~ rightMost(target)

(3)大于某个值:rightMost(target)+1 ~ 无穷大

(4)大于等于某个值:leftMost(4) ~ 无穷大

(5)他们可以组合使用。

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

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

相关文章

python读取csv文件

在Python中&#xff0c;你可以使用pandas库来读取CSV文件。以下是一个基本的例子&#xff1a; import pandas as pd# 读取CSV文件data pd.read_csv(filename.csv)# 显示前几行数据print(data.head()) 这里&#xff0c;filename.csv应该被替换为你的CSV文件的实际路径和名称。…

Python:核心知识点整理大全16-笔记

目录 8.2.3 默认值 8.2.4 等效的函数调用 8.2.5 避免实参错误 8.3 返回值 8.3.1 返回简单值 formatted_name.py 8.3.2 让实参变成可选的 8.3.3 返回字典 往期快速传送门&#x1f446;&#xff08;在文章最后&#xff09;&#xff1a; 8.2.3 默认值 编写函数时&#xff…

巧妙的使用WPF中的资源

其实&#xff0c;在wpf中&#xff0c;最核心的就是xaml&#xff0c;因为只有xaml&#xff0c;才能体现出用的是wpf&#xff0c;而不是普通的cs文件&#xff0c;cs文件在winform中等等程序都可以使用的&#xff0c;唯独xaml才是wpf中最重要的&#xff0c;最精华的东西&#xff0…

天软基金经理因子定期报告(2023-12)

天软基金经理因子定期报告&#xff08;2023-12&#xff09;报告概要&#xff1a; 从投资业绩来看&#xff0c;葛兰长期业绩表现优于市场&#xff0c;任职以来年化收益率为12.714%&#xff0c;最大回撤为-53.460%。 从投资能力来看&#xff0c;其选股能力与收益择时能力较为突出…

智能优化算法应用:基于入侵杂草算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于入侵杂草算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于入侵杂草算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.入侵杂草算法4.实验参数设定5.算法结果6.…

Rust语言GUI库之gtk安装

文章目录 工具链安装管理软件vcpkgvcpkg介绍安装vcpkg 安装gtk遇到的问题Rust其他依赖package-confg 工具链安装管理软件vcpkg vcpkg介绍 在使用C/C编写项目时, 引用第三方库是很麻烦的事, 需要手动下载源码然后编译最后再添加到项目里&#xff0c;配置头文件、lib、dll&…

Tensorboard可视化远程服务器上保存的训练文件

方法一&#xff1a; 最简单的&#xff0c;把服务器上的训练权重文件下载到本地&#xff0c;使用本地的tensorboard打开 方法二&#xff1a; 使用VsCode的remote ssh插件&#xff0c;可以通过端口映射&#xff0c;将远程的6006端口映射到本地&#xff0c;直接访本地的6006即可…

华清远见嵌入式学习——QT——作业4

作业要求&#xff1a; 代码运行效果图&#xff1a; 代码&#xff1a; 头文件&#xff1a; #ifndef ALARMCLOCK_H #define ALARMCLOCK_H#include <QWidget> #include <QTimerEvent> #include <QTimer> #include <QTime> #include <QTextToSpeech&g…

优雅玩转实验室服务器(二)传输文件

使用服务器最重要的肯定是传输文件了&#xff0c;我们不仅需要本地的一些资源上传到服务器&#xff0c;好进行实验&#xff0c;也需要将服务器计算得到的实验结果传输到本地&#xff0c;来进行预览或者报告撰写。 首先&#xff0c;由于涉及到服务器操作&#xff0c;我强烈推荐…

[C++进阶]---AVL树模拟实现

目录 1.AVL树的概念2.AVL树模拟实现2.1AVL树节点的定义2.2AVL的插入2.3AVL树的旋转2.3.1左单旋2.3.2右单旋2.3.3右左双旋2.3.3.1旋转情况分析2.3.3.2平衡因子更新分析 2.3.4右左双旋2.3.4.1旋转情况分析2.3.4.2平衡因子更新分析 2.3.5AVL树的验证 3.AVL模拟实现源码4.总结 1.AV…

yarn或者pnpm第一次执行的时候遇到报错yarn : 无法加载文件......因为在此系统上禁止运行脚本

报错&#xff1a; yarn : 无法加载文件 C:\Users\rina2\AppData\Roaming\npm\yarn.ps1&#xff0c;因为在此系统上禁止运行脚本。有关详细信息&#xff0c;请参阅 https:/http://go.microsoft.com/fwlink/?LinkID135170 中的 about_Execution_Policies。 解决方案&#xff1a…

基于龙蜥(AnolisOS7.9)编译ZLMediaKit

系统安装 镜像下载 下载地址&#xff1a;https://openanolis.cn/download VirtualBox 下载地址&#xff1a;https://download.virtualbox.org/virtualbox/7.0.12/VirtualBox-7.0.12-159484-Win.exe ZLMediaKit编译 编译器和Cmake sudo yum -y install gcc sudo yum -y …

移动端机器学习框架 MDL 简介与实践

Mobile-deep-learning&#xff08;MDL&#xff09; MDL 是百度研发的可以部署在移动端的基于卷积神经网络实现的移动端框架&#xff0c;可以应用在图像识别领域。 具体应用&#xff1a;在手机百度 App 中&#xff0c;用户只需要点击自动拍开关&#xff0c;将手机对准物体&…

二、SpringFramework 介绍

2.1 Spring 和 SpringFramework概念 https://spring.io/projects 广义的 Spring&#xff1a;Spring 技术栈&#xff08;全家桶&#xff09; 广义上的 Spring 泛指以 Spring Framework 为基础的 Spring 技术栈。 经过十多年的发展&#xff0c;Spring 已经不再是一个单纯的应…

Linux实操——Tomcat安装

Tomcat安装 一、下载Tomcat包&#xff0c;并通过ftp上传到服务器二、解压安装包三、启动Tomcat四、验证是否安装完成 总结 博主最近项目上线了&#xff0c;终于能愉快的摸鱼了&#xff0c;额。。。那是不存在的&#xff0c;作为最勤奋的码农一份子&#xff0c;也是试着搭建一个…

隔离电源与非隔离式电源

开关电源 文章目录 开关电源前言一、它们之间的区别是什么&#xff1f;二、如何区分它们呢&#xff1f;三、隔离电源与非隔离电源的优缺点四、隔离电源与非隔离电源的选择总结 前言 在产品设计时&#xff0c;倘若没有考虑应用环境对电源隔离的要求&#xff0c;产品到了应用时就…

石油化工园区:安全管理工作中的挑战与措施

石油化工园区&#xff1a;安全管理工作中的挑战与措施 石油化工园区是一种设备设施多且结构复杂的工业园区&#xff0c;涉及到易燃易爆或有毒介质&#xff0c;同时园区内有大量的工作人员和工作车辆等动态参与要素。由于园区的特殊性质&#xff0c;安全管理工作显然具备较高的挑…

外网访问内网服务器使用教程

如何在任何地方都能访问自己家里的笔记本上的应用&#xff1f;如何让局域网的服务器可以被任何地方访问到&#xff1f;有很多类似的需求&#xff0c;我们可以统一用一个解决方案&#xff1a;内网穿透。内网穿透的工具及方式有很多&#xff0c;如Ngrok、Ssh、autossh、Natapp、F…

小学生台灯买什么样的合适?精选专业的学生台灯

随着时代的发展和进步&#xff0c;孩子的教育也提升了很多。但很多家长可能并不知道&#xff0c;其实现在的学生不管处小学还是初高中&#xff0c;他们的学习压力都是比我们以前大很多的。繁重的功课让他们经常用眼过度&#xff0c;这也是如今这么多孩子过早近视的主要原因。所…

妙手ERP特色功能来袭:上线Lazada包邮营销功能,全方位助力卖家高效引流!

包邮是线上消费者作出购买决策的重要因素&#xff0c;据Lazada平台调研显示&#xff1a;73%的受访者希望商品免费配送&#xff0c;有84%的消费者使用过Lazada包邮优惠券&#xff0c;其中75%的消费者对此感到满意。由此可见&#xff0c;包邮已成为打动东南亚消费者下单的主要原因…