Google面试题(选自公众号)
date: 2018-12-14 13:34:56
updated: 2018-12-14 13:34:56
Google面试题(选自公众号)
问题
把你的手机拨号页想象成一个棋盘。棋子走只能走“L”形状,横着两步,竖着一步;或者竖着两步,横着一步。
现在,假设你拨号只能像棋子一样走“L”形状。每走完一个“L”形拨一次号,起始位置也算拨号一次。问题:从某点开始,在N步内,你可以拨到多少不同的数字?
讨论
每次面试,我基本都会分成两个部分:首先我们找出算法方案,然后让面试者在代码中实现。我说“我们找出算法方案”,因为这个过程我不是沉默的独裁者。在这样高压下,设计并实现一种算法,45分钟时间并不算充足。
我通常会让面试者主导讨论,让他们去产生想法,我嘛,就在旁边,时不时地泄漏一点点“天机”。面试者们能力越强,我需要泄漏的“天机”就越少;但是目前为止,我还没遇到一点都不需要我提示的面试者。
有一点我想强调一下,重要的很:作为面试官,我的职责可不是坐那看着大家失败搞砸。我想要给大家正面的反馈,给大家机会去展现大家最擅长的点。给他们提示,就像是在说:呐,这一步路我给你铺上,但这只是为了让你展示给我,你在后面的路上能走的更远。
当听完面试官的问题,你应该做什么?切记不要立刻就去写代码,而是在黑板上试着一步一步去分解问题。分解问题能够帮助你寻找到规律,特例等等,逐渐在大脑中形成解决方案。比如,你现在从数字6开始走,能走2步,会有如下组合:
6–1–8
6–1–6
6–7–2
6–7–6
6–0–4
6–0–6
一共有6种组合。你可以试着用铅笔在纸上画,相信我,有时候动手去解决问题会发生意想不到的事,比你盯着在脑袋里想更神奇。
怎么样?你脑海里有方案了吗?
第0阶:到达下一步
使用这个问题面试,最让我惊讶的是,太多人都卡在了计算从某个特定点跳出时,一共有多少种可能,即邻Neighbors。我的建议是:当你不确定时,先写个占位符,然后请求面试官能否晚点实现这一部分。
这个问题的复杂性并不在Neighbors的计算;我在意的是你如何计算出总数。所有花费在计算Neighbors上的时间其实都是浪费。
我会接受“让我们假设有一个函数能给出我Neighbors”。当然,我也可能会让你后面有时间再去实现这一步,你只需要这样写,然后继续。
而且,如果一个问题的复杂性不在这里,你也可以问我能不能先略过,一般我都是允许的。我倒是不介意面试者不知道问题的复杂性在哪里,尤其刚开始他们还没有全面了解问题的时候。
至于Neighbors函数,因为数字永远不变,你可以直接写一个Map然后返回符合的值。
第1阶:递归
聪明的你可能注意到了,这个问题可以通过枚举出所有符合条件的数字,然后计算。这里可以使用递归产生这些值:
这个方法可以,而且是在面试中最普遍的方法。但是请注意,我们产生了这么多数字却并没有使用他们,我们计算完他们的个数后,就再也不去碰了。所以我建议大家遇到这种情况,尽量去想一下看有没有更好的方案。
第2阶:数不数数
怎么在不产生这些数字的情况下计算出个数?可以做到,但需要一点点机智。注意从特定点跳出N次能够拨到的数字个数,等于从它所有临近的点跳出N-1次能够拨到的数字个数的总和。我们可以表达为这样的递归关系:
如果你这样想,就会很直观了,跳一次时:6有3个neighbors(1,7和0),当跳0次时每个数字本身算一次,因此每次你只能拨到3个数字。
怎么会产生这样机智的想法?其实,如果你学了递归,并且在黑板上好好研究,这一点就会变得显而易见。这样你就能继续去解决这个问题,实际上就这一点就有多种实现方法,下面这个便是面试中最常见的:
就是这样,结合这个函数计算出neighbors 就可以了。这时候,你就可以捏捏肩膀休息下了,因为到这里,你已经刷掉很多人了。
接下来这个问题我经常问:这个方案的算法理论速度如何?在这个实现中,每次调用count_sequences()都会递归地调用count_sequences()至少2次,因为每个数字至少有2个neighbors。这样会导致runtime成指数增长。
对于跳1次到20次这样的次数还可以,但是到更大的数字,我们就要碰壁。500次可能就需要整个宇宙的热量来完成运算。
第3阶:记忆
那么,我们能做的更好么?使用上面的方法,并不能。我喜欢这个问题,也是因为他能一层一层带出大家的智慧,找到更高效的方法。为了找到更好的方法,让我们看下这个函数是怎么调用的,以count_sequences(6, 4)为例。注意这里用C作为函数名简化。
你可能注意到了,C(6, 2)运行了3次,每次都是同样的运算并返回同样的值。这里最关键的点在于这些重复的运算,每次你使用过他们的值之后,就没有必要再次计算。
怎么解决这个问题?记忆。我们那些相同的函数调用和结果,而不是让他们重复。这样,在后面我们就可以直接给出之前的结果。实现方法如下:
第4阶:动态设计
如果你再看看前面的递归关系,就会发现递归记忆的方案也有一点局限性:
注意跳N次的结果仅仅取决于跳N-1次后调用的结果。同时,缓存中包含着每个次数的所有结果。我之所以说这是个小局限,因为确实不会造成真的问题,当跳的次数增长时,缓存也只是线性增长。但是,毕竟,这还是不够高效。
怎么办?让我们再来看一看方案和代码。注意,代码中是从最大的次数开始,然后直接递归到最小的次数:
如果你把整个的函数调用图想象成某种虚拟的树,你就会发现我们在执行深度优先策略。这并没有什么问题,但是它没有利用到浅依赖这个属性。
如何实现广度优先策略?这里就是一种实现方法:
这个版本比前面递归版好在哪里?其实并没有好很多,但是这个不是递归的,因此即使处理超大数据也很难崩溃。其次,它使用的是常量内存;最后,它仍旧是线性增长,即便处理200000次跳也只用不到20秒。
Google面试题(选自公众号)的更多相关文章
- 线程安全使用(四) [.NET] 简单接入微信公众号开发:实现自动回复 [C#]C#中字符串的操作 自行实现比dotcore/dotnet更方便更高性能的对象二进制序列化 自已动手做高性能消息队列 自行实现高性能MVC WebAPI 面试题随笔 字符串反转
线程安全使用(四) 这是时隔多年第四篇,主要是因为身在东软受内网限制,好多文章就只好发到东软内部网站,懒的发到外面,现在一点点把在东软写的文章给转移出来. 这里主要讲解下CancellationT ...
- Typora +google + Markdown Here 公众号
一劳永逸的公众号排版方法 http://mp.weixin.qq.com/s/zb-YaacNLggG2-njF5HJ0A
- appium+java(四)微信公众号自动化测试实践
前言 随着手机阅读的普遍应用,微信公众号阅读,更为普遍,微信和qq一样,都是基于腾讯自研X5内核,不是google原生webview(其实就是进行了二次定制).实质上也是混合应用的一种,现在很多app ...
- 使用Appium 测试微信小程序和微信公众号方法
由于腾讯系QQ.微信等都是基于腾讯自研X5内核,不是google原生webview,需要打开TBS内核Inspector调试功能才能用Chrome浏览器查看页面元素,并实现Appium自动化测试微信小 ...
- 微信公众号开发C#系列-12、微信前端开发利器:WeUI
1.前言 通过前面系列文章的学习与讲解,相信大家已经对微信的开发有了一个全新的认识.后端基本能够基于盛派的第三方sdk搞定大部分事宜,剩下的就是前端了.关于手机端的浏览器的兼容性问题相信一直是开发者们 ...
- 人工智能头条(公开课笔记)+AI科技大本营——一拨微信公众号文章
不错的 Tutorial: 从零到一学习计算机视觉:朋友圈爆款背后的计算机视觉技术与应用 | 公开课笔记 分享人 | 叶聪(腾讯云 AI 和大数据中心高级研发工程师) 整 理 | Leo 出 ...
- 微信公众号开发之VS远程调试
目录 (一)微信公众号开发之VS远程调试 (二)微信公众号开发之基础梳理 (三)微信公众号开发之自动消息回复和自定义菜单 前言 微信公众平台消息接口的工作原理大概可以这样理解:从用户端到公众号端一个流 ...
- C#开发微信门户及应用(37)--微信公众号标签管理功能
微信公众号,仿照企业号的思路,增加了标签管理的功能,对关注的粉丝可以设置标签管理,实现更加方便的分组管理功能.开发者可以使用用户标签管理的相关接口,实现对公众号的标签进行创建.查询.修改.删除等操作, ...
- C#开发微信门户及应用(27)-公众号模板消息管理
通过模板消息接口,公众号能向关注其账号的用户发送预设模板的消息.模板消息仅用于公众号向用户发送重要的服务通知,只能用于符合其要求的服务场景中,如信用卡刷卡通知,商品购买成功通知等.不支持广告等营销类消 ...
随机推荐
- rest_framework五大模块
面向对象封装 面向对象封装导入 # 1.将子类共有的方法抽离形成父类方法 # 2.子类使用共有方法,使用的是父类方法 # 3.共有方法中的资源,在子类使用方法时,获取的是子类资源 class MyCl ...
- HotSpot VM 中的JIT分类
在HotSpot VM中内嵌有两个JIT编译器,分别为Client Compiler和Server Compiler,但大多数情况下我们简称为C1编译器和C2编译器.开发人员可以通过如下命令显式指定J ...
- 手把手教你在容器服务 TKE 上使用 LB 直通 Pod
什么是 LB 直通 Pod ? Kubernetes 官方提供了 NodePort 类型的 Service,即给所有节点开一个相同端口用于暴露这个 Service,大多云上 LoadBalancer ...
- get请求传递json格式数据的两种方法
get请求参数为json格式数据,使用pyhton+request的两种实现方式如下: 方法一:使用requests.request() 示例代码如下: 1.导入requests和json impor ...
- Python-变量、变量作用域、垃圾回收机制原理-global nonlocal
变量实现原理决定了Python使用的垃圾回收机制为变量引用计数,当这个对象引用计数为0时候,则会自动执行__del__函数回收资源, del方法只是把变量指向的对象引用计数减一而已并删除这个变量 表达 ...
- 记一次uwsgi django nginx 调优
[uwsgi] project = fortune_cat uid = ubuntu gid = ubuntu path = fortune_cat base = /home/%(uid) chdir ...
- matlab中figure 创建图窗窗口
来源:https://ww2.mathworks.cn/help/matlab/ref/figure.html?searchHighlight=figure&s_tid=doc_srchtit ...
- 【题解】Product
\(\color{brown}{Link}\) \(\text{Solution:}\) \(Question:\) \(\prod_{i=1}^n \prod_{j=1}^n \frac{lcm(i ...
- PicGo图床与Typora(PicGo+Typora+GitHub的完整设置)
PicGo图床与Typora(PicGo+Typora+GitHub的完整设置) 如何更方便的用markdown写文章,接下来按照我的步骤来,你一定可以的,这个文章包含了GitHub图床配置.PicG ...
- 一些IT service的相关知识
1. cmd是什么,怎么在电脑上打开cmd命令框. 在windows环境下,命令行程序为cmd.exe,是一个32位的命令行程序,微软Windows系统基于Windows上的命令解释程序,类似于微软的 ...