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)-公众号模板消息管理
通过模板消息接口,公众号能向关注其账号的用户发送预设模板的消息.模板消息仅用于公众号向用户发送重要的服务通知,只能用于符合其要求的服务场景中,如信用卡刷卡通知,商品购买成功通知等.不支持广告等营销类消 ...
随机推荐
- NuxtJS快速入门
服务器端渲染(SSR) 知识储备 ES6 Nodejs Vue React Angular 什么是服务器端渲染 前端渲染:html页面作为静态文件存在,前端请求时后端不对该文件做任何内容上的修改,直接 ...
- .NET Core开源导入导出库 Magicodes.IE 2.3发布
在2.3这一版本的更新中,我们迎来了众多的使用者.贡献者,在这个里程碑中我们也添加并修复了一些功能.对于新特点的功能我将在下面进行详细的描述,当然也欢迎更多的人可以加入进来,再或者也很期待大家来提is ...
- 深入理解SVM,详解SMO算法
今天是机器学习专题第35篇文章,我们继续SVM模型的原理,今天我们来讲解的是SMO算法. 公式回顾 在之前的文章当中我们对硬间隔以及软间隔问题都进行了分析和公式推导,我们发现软间隔和硬间隔的形式非常接 ...
- BeautifulSoup解析页面
beautiful soup是一个解析包,专门用来解析html语法的,lxml是一个解析器,用来分析以及定位内容的 .是class #是id import requests from bs4 impo ...
- ThreadLocal源码分析与实践
ThreadLocal是什么? ThreadLocal是一个线程内部存储类,提供线程内部存储功能,在一个ThreadLocal对象中,每一个线程都存储各自独立的数据,互不干扰 示例如下: public ...
- MySQL中concat()、concat_ws()、group_concat()函数的使用技巧与心得总结
Author:极客小俊 一个专注于web技术的80后 我不用拼过聪明人,我只需要拼过那些懒人 我就一定会超越大部分人! CSDN@极客小俊,原创文章, B站技术分享 B站视频 : Bilibili.c ...
- PCA基本原理
降维问题的优化目标:将一组N维向量降维k维(K大于0,小于N),其目标是选择K个单位(模为1)正交基,使得原始数据变换到这组基上后, 选择然数据点之间方差最大的方向作为坐标轴 各字段两两间协方差为0, ...
- STM32之旅5——IWDG
STM32之旅5--IWDG stm32有两个看门狗,一个独立看门狗(IWDG).一个窗口看门狗(WWDG):独立看门狗是时钟源是内部的40kHz的低速时钟,即使主频出问题了,独立看门狗也不会受到影响 ...
- kalilinux2020.3的安装与一些坑
1.下载镜像文件.iso kali官方下载太慢,用一些魔法也是不行,这里推荐用国内的下载源. 阿里云: https://mirrors.aliyun.com/kali-images/?spm=a2c6 ...
- 使用响应扩展的响应面(Rx)
下载demo - 196 KB 下载source - 98 KB 表的内容 系统要求反应面一个简单的计时器从事件中收集数据序列使用更复杂的查询订阅您希望完成的面最终考虑历史 介绍 "Rx&q ...