• 打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
  • 打赏支付宝扫一扫

首页

 > 

设计架构 > 

数据结构

面试时算法题的解答思路

winter-cnwinter-cn • 7年前

面试中纯粹考算法的问题一般是让很多程序员朋友痛恨的,这里分享下我对于解答算法题的一些思路和技巧。

一般关于算法的文章,都是从经典算法讲起,一种一种算法介绍,见得算法多了,自然就有了感悟,但如此学习花费的时间和精力却是过于巨大,也不适合在博客里面交流。这一篇文,却是专门讲快捷思路的,很多人面对算法题的时候几乎是脑子里一片空白,这一篇文章讲的就是从题目下手,把毫无思路的题目打开一个缺口的几种常见技巧。

(一)由简至繁

事实上,很多问题确实是很难在第一时间内得到正确的思路的,这时候可以尝试一种由简至繁的思路。首先把问题规模缩小到非常容易解答的地步。

[题目]有足够量的2分、5分、1分硬币,请问凑齐1元钱有多少种方法?

此题乍看上去,只会觉得完全无法入手,但是按照由简至繁的思路,我们可以先考虑极端简单的情况,假如把问题规模缩小成:有足够量的1分硬币,请问凑齐1分钱有多少种方法?毫无疑问,答案是1。

得到这一答案之后,我们可以略微扩大问题的规模: 有足够量的1分硬币,凑齐2分钱有多少种方法?凑齐n分钱有多少种方法?答案仍然是1

接下来,我们可以从另一个角度来扩大问题,有足够量的1分硬币和2分硬币,凑齐n分钱有多少种方法?这时我们手里已经有了有足够量的1分硬币,凑齐任意多钱都只有1种方法,那么只用1分钱凑齐n-2分钱,有1种方法,只用1分钱凑齐n-4分钱,有1种方法,只用1分钱凑齐n-6分钱,有1种方法......

而凑齐这些n-2、n-4、n-6这些钱数,各自补上2分钱,会产生一种新的凑齐n分钱的方法,这些方法的总数+1,就是用1分硬币和2分硬币,凑齐n分钱的方法数了。

在面试时,立刻采用这种思路是一种非常有益的尝试,解决小规模问题可以让你更加熟悉问题,并且慢慢发现问题的特性,最重要的是给你的面试官正面的信号——立即动手分析问题比皱眉冥思苦想看起来好得多。

对于此题而言,我们可以很快发现问题的规模有两个维度:用a1-ak种硬币和凑齐n分钱,所以我们可以记做P(k,n)。当我们发现递归公式 P(k,n) = P(k-1,n - ak) + P(k-1,n - 2*ak) + P(k-1,n - 3*ak) ... ... 时,这个问题已经是迎刃而解了

通常由简至繁的思路,用来解决动态规划问题是非常有效的,当积累了一定量简单问题的解的时候,往往通向更高一层问题的答案已经摆在眼前了。

 

(二)一分为二

另一种思路,就是把问题一刀斩下,把问题分为两半,变成两个与原来问题同构的问题,能把问题一分为2,就能再一分为4,就能再一分为8,直到分成我们容易解决的问题。当尝试这种思路时,其实只需要考虑两个问题:1.一分为二以后,问题是否被简化了? 2.根据一分为二的两个问题的解,能否方便地得出整个问题的解?

[题目]将一个数组排序。

这个经典算法肯定所有人都熟悉的不能再熟悉了,不过若是从头开始思考这个问题,倒也不是所有人都能想出几种经典的排序算法之一的,这里仅仅是用来做例子说明一分为二的思路的应用。

最简单的一分为二,就是将数组分成两半,分别排序。对于两个有序数组,我们有办法将它合并成一个有序数组,所以这个一分为二的思路是可行的,同样对于已经分成两半的数组,我们还可以将这个数组分作两半,直到我们分好的数组仅有1个元素,1个元素的数组天然就是有序的。不难看出,按这种思路我们得出的是经典数组排序算法中的“归并排序”。

还有另一种一分为二的思路,考虑到自然将数组分成两半合并起来比较复杂,我们可以考虑将数组按照大于和小于某个元素分成两半,这样只要分别解决就可以直接连接成一个有序数组了,同样这个问题也是能够再次一分为二。按照这个思路,则可以得出经典数组排序算法中的“快速排序”。

 

(三)化虚为实

这种思路针对的是浮点数有关的特殊问题,因为无论是穷举还是二分,对于浮点数相关的计算问题(尤其是计算几何)都难以启效,所以化虚为实,指的是把有点"虚"的浮点数,用整数来替代。具体做法是,把题目中给出的一些浮点数(不限于浮点数,我们不关心其具体大小的整数也可以)排序,然后用浮点数的序号代替本身来思考问题,等到具体计算时再替换回来。

[题目]已知n个边水平竖直的矩形(用四元组[x1,y1,x2,y2]表示),求它们的总共覆盖面积。

因为坐标可能出现浮点数,所以此题看起来十分繁复(可以实践上面由简至繁和一分为二的思路都基本无效),略一思考,矩形的覆盖关系其实只跟矩形坐标的大小有关,所以我们尝试思考将矩形的所有x值排序,然后用序号代替具体竖直,y值亦然,于是我们得到所有矩形其实处于一个2nx2n的区块当中,这样我们用最简单的穷举办法,可以计算出每一个1x1的格子是否被覆盖住了。至此,只要我们计算面积的时候,把格子的真实长宽换算回来,就已经得到题目的答案了。

 

本文是某天在QQ群里讨论面试时的算法问题时想到要写的,以上三种思路,是我平时遇到算法问题的快速思考方向,并非万灵药方,若是不能生效,就要静下心来慢慢思考观察了,考虑到面试的时候基本不会遇到高难度算法题,这几种技巧的命中率应该不会太低,共享给大家,希望有所帮助。

“看完这篇还不够?如果你也在学习IT,并希望记录自己的成长日志,请戳这里告诉我们!”
新人作者

好好学习,天天向上,有工作有兼职可以找我。微信号:gethost

文章总数
总阅读量
程序猿们,如果你或你的朋友想升职加薪,请狠戳这里我要成长
参与讨论
后参与讨论
winter-cn
新人作者

文章总数
总阅读量
程序猿们,如果你或你的朋友想升职加薪,请狠戳这里我要成长
48h快讯7天最热月榜More
  • 7年前

    Dijkstra算法(单源最短路径)单源最短路径问题,即在图中求出给定顶点到其它任一顶点的最短路径。在弄清楚如何求算单源最短路径问题之前,必须弄清楚最短路径的最优子结构性质。一.最短路径的最优子结构性质该性质描述为:如果P(i,j)={Vi....Vk..Vs...Vj}是从顶点i到j的最短路径,k和s是这条路径上的一个中间顶点,那么P(k,s)必定是从k到s的最短路径。下面证明该性质的正确性。假设P(i,j)={Vi....Vk..Vs...Vj}是从顶点i到j的最短路
    收起
  • 7年前

    二叉树的非递归遍历二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的。对于二叉树,有前序、中序以及后序三种遍历方法。因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁。而对于树的遍历若采用非递归的方法,就要采用栈去模拟实现。在三种遍历中,前序和中序遍历的非递归算法都很容易实现,非递归后序遍历实现起来相对来说要难一点。一.前序遍历前序遍历按照根结点-左孩子-右孩子的顺序进行访问。1.递归实现voi
    收起
  • 7年前

    淘宝名词解释产品和商品的区别:淘宝标准化产品,由类目+关键属性唯一确定。如:手机类目,关键属性是品牌和型号,NokiaN95就是一个产品,nokia是品牌,N95是型号。产品除了关键属性还包括一般信息、销售属性和非关键属性。参考:如"诺基亚N95"就是一个产品。通过类目的关键属性组合来确定唯一的产品。后台标准类目叶子节点下,一组共同特征商品的组合(例如:化妆品+雅芳+保湿单品+容量),属于同一个产品的商品可以认为对消费者的效用及使用感受是没有差别的。产品这个概念对淘宝这种C2
    收起
  • 5年前

    队列特性:先进先出(FIFO)先进队列的元素先出队列。来源于我们生活中的队列(先排队的先办完事)。队列有下面几个操作:InitQueue()  初始化队列EnQueue()进队列DeQueue()出队列IsQueueEmpty()判断队列是否为空IsQueueFull()判断队列是否已满队列可以由数组和链表两种形式实现队列操作(c语言),下面仅以数组为例:数组实现:队列数据结构typedefstructqueue
    收起
  • 7年前

    前言那个啥前面发了2篇文章讲这个商品表的设计,后面越多需求浮出水面才发现设计依旧有问题,好吧,乐观一点,正如我博客的标题一样,我在进化^_^为什么要这样设计先说几个需求,看看您现在是如何去实现:一个用户来到我们网站,在前台页面,1.他要买洗发水,他进入了洗发水的类别,他想买带去屑止痒功效的500ml的洗发水,能否直接搜索出来所有品牌带这个功效属性是500ml的洗发水2.接着他要买一件T恤,他想买V领,短袖的T恤,能否直接通过2个属性搜索出所有品牌的T恤展示给他3.他
    收起
  • 9年前

    1、反转一个链表。循环算法。1Listreverse(Listl){2if(!l)returnl;3listcur=l.next;4listpre=l;5listtmp;6pre.next=null;7while(cur){8tmp=cur;9cur=cur.ne
    收起
  • 7年前

    图的遍历图的遍历有两种遍历方式:深度优先遍历(depth-firstsearch)和广度优先遍历(breadth-firstsearch)。1.深度优先遍历基本思想:首先从图中某个顶点v0出发,访问此顶点,然后依次从v0相邻的顶点出发深度优先遍历,直至图中所有与v0路径相通的顶点都被访问了;若此时尚有顶点未被访问,则从中选一个顶点作为起始点,重复上述过程,直到所有的顶点都被访问。可以看出深度优先遍历是一个递归的过程。如下图中的一个无向图其深度优先遍历得到的序
    收起
  • 7年前

    1:原理以此比较相邻的两个元素,每次比较完毕最大的一个字跑到本轮的末尾。目的:按从小到大排序。方法:假设存在数组:72,54,59,30,31,78,2,77,82,72第一轮比较相邻两个元素,如果左边元素大于右边元素,则交换。72和54比较的结果就是,54在前,72在后;然后72和59比较的结果,59在前,72在后;以此类推,第一轮比较之后的结果是:54,59,30,31,72,2,77,78,72,82经过第一轮比较,最大的元素跑到了最
    收起
  • 9年前

    CodehighlightingproducedbyActiproCodeHighlighter(freeware)http://www.CodeHighlighter.com/-->/*冒泡排序基本思想将n个记录看作按纵向排列,每趟排序时自下至上对每对相邻记录进行比较,若次序不符合要求(逆序)就交换。每趟排序结束时都能使排序范围内关键字最小的记录象一个气泡一样升到表上端的对应位置,整个排序过程共进行n-1趟,依次将关键字最小、次小、第三小的各个记录冒到表的第一个、第二个、第三个位置
    收起