一些常用的算法技巧总结

算法总结---最常用的五大算法(算法题思路) 【明确所求:dijkstra是求点到点的距离,辅助数组就是源点到目标点的数组】【最简实例分析:比如思考dijkstra:假设先只有三个点】 阅读详情

朋友写的一篇关于算法技巧的文章,我觉得写得很不错,给大家分享一下。




640


今天和大家讲讲,在做算法题时常用的一些技巧。对于平时没用过这些技巧的人,或许你可以考虑试着去看看在实践中能否用的上这些技巧来优化问题的解。


1. 巧用数组下标


数组的下标是一个隐含的很有用的数组,特别是在统计一些数字,或者判断一些整型数是否出现过的时候。例如,给你一串字母,让你判断这些字母出现的次数时,我们就可以把这些字母作为下标,在遍历的时候,如果字母a遍历到,则arr[a]就可以加1了,即  arr[a]++;


通过这种巧用下标的方法,我们不需要逐个字母去判断。


我再举个例子:


问题:给你n个无序的int整型数组arr,并且这些整数的取值范围都在0-20之间,要你在 O(n) 的时间复杂度中把这 n 个数按照从小到大的顺序打印出来。


对于这道题,如果你是先把这 n 个数先排序,再打印,是不可能O(n)的时间打印出来的。但是数值范围在 0-20。我们就可以巧用数组下标了。把对应的数值作为数组下标,如果这个数出现过,则对应的数组加1。


代码如下:


public void f(int arr[]) {        int[] temp = new int[21];        for (int i = 0; i < arr.length; i++) {            temp[arr[i]]++;        }        //顺序打印        for (int i = 0; i < 21; i++) {            for (int j = 0; j < temp[i]; j++) {                System.out.println(i);            }        }    }

       int[] temp = new int[21];
       for (int i = 0; i < arr.length; i++) {
           temp[arr[i]]++;
       }
       //顺序打印
       for (int i = 0; i < 21; i++) {
           for (int j = 0; j < temp[i]; j++) {
               System.out.println(i);
           }
       }
   }

提醒:可以左右滑动


利用数组下标的应用还有很多,大家以后在遇到某些题的时候可以考虑是否可以巧用数组下标来优化。



2. 巧用取余


有时候我们在遍历数组的时候,会进行越界判断,如果下标差不多要越界了,我们就把它置为0重新遍历。特别是在一些环形的数组中,例如用数组实现的队列。往往会写出这样的代码:


for (int i = 0; i < N; i++) {
       if (pos < N) {
        //没有越界
        // 使用数组arr[pos]
        else {
          pos = 0;//置为0再使用数组
          //使用arr[pos]
         }
        pos++;
   }


实际上我们可以通过取余的方法来简化代码


for (int i = 0; i < N; i++) {
  //使用数组arr[pos]   (我们假设刚开始的时候pos < N)
  pos = (pos + 1) % N;
}



3. 巧用双指针


对于双指针,在做关于单链表的题是特别有用,比如“判断单链表是否有环”、“如何一次遍历就找到链表中间位置节点”、“单链表中倒数第 k 个节点”等问题。对于这种问题,我们就可以使用双指针了,会方便很多。我顺便说下这三个问题怎么用双指针解决吧。


例如对于第一个问题


我们就可以设置一个慢指针和一个快指针来遍历这个链表。慢指针一次移动一个节点,而快指针一次移动两个节点,如果该链表没有环,则快指针会先遍历完这个表,如果有环,则快指针会在第二次遍历时和慢指针相遇。


对于第二个问题


一样是设置一个快指针和慢指针。慢的一次移动一个节点,而快的两个。在遍历链表的时候,当快指针遍历完成时,慢指针刚好达到中点。


对于第三个问题


设置两个指针,其中一个指针先移动k个节点。之后两个指针以相同速度移动。当那个先移动的指针遍历完成的时候,第二个指针正好处于倒数第k个节点。


你看,采用双指针方便多了吧。所以以后在处理与链表相关的一些问题的时候,可以考虑双指针哦。


4. 巧用移位运算。


有时候我们在进行除数或乘数运算的时候,例如n / 2,n / 4, n / 8这些运算的时候,我们就可以用移位的方法来运算了,这样会快很多。


例如:


n / 2 等价于 n >> 1

n / 4 等价于 n >> 2

n / 8 等价于 n >> 3。


这样通过移位的运算在执行速度上是会比较快的,也可以显的你很厉害的样子,哈哈。


还有一些 &(与)、|(或)的运算,也可以加快运算的速度。例如判断一个数是否是奇数,你可能会这样做


if(n % 2 == 1){
 dosomething();
}


不过我们用与或运算的话会快很多。例如判断是否是奇数,我们就可以把n和1相与了,如果结果为1,则是奇数,否则就不会。即


if(n & 1 == 1){
 dosomething();
)


具体的一些运算技巧,还得需要你们多在实践中尝试着去使用,这样用久后就会比较熟练了。


5. 设置哨兵位


在链表的相关问题中,我们经常会设置一个头指针,而且这个头指针是不存任何有效数据的,只是为了操作方便,这个头指针我们就可以称之为哨兵位了。


例如我们要删除头第一个节点是时候,如果没有设置一个哨兵位,那么在操作上,它会与删除第二个节点的操作有所不同。但是我们设置了哨兵,那么删除第一个节点和删除第二个节点那么在操作上就一样了,不用做额外的判断。当然,插入节点的时候也一样。


有时候我们在操作数组的时候,也是可以设置一个哨兵的,把arr[0]作为哨兵。例如,要判断两个相邻的元素是否相等时,设置了哨兵就不怕越界等问题了,可以直接arr[i] == arr[i-1]?了。不用怕i = 0时出现越界。


当然我这只是举一个例子,具体的应用还有很多,例如插入排序,环形链表等。



6. 与递归有关的一些优化


(1).对于可以递归的问题考虑状态保存


当我们使用递归来解决一个问题的时候,容易产生重复去算同一个子问题,这个时候我们要考虑状态保存以防止重复计算。例如我随便举一个之前举过的问题


问题:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法?


这个问题用递归很好解决。假设 f(n) 表示n级台阶的总跳数法,则有

f(n) = f(n-1) + f(n - 2)。


递归的结束条件是当0 <= n <= 2时, f(n) = n。因此我们可以很容易写出递归的代码


    public int f(int n) {
       if (n <= 2) {
           return n;
       } else {
           return f(n - 1) + f(n - 2);
       }
   }


不过对于可以使用递归解决的问题,我们一定要考虑是否有很多重复计算。显然对于 f(n) = f(n-1) + f(n-2) 的递归,是有很多重复计算的。如


640


就有很多重复计算了。这个时候我们要考虑状态保存。例如用hashMap来进行保存,当然用一个数组也是可以的,这个时候就像我们上面说的巧用数组下标了。可以当arr[n] = 0时,表示n还没计算过,当arr[n] != 0时,表示f(n)已经计算过,这时就可以把计算过的值直接返回回去了。因此我们考虑用状态保存的做法代码如下:


//数组的大小根据具体情况来,由于int数组元素的的默认值是0
   //因此我们不用初始化
   int[] arr = new int[1000];
   public int f(int n) {
       if (n <= 2) {
           return n;
       } else {
           if (arr[n] != 0) {
               return arr[n];//已经计算过,直接返回
           } else {
               arr[n] = f(n-1) + f(n-2);
               return arr[n];
           }
       }
   }


这样,可以极大着提高算法的效率。也有人把这种状态保存称之为备忘录法。


(2).考虑自底向上


对于递归的问题,我们一般都是从上往下递归的,直到递归到最底,再一层一层着把值返回。


不过,有时候当n比较大的时候,例如当 n = 10000时,那么必须要往下递归10000层直到 n <=2 才将结果慢慢返回,如果n太大的话,可能栈空间会不够用。


对于这种情况,其实我们是可以考虑自底向上的做法的。例如我知道


f(1) = 1;

f(2) = 2;


那么我们就可以推出 f(3) = f(2) + f(1) = 3。从而可以推出f(4),f(5)等直到f(n)。因此,我们可以考虑使用自底向上的方法来做。


代码如下:


public int f(int n) {
       if(n <= 2)
           return n;

       int f1 = 1;
       int f2 = 2;
       int sum = 0;

       for (int i = 3; i <= n; i++) {
           sum = f1 + f2;
           f1 = f2;
           f2 = sum;
       }
       return sum;
   }


我们也把这种自底向上的做法称之为递推。


总结一下


当你在使用递归解决问题的时候,要考虑以下两个问题


(1). 是否有状态重复计算的,可不可以使用备忘录法来优化。


(2). 是否可以采取递推的方法来自底向上做,减少一味递归的开销。



 乐于分享和输出干货的Java技术公众号:Java3y。关注即可领取海量的视频资源!


640
帅的人都关注了

文章的目录导航:

  • https://github.com/ZhongFuCheng3y/3y


【原】在vc中实现获取汉字拼音的首字母 - lixiaosan的专栏 - 优快云Blog 导读: Author: lixiaosanDate: 05/26/2006/********************************************************************************************/* Syntax/*        GetFirstLetter(CString strName, CString& strFir 阅读详情

相关推荐

2D激光slam四种算法建图效果对比

2d激光slam四种算法建图比较

m0_73791170的博客 8449

日常练习24——交换AB

1.基本变换 函数内使用任何临时变量,交换两个数的值。 //思路:使用中间变量 public class Exchange { public int exchangeAB(int A,int B) { int tmp = 0; tmp = A; A = B; B = tmp; } } ...

qinghuan1998的博客 1万+

前端监控体系:从Sentry到LogRocket错误追踪

Sentry是一款开源的实时错误追踪系统,支持多种语言和框架,包括JavaScript、React、Vue等。它提供了丰富的错误信息、堆栈跟踪和环境数据,帮助开发者快速定位和解决问题。LogRocket是一款前端监控和用户行为分析工具,它提供了视频回放、性能监控、错误追踪等功能。与Sentry不同,LogRocket更注重用户行为的全面分析。前端监控体系是确保应用稳定性和用户体验的重要保障。通过集成Sentry和LogRocket等监控工具,开发者可以实时追踪应用中的错误和用户行为,快速定位和解决问题。

shejizuopin的博客 1314

C++奇技淫巧(一):取位数,交换,比较,求均值

一、计算一个数转化成二进制后包含1的位数 写法:判断x&(x-1)计算了几次 程序: int func(int x) { int count = 0; while(x){ count++; x = x&(x - 1); } return count; } 牛逼!!! ———————————————— 二、编程风格

leonharddt的博客 1万+

Xilinx ZYNQ 7000学习笔记二(FSBL代码分析启动-汇编代码)

Xilinx ZYNQ 7000学习笔记

u011116085的博客 4246

Android T GPS 定位流程

Gps 定位

好记性不如烂笔头 1355

【数据结构与算法】一些常用的算法技巧总结

1. 巧用数组下标 数组的下标是一个隐含的很有用的数组,特别是在统计一些数字,或者判断一些整型数是否出现过的时候。例如,给你一串字母,让你判断这些字母出现的次数时,我们就可以把这些字母作为下标,在遍历的时候,如果字母a遍历到,则arr[‘a’]就可以加1了,即 arr[‘a’]++; 通过这种巧用下标的方法,我们不需要逐个字母去判断。 再举个例子: 问题:给你n个无序的int整型数组arr,并且...

feiyan的博客 2327

Ubuntu22.04下ROS2与PX4仿真环境搭建全流程解析

本文详细解析了在Ubuntu22.04系统下搭建ROS2与PX4仿真环境的全流程,包括系统准备、ROS2 Humble安装、PX4飞控环境部署、ROS2与PX4通信桥梁搭建等关键步骤。针对常见问题提供了解决方案,并分享了性能优化和开发调试技巧,帮助开发者快速构建无人机仿真开发环境。

weixin_29248653的博客 607

基础算法常用技巧

−231231219memset初始化变量名​初始化的值​初始化的大小​通常使用sizeof变量名​105。

2301_81394321的博客 735

AHB—SRAMC项目(结构图,核心代码、Testbench架构)

文章目录一、AHB_SRAMC项目介绍1.1.AHB总线控制单元(ahb_slv_if.v)1.2.SRAM控制单元(sramc_top.v)1.3.主要的传输路径二、结构框图2.1.AHB_SRAMC结构图(重点)2.2.总线控制单元与SRAM控制单元结构图三、部分核心代码(重点理解)四、SystemVerilog Testbench架构(重点)五、目录结构 一、AHB_SRAMC项目介绍 本项...

Mr.翟的博客 3万+

Vue2 - 详细实现网页 “开启录音并生成音频文件,上传到服务器效果“,浏览器录制外部音频调用麦克风并传到后端,兼容全部浏览器、支持 PC 网页或手机 H5 网页、可本地播放试听(详细示例运行代码)

vue,nuxt,uniapp,网页网站,麦克风,网页录音,MediaRecorder,浏览器录音,移动端h5网页,手机端录音,web网页录音,recorder-core官方文档,Recorder,非https怎么本地录音,录音报错失败,录音后怎么播放音频,如何获取录音mp3文件,解决一直不提示麦克风权限,小白详细教程,实时录音,调用浏览器麦克风录音,浏览器不兼容,wav,mp3,vue怎么实现网页录音呢,vue2网页录音并上传到服务器,web如何实现录制音频,vue网页录音,音频录制播放和上传服务器,vu

🏆 前端领域优质创作者 6003

【算法学习】链表篇:链表的常用技巧和操作总结

【算法学习】链表篇:一篇带你搞懂链表的常用技巧和常用操作!!

2301_80220607的博客 4159

Cleo Synchronization接口任意文件读取漏洞CVE-2024-50623 附POC

微信公众号搜索:南风漏洞复现文库该文章 南风漏洞复现文库 公众号首发Cleo。

nnn2188185的博客 480

链表算法中常用操作和技巧

画图可以让一些抽象的文字语言更加形象生动画图!!!

2301_81831423的博客 1039

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

常用的算法技巧

树的遍历是处理树结构的基础,常见的有深度优先搜索(DFS)和广度优先搜索(BFS),衍生出前序、中序、后序遍历(DFS)和层序遍历(BFS)。:通过递归将问题分解为子问题,同时用缓存(如哈希表)存储已解决的子问题结果,避免重复计算(本质是动态规划的 “自顶向下” 实现)。:直接操作二进制位,利用位运算的特性(如与、或、异或、左移、右移)解决问题,效率极高(时间 / 空间复杂度低)。,递归解决子问题后合并结果,适合处理具有 “分治特性” 的问题(如问题可拆分、子问题独立、合并简单)。

AlbenXie的博客 1045

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Java算法题常用方法与技巧全攻略

特点:连续内存,随机访问快,增删慢。常用操作:java复制 int[] arr = new int[10]; // 初始化 Arrays.sort(arr); // 排序 Arrays.fill(arr, 0); // 填充 Arrays.binarySearch(arr, key); // 二分查找 字符串(String) 特点:不可变,操作效率低。常用操作:java复制 String s = "hello"; s.charAt(0); // 获取字符 s.subst

2302_80461269的博客 945

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

【算法】——力扣hot100常用算法技巧

hash.getOrDefault(key2,自定义值)在表里查找是否存在key2这个关键字,若存在返回key2所对应的value,不存在返回自定义的值注:不能尾追++,一般采用hash.getOrDefault(key2,0)+1。

阿华的博客 1176

五大常用算法技巧总结,助你更加快速解题

对于算法技巧,之前的文章也写过一些算法技巧,不过相对零散一些,今天我把之前的很多文章总结了下,并且通过增删查改,给大家总结一些常用的算法解题技巧,当然,这些也不是多牛逼的技巧,不过可以让你的代码看起来更加短小精悍,如果你能够充分掌握这些技巧,能够混合运用起来,那么写出来的代码,必然可以让别人拍案叫绝。 1、多思考能否使用位运算 如果你去看一些大佬的解题代码,你会发现大部分代码里都会出现位运算相关的代码,而且不瞒你说,如果我看到一个人的代码里,如果出现了位运算,我就会感觉这个人还是有点东西。 最简单地位运算使

m0_59162559的博客 943

【算法】链表题的常用技巧及算法题(C++)

通过对链表常用技巧、操作的介绍首先通过几道例题进行使用;后通过一系列算法题进行链表题的熟练

卜及中的博客 1488

解决算法题的常用技巧

转载from: https://blog.youkuaiyun.com/m0_37907797/article/details/84960402 今天和大家讲讲,在做算法题时常用的一些技巧。对于平时没用过这些技巧的人,或许你可以考虑试着去看看在实践中能否用的上这些技巧来优化问题的解。 1. 巧用数组下标 数组的下标是一个隐含的很有用的数组,特别是在统计一些数字,或者判断一些整型数是否出现过的时候。例如,给...

东瓜blog 702

【Java算法】链表常用技巧和操作总结

在编程世界中,链表是一种非常重要的数据结构,它具有很多独特的优势和用途。今天,就让我们一起来总结一下链表的常用技巧和操作。链表的基本概念链表是一种线性数据结构,由一系列节点组成,每个节点包含一个数据元素和一个指向下一个节点的指针。链表的特点是可以动态地增长和收缩,不需要预先分配固定的存储空间。链表的常用技巧1.常画图--->直观形象,便于理解2.引入虚拟头结点处理边界情况方便操作链表3.不要吝啬空间,大胆定义变量(大胆定义变量)4.双指针。

2302_79806056的博客 1479

算法中常用到的技巧

算法中常用到的技巧

闲余知道 935

算法-常用解题思路和技巧

双路快排:主要目的是让等于pivot的元素均匀的分到数组的两边,所以,lt和gt遇到等于pivot的元素时都要停下来(lt遇到大于的时候也要停下来,gt遇到小于的时候也要停下来),然后交换它们的值,虽然交换相等的元素没有什么意义,但是这样的操作会把等于pivot的元素均匀的分到数组的两边,避免一边的数组很长,另一边的很短。每次出一个,入好几个。如果有环,快指针一定可以追上慢指针,追上了,说明有环,就返回true,跳出循环,如果没追上,则,快指针会先到终点,为空,然后自己出循环,说明没有环,返回false。

快乐的小小程序猿 1762
上一篇: 周末推荐阅读【第二弹】
下一篇: 我是如何将博客转成PDF的
Java3y
Java3y 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 1万+粉丝 509原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值