二分、复杂度、动态数组、哈希表

news2024/11/17 16:23:29

1.二分法 不一定一定有序,比如找局部最小值就可以不有序

有序数组中找到num

对数器生成随机数组来校验find()方法是否正确

public class Code01_BSExist {
    //有序数组中找到num
    //arr保证有序
    public static boolean find(int[] arr, int num) {
        if (arr == null || arr.length == 0) {
            return false;
        }
        int L = 0;
        int R = arr.length - 1;
        //arr[0,N-1]  arr[L,R]
        while (L <= R) {
            int mid = (L + R) / 2;
            if (arr[mid] == num){
                return true;
            }else if(arr[mid]<num){//如果arr[mid]<num则arr[mid]左边的数都不符合,都排除掉L = mid + 1
                L = mid + 1;
            }else {
                R = mid - 1; //如果arr[mid]>num则arr[mid]右边的数都不符合,都排除掉R = mid - 1
            }
        }
        return false;
    }
    // for test 暴力测试
    public static boolean test(int[] sortedArr, int num) {
        for (int cur : sortedArr) { //增强for循环遍历
            if (cur == num) {
                return true;  //找到num返回true
            }
        }
        return false; //找不到返回false
    }

    // for test
    public static int[] generateRandomArray(int maxSize, int maxValue) {
        //生成随机大小的随机数组
        int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
        for (int i = 0; i < arr.length; i++) {//给数组每一个位置生成随机数
            arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
        }
        return arr;
    }

    public static void main(String[] args) {
        int testTime = 500000;
        int maxSize = 10;
        int maxValue = 100;
        boolean succeed = true;
        for (int i = 0; i < testTime; i++) {
            int[] arr = generateRandomArray(maxSize, maxValue);
            Arrays.sort(arr);//Arrays.sort默认从小到大排序
            int value = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());//生成一个随机num
            if (test(arr, value) != find(arr, value)) {
                System.out.println("出错了!");
                succeed = false;
                break;
            }
        }
        System.out.println(succeed ? "Nice!" : "Fucking fucked!");
    }
}

image-20230112101441213

有序数组中找到>=num最左的位置

package class03;

import java.util.Arrays;

public class Code02_BSNearLeft {
    //有序数组中找到>=num最左的位置  最左不小于num的索引位置
    public static int mostLeftNoLessNumIndex(int[] arr, int num) {
        if (arr == null || arr.length == 0) {
            return -1;
        }
        int L = 0;
        int R = arr.length - 1;
        int ans = -1;
        //1.有序数组中找到>=num最左的位置
        /*while (L <= R) {
            int mid = (L + R) / 2;
            if (arr[mid] >= num){
                ans = mid;//不断更新ans值,也就是索引位置,如果arr[mid] = num成立,也就是找到了num值,最后一次更新的位置就是要找的位置
                R = mid - 1;
            }else {
                L = mid + 1;
            }
        }*/
        
        //2.有序数组中找到<=num最右的位置
        while (L <= R) {
            int mid = (L + R) / 2;
            if (arr[mid] > num) {
//不断更新ans值,也就是索引位置,如果arr[mid] == num成立,也就是找到了num、mid值,最后一次更新的位置就是要找的位置mid,
//如果在这个过程中始终没有找到或者arr[mid] > num就不更新ans值,比如如果数组{1,2,3,4}我们找100,
// 一直都找不到arr[mid]>100的值ans值就一直不更新,但是我们这里是要找100在最右侧出现,所以当arr[mid] <= 100时就不断更新ans值,不断去找寻这个arr[mid]==100的位置,所以条件一不更新,条件二不断的更新ans值,直到找到合适的mid值,这个mid就是我们要找的位置
//如果这个数组中的全部数都大于num,就一直执行arr[mid] > num这个条件,ans一直不更新,最后ans的返回值就是-1;
                R = mid - 1;
            } else {
                ans = mid;
                L = mid + 1;
            }
        }
        return ans;
    }
//==============================================================================================
    // 1.for test 有序数组中找到>=num最左的位置
/*    public static int test(int[] arr, int value) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] >= value) {
                return i;
            }
        }
        return -1;
    }*/
    
    //2.有序数组中找到<=num最右的位置
    public static int test(int[] arr, int value) {
        for (int i = arr.length-1; i > 0; i--) {
            if (arr[i] == value) {
                return i;
            }
        }
        return -1;
    }
//===================================================================================================
    // for test
    public static int[] generateRandomArray(int maxSize, int maxValue) {
        int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
        }
        return arr;
    }
    
public static int test(int[] arr, int value) {
        //i >= 0这里i一定要把等于0写上,因为如果左右出现的数在0,就需要返回0索引了
        for (int i = arr.length-1; i >= 0; i--) {
            if (arr[i] <= value) {
                return i;
            }
        }
        return -1;
    }


    public static void main(String[] args) {
        int testTime = 50;
        int maxSize = 10;
        int maxValue = 100;
        boolean succeed = true;
        for (int i = 0; i < testTime; i++) {
            int[] arr = generateRandomArray(maxSize, maxValue);
//            int[] arr = {1, 2, 3, 5, 6, 6, 6, 6, 7, 8, 9};
            Arrays.sort(arr);
            int value = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
//            int value = 6;
            if (test(arr, value) != mostLeftNoLessNumIndex(arr, value)) {
                printArray(arr);
                System.out.println(value);
                System.out.println(test(arr, value));
                System.out.println(mostLeftNoLessNumIndex(arr, value));
                succeed = false;
                break;
            }
        }
        System.out.println(succeed ? "Nice!" : "Fucking fucked!");
    }
}

image-20230112114924609

局部最小值问题 需要数与数之间相邻不等

package class03;
public class Code03_BSAwesome {
    public static int oneMinIndex(int[] arr) {
        if (arr == null || arr.length == 0) {
            return -1;
        }
        int N = arr.length;
        if (N == 1) {
            return 0;
        }
        if (arr[0] < arr[1]) {
            return 0;
        }
        if (arr[N - 1] < arr[N - 2]) {
            return N - 1;
        }
        int L = 0;
        int R = N - 1;//L...R肯定有局部最小
        while (L < R - 1) {
            int mid = (L + R) / 2;
            if (arr[mid] < arr[mid - 1] && arr[mid] < arr[mid + 1]) {
                return mid;
            } else {
                //三种情况 1.左>mid mid>右、2.左<mid mid>右、3.左<mid mid<右
                //2.3情况
                if (arr[mid] > arr[mid - 1]) {
                    R = mid - 1; //局部最小值肯定在左边,右边可能有可能没有,但是只要一个局部最小,所以把右边的值都砍掉
                    // 因为arr[mid]大于arr[mid-1]的值
                }
                //1.情况
                else {//arr[mid] >arr[mid+1]  左边的数都砍掉,局部最小肯定在右边,左边可能有可能没有
                    L = mid + 1;
                }
            }
        }
        return arr[L] < arr[R] ? L : R;
    }

    //生成随机数组,且相邻数不相等
    public static int[] randomArray(int maxLen, int maxValue) {
        int len = (int) (Math.random() * maxLen);
        int[] arr = new int[len];
        if (len > 0) {
            arr[0] = (int) (Math.random() * maxValue);
            for (int i = 1; i < len; i++) {
                //先执行一次,然后判断,如果arr[i] == arr[i - 1],就重做,如果不相等就继续执行下一次for循环,重复上述过程
                do {
                    arr[i] = (int) (Math.random() * maxValue);
                } while (arr[i] == arr[i - 1]);
            }
        }
        return arr;
    }

    public static boolean check(int[] arr, int minIndex) {
        if (arr.length == 0) {
            return minIndex == -1;
        }
        int left = minIndex - 1;
        int right = minIndex + 1;
        //先判断是否越界,如果没越界就比较一下
        boolean leftBigger = left >= 0 ? arr[left] > arr[minIndex] : true;
        boolean rightBigger = right < arr.length ? arr[right] > arr[minIndex] : true;
        return rightBigger && leftBigger;
    }

    //打印数组
    public static void printArray(int[] arr) {
        for (int num : arr) {
            System.out.print(num + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int maxLen = 100;
        int maxValue = 20;
        int testTimes = 1000000;
        System.out.println("测试开始");
        for (int i = 0; i < testTimes; i++) {
            int[] arr = randomArray(maxLen, maxValue);
            int ans = oneMinIndex(arr);
            if (!check(arr, ans)) {
                printArray(arr);
                System.out.println(ans);
                break;
            }
        }
        System.out.println("测试结束");
    }
}

image-20230112174838912

2.时间复杂度

等差数列中时间复杂度为O(N)

二分中时间复杂度为
O ( log ⁡ 2 N ) O (\log_2{N}) O(log2N)
常数操作时间复杂度O(1)

最差的情况来估计时间复杂度

3.动态数组

在java中arraylist是动态数组,时间复杂度是O(1),每往数组中新加数,如果下标越界,就会进行数组扩容,数组长度扩容到原本的2倍,扩容的过程是一个等差数列,扩容前的数组元素原封不动复制到扩容后的数组,然后新加的元素插入到新数组后面

o(1)0(n)

4.哈希表与有序表

哈希表<K,V>

  • 哈希表的增删改查时间复杂度都为O(1),但是这个常数时间是比较大的

  • 哈希表中按值传递,不看地址是否不同

public static class Node {
        public int value;

        public Node(int v) {
            value = v;
        }
    }

    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<>();
        map.put("name", "我是佩萁");
        System.out.println(map.containsKey("name"));//true
        System.out.println(map.get("name"));//我是佩萁
        map.put("name", "小熊");
        System.out.println(map.get("name"));//小熊


        HashMap<Integer, String> map2 = new HashMap<>();
        map2.put(123456, "我是1234567");
        Integer a = 123456;
        Integer b = 123456;
        //==比较的是内存地址  如果要比较后面的内容应该写equals方法
        System.out.println(a == b);//false
        //哈希表只看后面的内容不看内存地址是否不一样
        System.out.println(map2.containsKey(a));//true
        System.out.println(map2.containsKey(b));//true

        //如果是自己写的类型的话,就不是单看值是否相等了,而是看地址是否一样
        Node node1 = new Node(1);
        Node node2 = new Node(1);
        HashMap<Node,String> map3 = new HashMap<>();
        map3.put(node1,"我是node1");
        System.out.println(map3.containsKey(node1));//true
        System.out.println(map3.containsKey(node2));//false
    }

有序表

  • 有序表的每步时间复杂度都为O(N)

  • 有序表传入的key值必须可以比较,如果不是基础类型,而是自己定义的类型,需要说明怎么比较,否则会报错

        TreeMap<Integer,String> treeMap1 = new TreeMap<>();
        treeMap1.put(3,"我是3");
        treeMap1.put(0,"我是0");
        treeMap1.put(6,"我是6");
        treeMap1.put(4,"我是4");
        treeMap1.put(5,"我是5");
        treeMap1.put(8,"我是8");
        System.out.println(treeMap1.containsKey(4));//true
        System.out.println(treeMap1.get(4));//我是4
        System.out.println(treeMap1.firstKey());//0 找到最小的key值
        System.out.println(treeMap1.lastKey());//8 找到最大的key值
        System.out.println(treeMap1.floorKey(5));//5  <=5 离5最近的key
        System.out.println(treeMap1.ceilingKey(6));//6  >=6 离6最近的key

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

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

相关文章

1594_AURIX_TC275_PMU_应用提示1

全部学习汇总&#xff1a; GreyZhang/g_TC275: happy hacking for TC275! (github.com) 这一页主要是描述了当前的PMU版本与之前就版本相比之下的变更&#xff0c;对于第一次接触了解这个模块来说&#xff0c;其实了解前面的基本特性就好了。而这个差异&#xff0c;没有细看的必…

2023年网络安全比赛--Linux渗透测试中职组(超详细)

一、竞赛时间 180分钟 共计3小时 二、竞赛阶段 1.通过本地PC中渗透测试平台Kali对靶机场景进行系统服务及版本扫描渗透测试,并将该操作显示结果中Apache服务对应的版本信息字符串作为Flag值提交; 2.通过本地PC中渗透测试平台Kali对靶机场景进行渗透测试,将该场景/var/www/ht…

Ubuntu安装Redis最新版本

使用ubuntu自带的安装工具安装的redis并不是最新版本,在最近的项目中需要最新版本的redis所以需要手动安装,再次记录下安装过程 备份数据 首先如果当前的虚拟机已经安装过redis,那么卸载当前的安装的版本,同时注意备份数据,redis 的备份数据的默认路径如下: /var/lib/redis 具…

FFmpeg 将多张图片编码成视频

前言 本篇文章的需求是将相机获取到的图片进行编码&#xff0c;编码成一个视频&#xff0c;耗费了大约一个星期的时间在解决各种问题。这里阐述一下这篇文章所要解决的几个问题&#xff1a; 1、如何将多张图片编码成视频。 2、如何进行定时录制视频。 3、同时开启多线程进行视…

吴恩达机器学习课程笔记:正规方程法

1.吴恩达机器学习课程笔记&#xff1a;正规方程法 笔记来源&#xff1a; 1.吴恩达机器学习课程笔记&#xff1a;正规方程法 2.神经网络 - 多元线性回归 - 正规方程法 仅作为个人学习笔记&#xff0c;若各位大佬发现错误请指正 正规方程法区别于梯度下降法的迭代求解&#xff0…

基于 SSH 协议配置 Git 连接 GitHub

文章目录0.安装 Git1.注册 GitHub 账号2.配置 Git 的用户名和邮箱3.基于 SSH 协议远程连接 GitHub3.1 为本机生成 SSH 密钥对3.2 将公钥拷贝到 GitHub 上3.3 SSH 测试3.4 将文件上传到 GitHub 的远程仓库0.安装 Git Git 官网链接&#xff1a;https://git-scm.com/ Git 官网下…

[QMT]01-我的第一个Python策略

新年立个Flag 学写50个QMT策略:新建一个 Python 策略创建方法&#xff1a;我的主页-新建策略删掉模板带的内容,输入第一个策略 01-HelloWorld:编写 Python 策略需在开始时定义编码格式&#xff0c;如 gbk。Init 方法和 handlebar 方法的定义是必须的。上图展示了如何在 QMT 系统…

微信小程序---分包

1.什么是分包 分包指的是把一个完整的小程序项目&#xff0c;按照需求划分为不同的子包&#xff0c;在构建时打包成不同的分包&#xff0c;用户在使用时按需进行加载。 2.分包的好处 对小程序进行分包的好处主要有以下两点: 可以优化小程序首次启动的下载时间在多团队共同开…

Git使用详解(图文+代码):Git分支

Git分支不过如此前言什么是分支分支的新建与合并分支的新建与切换分支的合并遇到冲突时的分支合并分支的管理先写到这了&#xff0c;肝不动了。这几天每天都抽时间更新一点前言 每一种版本控制都以某种形式支持分支。 使用分支的好处就是你可以从开发主线上分离开来&#xff0…

Visusl Studio 2019 使用Sqlite3

1. 下载访问官网下载页面(Sqlite 官方下载)&#xff0c;从Window区下载编译好的动态库和头文件。动态库&#xff08;根据实际需要选择32或64位版本&#xff09;&#xff1a;解压得到&#xff1a;源码文件&#xff1a;解压得到&#xff08;当然我们只需要sqlite3.h&#xff09;&…

V4L2 摄像头应用

1.V4L2 是 Video for linux two 的简称&#xff0c;是 Linux 内核中视频类设备的一套驱动框架&#xff0c;为视频类设备驱动开发和应用层提供了一套统一的接口规范。2.使用 V4L2 设备驱动框架注册的设备会在 Linux 系统/dev/目录下生成对应的设备节点文件&#xff0c;设备节点的…

前端HTML5

什么是HTML&#xff1f; 超文本标记语言&#xff0c;它是用来描述网页的一种语言HTML不是一种编程语言&#xff0c;而是一种标记语言标记语言是一种标记标签 浏览器内核 浏览器内核&#xff08;渲染引擎&#xff09;&#xff1a;负责读取网页内容&#xff0c;整理讯息&#xf…

双方案-基于Mysql 与 ElasticSearch实现关键词提示搜索与全文检索

文章目录前言Mysql检索简述原理其他索引构建实例代码搜索流程搜索ElasticSearch 实现环境配置编码查询与插入前言 就喜欢搞这种不需要怎么费劲的东西&#xff0c;只需要把思路阐述清楚&#xff0c;随笔性质的博文&#xff0c;顺手啊&#xff0c;几乎不用改定就可以当博文发布出…

day19|669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

669. 修剪二叉搜索树 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即&#xff0c;如果没有被移除&#xff0c;原有的父代…

生物信息【蛋白序列对比blosum】

参考学习&#xff1a;传统蛋白质序列比对算法 - 知乎 (zhihu.com) 一、蛋白序列同源、相似 同源”&#xff08;homology&#xff09;和“相似”&#xff08;similarity&#xff09;&#xff1a; 同源是指有相同的祖先&#xff0c;在这个意义上&#xff0c;无所谓同源的程度&…

MybatisPlus学习笔记(二)

分页查询 分页在网站使用十分之多1.原始的limit进行分页2.pageHelper第三方插件3.MP内置的分页插件如何使用 1.配置拦截器组件 2.使用page对象 删除操作 逻辑删除 物理删除&#xff1a;从数据库中直接移除逻辑删除&#xff1a;在数据库中没有被删除&#xff0c;而是通…

Centos 7升级系统内核版本

步骤一&#xff1a;检查内核版本 [rootmaster ~]# uname -rs Linux 3.10.0-1160.el7.x86_64 步骤二&#xff1a;升级内核 CentOS 允许使用 ELRepo&#xff0c;这是一个第三方仓库&#xff0c;可以将内核升级到最新版本 rpm --import https://www.elrepo.org/RPM-GPG-KEY-elr…

二叉树知识锦囊(二)

作者&#xff1a;爱塔居 专栏&#xff1a;数据结构 作者简介&#xff1a;大三学生&#xff0c;希望和大家一起进步&#xff01; 文章目录 文章目录 一、二叉树的存储 二、二叉树的遍历&#xff08;重点&#xff09; 2.1 前序遍历 2.2 中序遍历 2.3 后序遍历 2.4 层序遍历 2.5 小…

AX7A200教程(2): DDR3仿真平台搭建(二)

本章主要新建ddr3工程&#xff0c;然后将官方的ddr3仿真文件加入到工程里进行仿真&#xff0c;开发环境2020.1。新建ddr3_test工程新建ddr3工程顶层新建的ddr3_top顶层文件&#xff0c;目前还是空白的调用mig控制器&#xff0c;请参考我上一个章节&#xff0c;这里不在具体写调…

搜索引擎——Elasticsearch

文章目录1.ElasticSearch简介2.基本概念3.Elasticsearch概念-倒排索引4.Elasticsearch和Kibana的安装5.Elasticsearch入门操作5.1_cat5.2PUT&POST新增数据5.3PUT&POST修改数据5.4GET查询数据5.5DELETE删除数据5.7bulk批量操作5.6乐观锁字段6.Elasticsearch进阶操作6.1批…