算法学习(持续更新中)

时间复杂度

一个操作如果和样本的数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作。

时间复杂度为一个算法流程中,常数操作数量的一个指标。常用O(读作big O)来表示。具体来说,先要对一个算法流程非常熟悉,然后去写出这个算法流程中发生了多少常数操作,进而总结出常数操作数量的表达式。

在表达式中,只要高阶项,不要低阶项,也不要高阶项的系数,剩下的部分如果为f(N),那么时间复杂度就位O(f(N))。

评价一个算法流程的好坏,先看时间复杂度的指标,然后再分析不同数据样本下的实际运行时间,也就是“常数项时间”.

常数操作:例如数组根据索引寻值,加、减、乘、除、比较

排序

选择排序

每次选择 i 到 n-1 范围内值最小的索引位置 t ,每一次内层循环结束之后交换 i 和 t 索引位置上的值,每一次外层循环 i 的值加 1

private static void selectSort(Integer[] nums) {for(int i=0;i<nums.length-1;i++){int t=i;for(int j=i+1;j<nums.length;j++){if(nums[t]>nums[j]){t=j;}}swap(nums,i,t);}}

时间复杂度:O(n^2) ,空间复杂度:O(1)

冒泡排序

每次从 0 到 i 的范围中将相邻的值进行两两比较,将大的一个值移到后面,这样每一次内层循环结束后,i 位置的值就是0 到 i 范围内最大的值,每一次外层循环 i 的值减 1.

private static void BubbleSort(Integer[] nums) {int n=nums.length;for(int i=n-1;i>0;i--){for(int j=0;j<i;j++){if(nums[j]>nums[j+1]){swap(nums, j, j+1);}}}}

时间复杂度:O(n^2) ,空间复杂度:O(1)

插入排序

i 从 0 开始,维护一个 0 到 i 范围的有序数组,每一次 i++ ,令 j 等于 i,j 所在位置的元素 和 j-1 所在位置的元素进行比较 因为前 j-1 个元素是有序的,所以 j 就往前进行比较,如果 j 所在位置 比 j-1 小,就进行交换,再往前进行比较,知道比前面的大为止。

private static void MySort(Integer[] nums) {if(nums==null || nums.length<2){return;}int l=nums.length;for(int i=1;i<l;i++){for(int j=i;j>0;j--){if(nums[j]<nums[j-1]){swap(nums,j,j-1);}else{break;}}}}

最坏情况下 时间复杂度为 O(n^2),空间复杂度为O(1)

异或运算

异或运算 也叫做无进位运算,当两个操作数相同时,异或运算的结果为 0。当两个操作数不同时,异或运算的结果为 1。

1011 ^ 1001  = 0010  , 0 ^ N = N  ,  N ^ N = 0
​1 0 1 11 0 0 1=  0 0 1 0//异或操作满足交换律和结合率:a^b=b^aa^bc=a^(b^c)

当交换两个数的值时,可以使用异或操作,这样就不会产生额外的空间

    @Testpublic void swap(){int a=1;int b=2;
​a=a^b;b=a^b;a=a^b;System.out.println("a="+a+"\n"+"b="+b);}
​
​
​输出:a=2b=1

原因:

a=1,b=2
第一次异或: a=a^b,b=b   ---> a=1^2,b=1
第二次异或: a=a^b,b=a^b^b=a  ---> a=1^2,b=1^2^2-->因为2^2=0,所以b=1^0=1
第三次异或: a=a^b^a,b=a  ---> a=1^2^1(原本是a^b^b,因为后面一个b在第二步异或的时候变成了a的值,所以这里是1)-->a=1^1^2=0^2=2
​
所以a和b就完成了交换。

但是:使用异或操作完成的交换功能在程序中只能作用于地址位置不同的两个对象,如果是同一个地址位置来进行异或,会把值抹为0

例:存在一个int类型的数组

(1)其中有一种数出现了奇数次,其余都出现了偶数次,求这个奇数次的数 (使用时间复杂度为 (O(n),空间复杂度为O(1))。

使用一个整数0,对数组中的每一个数进行异或运算,因为异或运算不在乎数的顺序,所以就是 0 ^ 所有的偶数次的数(为0)^ 奇数次的数(剩一个) ---> 结果就是 0 ^ 一个奇数次的数 = 奇数次的数。

//int[] nums=new int[]{0,0,1,3,1,2,3};
public static void printOddTimesNum1(int[] nums){int eor=0;for (int num : nums) {eor=eor^num;}System.out.println(eor);}
​
/**输出为:2
**/

(2)有两种数出现了奇数次,其余都出现了偶数次,求这个偶数次的数

//int[] nums=new int[]{0,1,3,1,2,3};
public static void printOddTimesNum2(int[] nums){int eor=0;/**eor = 奇数1 ^ 奇数2,因为奇数1和奇数2不相同,所以eor一定不等于0,这表示eor的32位二进制中至少有一位为1.那么在为1的这个二进制位置上,奇数1和奇数2的值一定不同(一定是其中一个为1,另一个为0),所以我们就可以先求出这个位              置,然后再去与数组中的值进行异或,得到其中一个奇数**/for (int num : nums) {eor=eor^num;}/**这里就是来求出最右边为1的位置例如:eor = 10100 ~eor = 01011  ~eor+1 = 01100eor & ~eor+1 :  1010001100--->   00100所以最右边为1的位置就是00100(4)**/int rightIndex=eor & ~eor+1;int onlyOne=0;for (int num : nums) {if((num & rightIndex)==1){//如果右边第4为为1才进行异或运算,onlyOne最后得到的就是奇数1或者奇数2的值onlyOne = onlyOne^num;}}System.out.println("num1:"+onlyOne+"\n"+"num2:"+(eor ^ onlyOne));}
​
//输出: num1:0
//      num2:2

二分查找

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

//int res=binarysearch(nums,target,0,nums.length-1);
private static int binarysearch(Integer[] nums, Integer target,Integer left,Integer right) {if(left>right) return -1;int l=left;int r=right;int mid=(l+r)>>>1;if(nums[mid]>target){return binarysearch(nums,target,left,mid-1);}else if(nums[mid]<target){return binarysearch(nums,target,mid+1,right);}
​return mid;}

2)在一个有序数组中,找 >= 某个数最左侧的位置

/**Integer[] nums2={1,1,1,1,1,2,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5};System.out.println(binarysearch2(nums2, 3, 0, nums2.length - 1));
**/
private static int binarysearch2(Integer[] nums, Integer target,Integer left,Integer right) {if(left>right) return -1;int l=left;int r=right;int t=0;while(l<=r){int mid=(l+r)>>>1;if(nums[mid]>=target){/*** 找到了一个 >= target的数,将位置记录下来,* 不过也可能在这个数的左边还存在 >= target 的数,* 所以就更新右边界,去左边继续寻找*/t=mid;r=mid-1;}else{//这里就是 nums[mid]的值比target要小,更新左边界,继续去数组右边去找l=mid+1;}}
​return t;}
​
//输出:10

3)局部最小值问题 (数组无序,相邻的两个数不相等 局部最小定义:arr[0] < arr[1] 数组0位置的值就是局部最小,arr[arr.length-1] < arr[arr.length-2] 数组最后一个位置的值就是局部最小,对于数组其他位置上的数 ,满足 arr[i-1] > arr[i] < arr[i+1] i位置上的数就是局部最小)

/**Integer[] nums3={1,0,1,3,6,5,1,2,3};System.out.println(binarysearch3(nums3));
**/
private static int binarysearch3(Integer[] nums) {int l=0;int r=nums.length-1;if(nums[l]<nums[l+1]) return l;if(nums[r]<nums[r-1]) return r;//如果执行到了这里,表示数组的两个边界都不是局部最小值,那么在这数组之中,一定存在一个局部最小值while(l<=r){int mid=(l+r)>>>1;if(nums[mid]<nums[mid-1] && nums[mid]<nums[mid]+1){return mid;}if(nums[mid]>nums[mid-1]){r=mid-1;} else if (nums[mid]>nums[mid+1]) {l=mid+1;}}return -1;}
​
//输出: 1

对数器

有一个你想要测的方法 a,

实现复杂度不好但是容易实现的方法 b ,

实现一个随机样本产生器,

把方法 a 和方法 b 跑相同的随机样本,看看得到的结果是否一样。

如果有一个随机样本是的对比结果不一致,打印样本进行人工干预,改对方法 a 或 方法 b

当样本数量很多时对比测试是否依然正确,如果依然正确,就可以确定方法 a 已经正确

这里以插入排序作为方法a,java中本身提供的sort方法作为方法b

public static void main(String[] args) {int testTime=500000;int maxSize=100;int maxValue=100;boolean succeed=true;for(int i=0;i<testTime;i++){int[] arr1=generateRandomArray(maxSize,maxValue);int[] arr2=copyArray(arr1);//对arr1数组深拷贝MySort(arr1);//插入排序 a方法comparator(arr2);//b方法if(!isEqual(arr1,arr2)){//如果排序后的两个方法中的值存在差异succeed=false;break;}}System.out.println(succeed ? "Nice":"Fucking fucked");
​int[] array = generateRandomArray(maxSize, maxValue);System.out.println(Arrays.toString(array));MySort(array);System.out.println(Arrays.toString(array));
​}
//随机生成一个长度位maxSize,最大值为maxValue的int类型的数组public static int[] generateRandomArray(int maxSize,int maxValue){/*** Math.random() -> [0,1) 所有的小数,等概率返回一个 因为在计算机中,数的位数是有限制的,所以可以确定所有的小数,在数学上就不行。* Math.random()*N -> [0,N) 所有的小数,等概率返回一个* (int)(Math.random()*N) -> [0,N-1] 所有的整数,等概率返回一个*/
​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;}
​
​
//深拷贝
private static int[] copyArray(int[] arr1) {if(arr1==null) return null;int[] arr=new int[arr1.length];for (int i = 0; i < arr1.length; i++) {arr[i]=arr1[i];}return arr;}
​
//插入排序
private static void MySort(int[] nums) {if(nums==null || nums.length<2){return;}int l=nums.length;for(int i=1;i<l;i++){for(int j=i;j>0;j--){if(nums[j]<nums[j-1]){swap(nums,j,j-1);}else{break;}}}}
​
//交换
private static void swap(int[] nums, int i, int j) {int tmp= nums[i];nums[i]= nums[j];nums[j]=tmp;}
​
//java提供的方法
private static void comparator(int[] arr2) {Arrays.sort(arr2);}
​
//比较两个数组中的内容是否完全一致
public static boolean isEqual(int[] arr1,int[] arr2){for (int i = 0; i < arr1.length; i++) {if(arr1[i]!=arr2[i]) return false;}return true;}
​
​

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

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

相关文章

AI - 支持向量机算法

&#x1f9e8;概念 支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是一种强大的机器学习算法&#xff0c;主要用于解决二分类问题。 SVM的核心思想是找到一个超平面&#xff0c;这个超平面能够最好地将数据分为两类&#xff0c;即在保证分类准确的情况下&am…

Hive SQL必刷练习题:同时在线人数问题(*****)

问题描述&#xff1a; 思路&#xff1a; ​ 因为有进直播间时间&#xff0c;和出直播间人数。所以我可以统计&#xff0c;进来一个是不是人数就会加1&#xff0c;出去一个&#xff0c;人数就会减1。 ​ 所以可以给进直播间的时间标记一个1&#xff0c;出直播间的时间标记一个…

【机器学习-02】矩阵基础运算---numpy操作

在机器学习-01中&#xff0c;我们介绍了关于机器学习的一般建模流程&#xff0c;并且在基本没有数学公式和代码的情况下&#xff0c;简单介绍了关于线性回归的一般实现形式。不过这只是在初学阶段、为了不增加基础概念理解难度所采取的方法&#xff0c;但所有的技术最终都是为了…

sparksql简介

什么是sparksql sparksql是一个用来处理结构话数据的spark模块&#xff0c;它允许开发者便捷地使用sql语句的方式来处理数据&#xff1b;它是用来处理大规模结构化数据的分布式计算引擎&#xff0c;其他分布式计算引擎比较火的还有hive&#xff0c;map-reduce方式。 sparksql…

GUROBI之数学启发式算法Matheuristics

参考运小筹的帖子&#xff1a;优化求解器 | Gurobi 数学启发式算法&#xff1a;参数类型与案例实现 - 知乎 (zhihu.com) 简言之&#xff0c;数学启发式是算法就是数学规划和启发式算法的融合&#xff0c;与元启发式算法相比&#xff0c;数学启发式算法具有更强的理论性。 在GUR…

python--模块导入+路径处理+常见异常类型

python--模块导入路径处理常见异常类型 模块导入import 模块名from 模块名 import 类、变量、函数from 模块名 import *from 项目名.包.py文件名称 import 类、变量、函数导包快捷键 os 模块 路径处理路径获取os.path.dirname(__file__)os.path.abspath(test.txt)os.getcwd() 路…

React低代码平台实战:构建高效、灵活的应用新范式

文章目录 每日一句正能量前言一、React与低代码平台的结合优势二、基于React的低代码平台开发挑战三、基于React的低代码平台开发实践后记好书推荐编辑推荐内容简介作者简介目录前言为什么要写这本书 读者对象如何阅读本书 赠书活动 每日一句正能量 人生之美&#xff0c;不在争…

AI论文速读 | TPLLM:基于预训练语言模型的交通预测框架

论文标题&#xff1a;TPLLM: A Traffic Prediction Framework Based on Pretrained Large Language Models 作者&#xff1a;Yilong Ren&#xff08;任毅龙&#xff09;, Yue Chen, Shuai Liu, Boyue Wang&#xff08;王博岳&#xff09;,Haiyang Yu&#xff08;于海洋&#x…

提高安全投资回报:威胁建模和OPEN FAIR™风险分析

对大多数人和企业来说&#xff0c;安全意味着一种成本。但重要的是如何获得适合的量&#xff0c;而不是越多越好。然而&#xff0c;你如何决定什么时候可以有足够的安全性&#xff0c;以及你如何获得它&#xff1f;则完全是另一回事。 该篇文章是由The Open Group安全论坛主办&…

爱奇艺 CTR 场景下的 GPU 推理性能优化

01 背景介绍 GPU 目前大量应用在了爱奇艺深度学习平台上。GPU 拥有成百上千个处理核心&#xff0c;能够并行的执行大量指令&#xff0c;非常适合用来做深度学习相关的计算。在 CV&#xff08;计算机视觉&#xff09;&#xff0c;NLP&#xff08;自然语言处理&#xff09;的模型…

基于SpringBoot SSM vue办公自动化系统

基于SpringBoot SSM vue办公自动化系统 系统功能 登录 个人中心 请假信息管理 考勤信息管理 出差信息管理 行政领导管理 代办事项管理 文档管理 公告信息管理 企业信息管理 会议室信息管理 资产设备管理 员工信息管理 开发环境和技术 开发语言&#xff1a;Java 使用框架: S…

ChatGLM3-6B独立部署提供HTTP服务failed to open nvrtc-builtins64_121.dll

背景 我在本地windoes部署ChatGLM3-bB&#xff0c;且希望部署后能提供HTTP server的能力。 模型部署且启动是成功了&#xff0c;但是在访问生成接口/v1/chat/completions时报错failed to open nvrtc-builtins64_121.dll。 问题详细描述 找不到nvrtc-builtins64_121.dll Runtime…

【JavaScript】JavaScript 运算符 ④ ( 逻辑运算符 | 逻辑与运算符 | 逻辑或运算符 || | 逻辑非运算符 ! )

文章目录 一、JavaScript 逻辑运算符1、逻辑运算符 概念2、逻辑与运算符 &&3、逻辑或运算符 ||4、逻辑非运算符 !5、完整代码示例 一、JavaScript 逻辑运算符 1、逻辑运算符 概念 JavaScript 中的 逻辑运算符 的作用是 对 布尔值 进行运算 , 运算完成 后 的 返回值 也是…

Java面试题20之论如何实现接口的幂等性(高并发情况下)

电商的前后端交互&#xff0c;下一步&#xff0c;登陆注册&#xff0c;由于网络原因的重复发送请求&#xff0c;同一资料发送多份 接口的幂等性&#xff1a;相同的资料进来只注册一个 唯一id&#xff1a; 每次操作&#xff0c;都根据操作和内容生成唯一的id&#xff0c;在执…

2.26回顾章节主体线索脉络,课程要求(评分)

3)翻译程序、汇编程序、编译程序、解释程序有什么差别&#xff1f;各自的特性是什么&#xff1f; 翻译程序是指把高级语言源程序翻译成机器语言程序&#xff08;目标代码&#xff09;的软件。 翻译程序有两种&#xff1a;一种是编译程序&#xff0c;它将高级语言源程序一次全部…

学习笔记--强化学习(1)

参考&#xff1a;https://blog.csdn.net/koulongxin123/article/details/122676149 1.什么是强化学习&#xff1f; (1)定义 基于环境的反馈而行动&#xff0c;通过不断与环境的交互、试错&#xff0c;最终完成特定目的或者使得整体行动收益最大化&#xff08;是一种通过与环境…

CKA认证之Etcd备份与恢复

题目介绍&#xff1a; 资料参考&#xff1a; https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/configure-upgrade-etcd 解题&#xff1a; 1、备份 #参考模板列出 etcdctl 可用的各种选项。 #例如&#xff0c;你可以通过指定端点、证书和密钥来制作快照&#xff0…

15 个最佳免费照片恢复软件快速恢复已删除的图像

这篇文章重点介绍了适用于 Windows 10 的 15 款最佳免费照片恢复软件。阅读整篇文章&#xff0c;了解理想的图像恢复软件。 照片可以带回所有的回忆&#xff0c;回忆起与我们所爱的人和亲密的人度过的每一个“时刻”。照片是我们永远不想失去的东西&#xff0c;但有时我们会无…

Axios 中的文件上传(Upload File)方法

Axios 提供了多种上传文件&#xff08;Upload File&#xff09;的方法&#xff0c;适用于不同的上传场景。以下是其中几种常用的方法&#xff1a; 1. 使用 FormData 对象FormData是一个用于创建表单数据的 API&#xff0c;可用于发送包含文件和其他表单数据的multipart/form-d…

【热门话题】前端框架发展史

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 前端开发的历史演变引言第一章&#xff1a;起源与基础建设 - HTML与CSS时代1.1 …