圈的那这道题我不会做,

  换题季咣咣地过了一半了各个大学最新的录取条件又刷新了小编的震惊程度!不知道小伙伴们准备的如何啦?

  有很多小伙伴在这个时候都很紧张没办法,小編只好把压箱底的宝贝——雅思终极抢救法拿出来了!

  听力录音没跟上漏了题没听到怎么办?

  阅读文章太难了时间不够用了,题不会做/做不完了怎么办

  没办法,只能兵行险招了!今天就来和大家聊一聊雅思考试中猜(≠瞎蒙)答案的特殊技巧!

  其實猜答案这种策略在遇到以上情况时,是一个不错的方法——我们知道与其它标准化考试不同的是,雅思考试中答错题不倒扣分这樣一来,即使一个问题我们完全不知道答案仍然有20-25%的机会选出正确答案。

  很多同学不理解猜答案对他们的分数产生的影响其实,除非是特别厉害的考生否则猜答案这个动作是会对我们的最终总分有很大影响的——当然,前提是我们能够尽量猜出正确的答案

  猜测不是瞎蒙,猜答案其实还是有一定的技巧规律可循的掌握这些技巧可以在万不得已的时刻紧急抢救一下!(非紧急情况慎用!慎用!)

  一、俚语(非正式、较口语的语句)

  答案中,看起来更加科学、合理的选项要比俚语类的选项中奖率高

  我们来看,选項A和B中都提到了“不同类项的治疗”选项A中用的是“different kinds of”,而选项B中用的“one or the other”相比起来B中的表达更加口语化,而这这道题我不会做的正確答案也正是选项A

  二、极端表达 (绝对词)

  去掉表达“狂野”的选项,这样的选项中一般都会抛出颇具争议的观点、非常极端嘚表达然后说这样的观点就是既定事实。

  我们注意到选项A中出现了绝对词“completely”,这个想法很激进很危险啊!而选项B就冷静了很多没有提出绝对的观点,而是用if这个缓冲词圈定了事情发生的条件这样看起来就留下了更多后路。尤其在雅思阅读的T/F/NG题中含有绝對词的选项一般都是F。

  如果有两个选项的意思是完全相反的那么通常来说,正确答案就在它们俩中间

  这两个选项的内容非常楿近。这样的题目一般有两个意思相反的选项+一个中立的选项构成

  这里要注意一下前三个选项的相关性,它们都是在比较价格峩们可以立刻反应出,选项B和C的意思是相反的所以我们优先从它俩中间选。当然选项A也提到了价格,所以A也可以纳入考虑而选项D与其余三个的相关性则不高,不属于同族选项D没有提到价格相关的内容,所以在大多数情况下可以不考虑

  进一步说,如果三个选项Φ有两个是近义的,另外一个是与这两个选项完全相反的那么通常两个近义项中与第三个选项形成“绝对反义”的那一个,通常是正確答案

  这里,选项A和B中有近义词而C又是A与B的反义词,那么我们可以发现,相比起prettybeautiful才是ugly的绝对反义,所以这里A才是正确答案。

sometimes考官会把这些词加入到选项中,以保证能够覆盖到更多的情况通常,一个没有任何例外的绝对选项都是错误的所以我们要避免含囿“exactly”、“always”这种词的选项。

  还没完彩蛋在此!

  听力考试——单选题(可延伸到阅读考试中使用)

  一、雅思听力考试中的救命稻草(次级技巧,50%正确率):

  1. 最后原则:听到题干题眼后选项都被提及,最后被提及的是答案

  2. 常识原则:用一般常理推絀正确答案。

  3. 陌生词原则:选项包含从未见过的英文单词且在录音中原文重现,则排除不选

  4. 数字选项选中间值。

  二、雅思听力考试中的灵丹妙药(推荐技巧70%正确率):

  1. 淘汰绝对词(上文有提到)。

  2. 相似(相反)是考点:a. 形式相似意义不同的选项;b. 意思相反的选项二选一(一般选择否定/负面的意思)

  听力考试——多选题(可延伸到阅读考试中使用)

  以下答案根据考试數据统计得出:

  1. 五选二/六选二多选题一般选B;

  2. 七选三多选题一般选C和F。(如果C或F不正确则选择B、D、E)

在YouTube上TechLead关于软件工程的视频非常受欢迎。其中一期视频中TechLead提到了他在谷歌100多次面试中提出的一个问题。这个视频让人很燃——

他提这个问题主要目的是想了解:应聘者昰否会在编程之前提出合适的问题提出的解决方法是否符合项目指南?他甚至说能否回答出正确答案并不重要,只是想要探明你如何思考亦或你是否正确理解问题所在。

也许你会很好奇如何解决这个问题?TechLead谈到了几个解决方案一个是递归式(受堆栈大小的限制),一個是迭代式(受内存大小的限制)本文将会对这两个问题进行更多的研究!

Techlead提出的问题是:在这张网格图中,计算最大的同色相连方块数量

当听到这个问题时,我边看图边想“天呐,我得用二维模型来解答了”这听起来简直就是个近乎不可能在面试中能够回答的问题。

隨着讲解的深入我意识到问题并未如此简单。前面的解法事实上只是在运行已抓取的数据而不是解析图像我意识到,图像这个词其實是用词不当的。

在开始编程之前需要定义好数据模型。这件事再怎么强调也不为过在编写如此高级的代码之前,首先要弄清楚自己囸在处理什么同时收集好业务需求。

在本文所举的例子里TechLead给大家定义了许多要求:

· 彩色方块的概念,或者称之为“节点”
· 此数據集中有10K节点。
· 节点被组织成行和列二维)
· 行数和列数可能不均匀。
· 节点有颜色和表示邻接的方法

从数据中还能得到更多的信息:

· 任意两个节点不会重叠。
· 节点永远不会和自身相邻
· 一个节点永远不会重复相邻。
· 位于边和角上的节点将分别丢失一个或两个鄰接

· 只有一种颜色的概率

作为开发者,级别越高越清楚应该问哪些问题。当然这也不全是过往经验所能赋予的尽管有所帮助,但昰如若不能找出这些未知量解决问题时还是会遇到困难。

我们并不期望众人能够找出这些未知量在脑海中计算这个算法之前,我对其吔一无所知要找到这些未知量需要一定的时间,需要通过反复与业务人员进行大量的讨论来找到这当中的症结

图片里色块的分布看起來似乎是随机的。他除了说只用了3种颜色并没有说别的,所以我们也可以这么做同时,做个假设:有一种可能情况是所有的颜色都有楿同数量

由于它可能会破坏算法,因此假设正在处理一个100*100的网格图。这样就不需要处理奇数行和10K列的情况

一般来说, 我会在数据探索嘚最初几个小时内问这些问题,而这才是TechLead 真正关心之处你会先编写一个随机解还是先找出问题呢?

在数据建模的时候你应该会犯错误峩第一次写文章的时候就犯了错误。但如果你能够提前考虑到问题并有所防范这些问题可能处理起来会更加容易。反正当时我最终不得鈈重写一部分代码

为了建立模型,我们需要知道数据是如何输入以及希望如何处理由于没有适当的系统来处理数据,因此需要自己进荇可视化处理

数据的基本构成是这样的:

为什么需要ID? 因为处理时有可能不止一次遇到相同的方块。想要防止无限循环则需要标记在这些情况下该方块所处的位置。

同时像这样的数据,通常会配有某种ID、散列或者其他值它是一个独一无二的标识符,因而我们有办法能識别那个特定的节点如果想知道最大的相连方块,我们需要知道该方块上有哪些节点

由于TechLead用网格表示数据,我们假设会得到X, Y的值仅使用这些属性,可以生成一些HTML, 以确保所生成的内容与他给定的内容相似

这是用绝对定位完成的,如他的例子那样:

在更大的网格图中這个方法也可以使用:

这是他用于生成节点的代码:

取行和列,从项的数量中创建一个一维数组然后根据这些数据生成节点。

在这里用嘚不是颜色而是colorID。这样做的原因有两个一是随机化更简便;二是颜色值通常需要自己查找。

尽管他从来没有明确说明他只使用了3个颜銫值这里也将数据集限制为3种颜色。只要知道它可以有数百种颜色最终的算法就不需要改变。

举个更简单的例子这里有一个2x2节点列表:

无论使用什么方法,我们都希望得到这里每个节点的相邻值X和Y的值并不能满足要求。

因此给定一个X和Y,相对应需要找出X和Y的相邻徝当然,这很简单只需要在X和Y上找到+ 1和- 1的节点就可以了。

为此我写了一个辅助函数:

相反,假设节点会随机进入系统

生成节点的方式,其实确有一种可以推算出相邻节点ID的数学方法但我不这么做,相反我假设节点会随机进入系统

在第二轮遍历,所有节点时加入楿邻节点:

避免在这个预处理器代码中进行任何不必要的优化它不会影响最终的性能统计,只会帮助简化算法

接着,继续把colorID变成一种顏色尽管对于这里的算法来说这完全没有必要,但是我想让它更好地可视化

在获得基本ID之后,将它们转换为一个邻接数组该数组只包含那些具有数值的邻接数组。这样只要有角和边,就不用担心所检查id是否为空它还允许循环一个数组,而不必在算法中手工记录每個基本ID

下面是另一个2x2示例,它使用一组新的节点遍历addAdjacencies:

因为想大力简化本文的算法所以我在另一个优化过程中添加了该算法。该操作會删除与当前节点颜色不匹配的相邻id

在增加更多功能的,同时缩减了addAdjacencies

通过删除颜色不匹配的节点,算法可以100%确定adjacentids实体中的任何id都是相鄰节点

最后,删除所有没有相同颜色邻接的节点这进一步简化了算法,将节点总数缩减剩所需的节点

TechLead说不能递归地做这个算法,因為会碰到堆栈溢出

虽然在一定程度上是正确的,但有几种方法可以缓解这个问题要么用迭代法要么使用尾部递归。下面将看到迭代的唎子但是JavaScript不再将尾部递归作为一种本地语言特性。

虽然仍可以在JavaScript中模拟尾部递归但这里将保持这种简单性,并创建一个典型的递归函數

编写代码之前要弄清楚算法。对于递归使用深度优先搜索也行得通。“即便不知道计算机科学术语也没关系” 当我向一位同事展礻想出来的不同解决方案时,他如是说

先从一个节点开始,然后一直延续下去直到达到终点然后再回来并采取下一个分支路径,直到掃描到整个连续块为止

这是其中一部分。此外也必须追踪所处位置和最大连续块的长度

这里做的是把函数分成两段。其中一个将保存朂大列表以及给每个节点进行至少一次循环时扫描过的ID。另一个则从一个未扫描的根节点开始并执行深度优先遍历。

是不是很夸张夲来不想把编码放上去,因为看起来实在是太乱了

下面将一步一步将其简化。

getContiguousIds 是递归函数每个节点都会用到一次。该函数每次返回结果时都会得到连续节点更新后的列表。

该函数只有一个条件那就是:节点是否在列表里了?如果不是那就再用一遍getContiguousIds。当它返回时僦会得到连续节点更新后的列表。而这列表也将回到缩减器用作下一个adjacentId的状态。

你也许会困惑为什么要给contiguousIds加值。当我们concat当前节点到contiguousIds时嘟要给其加值而每次递归下去,都要确保给adjacentIds进行循环时将当前节点加到contiguousIds的列表中。

一直增加当前节点是为了确保递归不会无限进行

函数的下半段也会经过每个节点至少一次。

递归函数被缩减器包围着缩减器会检查编码是否有被扫描过。如果有的话就会继续循环直箌遇到一个未被扫描的节点或者退出循环为止。

如果节点还未被扫描就用getContiguousIds然后等到扫描完毕。这是同步进行的但也会花上一点时间。

當它得到一个contiguousIds的列表后将其对着largestContiguousIds列表进行比较。然后将较大的那个值保存下来

把这些列出来后,看起来就简单多了

就算使用了10K项,茬三个随机颜色下它依然没有堆栈溢出如果换成是同色,那就会形成堆栈溢出那是因为该递归函数经过的是10K的递归。

由于内存大于函數调用栈下一步应该在一个循环中完成整个操作。

这里将会把所有的节点列表记录下并在跳出循环前持续将其添加和链接在一起。

这個方式要求在完成循环之前将所有可能的节点列表保存在内存中。而递归版本中只有最大的列表被保存在内存中。

要不尝试另一个更瘋狂的方式可以尝试从上往下拆开。将每个节点循环一次但是现在必须检查id是否在节点列表的列表contiguousIdsList中。

如果它不在contiguousIds的任何列表中就將它和它的adjacentIDs添加进去。这样在循环时,其他东西也就会和它连接上

如果节点在列表中,那它也有可能存在于其它列表中必须把它们铨部连接起来,并从contiguousIdsList移除未连接的节点

得到所有节点列表后,检查看哪个最大就完成了。

与递归版本不同的是当所有10K项都是同个颜銫时,这个方式是会结束的

除了这一点之外,这个方式比较慢比原先预计的还慢。而这里忘了考虑到一点就是在性能评估中考虑对列表中的列表进行循环这一因素,因为这显然对性能有一定的影响

这里的想法是采用递归方法背后的概念,将其以迭代的方式进行应用

我在花了一晚上大部分时间试图想起来如何动态地改变循环中的索引后,才想到了while(true)

有了这个“武器”后,便展开“***”由于花了很多時间尝试加快observable版本,最后决定了“抄小路”以传统的方式改变数据。

该算法的目的是命中每个节点各一次并只保存最大的连续块:

这裏不在列表添加先前扫描过的ID,而是从remainingNodes数组剪接数值
其实不建议这么做,只是在做这些实例时我已经快失去耐心所以想尝试不一样的東西。

在这里使用if块将它分成三个部分

先从中间部分开始。查看有没有queuedIds如果有的话,就进行一个循环使其透过已队列项看它们是否茬remainingNodes里。

而第三部分取决于第二部分的结果如果没有任何queuedIds,而remainingNodesIndes为-1那该节点列表就可以放一边了,并开始一个新的根节点新根节的索引始终为0,因为remainingNodes正在进行剪接中

回到第一个循环,其实可以使用while(true) 但是为以防万一需要想一个办法。这在排除错误时很有帮助因为有时候无限循环很难被判断出来。

之后将节点剪接出来。将其加入contiguousIds的列表然后将adjacentIds加入队列中。

结果是这个方法几乎和递归版本一样快当所有节点是同一个颜色时,它是所有算法中最快的

既然已知蓝色会和蓝色同组,那在序列迭代版本中就可以将类似颜色的节点分组在一起

将其分成三个更小的数组,会减少对内存的占用和对列表进行循环的次数但是,这依然解决不了所有颜色一样的情况下的问题所鉯这并无法修正上述的递归版本。

此外这也代表可以通过多线程操作,减少三分之二所需的执行时间

若按序列执行,只需要先运行三個数组中最大的那个如果另外两个合起来依然小过最大的那个,就不需要检查它们

其实不需要在特定间隔检查最大的列表,建议每次迭代都检查一次

如果最大组大于或等于可用节点的一半(5K或以上),那很明显手中的列表就是最大的

利用随机迭代版本,可以找到目湔为止最大的列表和剩余的节点量如果后者小于前者,那就代表已获得最大列表

虽然递归有其局限性,但依然可被使用所需做的就呮是检查剩余节点的数量。若它们低于堆叠上限就可转换去更快的递归版本。这方法虽然有风险但随着循环的深入,执行时间也肯定會缩短

使用 ‘for’ 循环

既然已知最大项数,从reduce函数切换到传统的for循环会带来一个微好处

不知为啥,Array.protoype方式与for循环比起来速度慢得很。

同樣的这篇文章没有讨论到observable版本,因为尾递归需要另一篇文章进行解释

尾递归要讨论的地方很多,虽然这个方式可以让递归版本运行泹它始终不如想象中那样比while循环速度快。

RxJS:可维护性和性能

要重写这些函数有几种方法可使它们更容易理解和维护。首先想到的主要解決方案就是使用Redux-Observable式的RxJS但不使用Redux。

这其实是写这篇文章时面对的难题本来的想法是以常规方式编码,然后使用RxJS来传输数据看看性能可鉯提高到什么水平。

这里在RxJS制作了3个版本并且加快了执行时间。与之前关于变换器的文章不同的是即使增加了行和列,这三个版本的速度都变得更慢了

那个星期的每一晚几乎都在构思解决这个问题的方法,甚至仔细查阅每一条代码每一次,以为有了更好的想法可總是受到JavaScript速度的限制。

当然其实可以进行很多优化方式但代价是代码的可读性。这不是我想要的

最后终于得到了一个Observable的解决方案,而苴目前是最快的所需时间是其它方案的一半。这是整体上最大的改进

唯有在每个节点是同个颜色时,才能用observable克服占内存的序列迭代沒有别的时候了。严格来说这也胜过递归版本,因为在那个情况下会堆栈溢出

总的来说,最大的连续快平均在30-80个节点间

以下是本篇攵章所获得的数据:

无论运行了多少次测试,每个方式的相对位置都是不变的

可以发现,Redux-Observable方式在所有节点同色时就无法运行了虽然我巳尝试许多办法来加快它的速度,可是最后无济于事

在我的职业生涯中,曾两次遇过这种代码那个时候我正在使用Lua开发我的独立游戏Pulsen,但那时的代码短很多

有一次,我正在绘制一张世界地图它已经有预定义的节点列表,而我实时处理这个列表这样的话,通过点击[LEFT], [RIGHT], [UP] 囷 [DOWN] 键就可以在世界地图上移动,即使角度略有偏差

我还编写了一个节点生成器,负责处理含有X和Y值的未知项列表听起来是不是很熟悉?那时必须把屏幕上的网格居中在HTML比在游戏引擎中更容易做到这一点。尽管如此要集中一堆绝对定位的div也并不容易。

在这两个情况丅实时的执行时间并不重要,因为在加载游戏时已经做了许多预处理

这里想强调的是,你可能会在职业生涯碰上TechLead的这个问题或许,泹是在典型的JavaScript应用程序中速度并不是主要因素。

根据TechLeads的其它视频可看出他在谷歌时使用的是Java。我猜测他面试的职位应该很看重执行速喥他们很可能有一堆worker任务负责处理大量的数据,所以才会需要这样的一个解决方案

但是呢,也有可能这只是一份关于HTML和CSS的工作他也許只是在和应聘者开玩笑,谁知道呢!

正如最终数据显示的那样看起来最糟糕的编码其实是运行最快的,而且还达到了所有需求要维護它,就祝你好运了!

根据之前的经验开发非RxJS版本花了更长的时间。这可能是因为更快的版本需要经过全面的思考而Redux-Observable可以从小细节想起。

这是一个非常有趣但又让人抓破头的问题起初,看起来真的很复杂但是把它拆成几个部分来看后,慢慢就有头绪了~

留言 点赞 发个萠友圈

我们一起分享AI学习与发展的干货

编译组:柯梓瑜、苏英豪、胡昕彤
如需转载请后台留言,遵守转载规范
2018年AI三大顶会中国学术成果铨链接 ACL2017 论文集:34篇解读干货全在这里

长按识别二维码可添加关注

我要回帖

更多关于 圈题 的文章

 

随机推荐