一道让我怀疑人生的题
之前经常有人说刚开始刷题时会怀疑人生,觉得每道题都很难,问这正不正常。其实这是正常的,算法本来就是诸多智慧的结晶,何况能拿出来面试的题目都不容易,哪有人万事通,总有我们从未解决过的难题出现,今天我还随机到了一道让我做到怀疑人生的题。
题目是这样的:初始时有 n 个灯泡关闭。第 1 轮,你打开所有的灯泡。第 2 轮,每两个灯泡你关闭一次。第 3 轮,每三个灯泡切换一次开关(如果关闭则开启,如果开启则关闭)。第 i 轮,每 i 个灯泡切换一次开关。对于第 n 轮,你只切换最后一个灯泡的开关。找出 n 轮后有多少个亮着的灯泡。
这题目乍一看,很简单呀,我套一下循环就能做出来,后期再看怎么优化:
public int bulbSwitch(int n) {
int result = 0;
int [] arr = new int[n];
for (int i = 0; i < arr.length; i++) {
arr[i] = 1;
}
for (int i = 1; i <= arr.length -1; i++) {
int times = i +1;//第多少轮
for (int j = 0; j < arr.length; j++) {
if ((j+1) %times == 0) {
if (arr[j] == 0) {
arr[j]=1;
}else{
arr[j] =0;
}
}
}
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 1) {
result ++;
}
}
return result;
}
当我兴高采烈地提交的时候,心想着虽然这种暴力解法不够优雅,没有灵魂在里面,但至少算写出来了吧,等会儿我再慢慢优化,没想到直接超时了!
我这下有点懵了,这道题不满足动态规划的结构,也没有我总结的那些套路中关键的条件,还是说有什么隐藏的信息我没有考虑到,抓耳挠腮两个小时也就过去了,再折腾下去我也想不出解法了。默默地点开了题解,题解短到让人看不懂:
int bulbSwitch(int n)
{
return (int)sqrt(n);
}
这是个什么意思,求平方根?这代码的每一个单词我都认识,代码的功能我也都明白,可是它是怎么解答这个问题的呢?
我又默默点开了大神们的讨论,他们有条不紊的分析,一个个的数学公式,一个个的“显而易见”让我头皮发麻,觉得受到了降维打击,虽然咱智商比不过大神们,还是硬着头皮逼着自己去理解他们的思路。
首先,我们得知道判断灯泡是开还是关的方法,将包含本轮在内的对第i个灯泡的所有操作次数做和,若为奇数,说明第i个灯泡,经过j轮以后,是亮着的,因为第0轮一定是关闭的。同理,若为偶数,说明第i个灯泡,经过j轮以后,是关闭的。所以我们的问题也就转换成了,经过n轮,第i个灯泡被操作了奇数次还是偶数次?奇数次则最后是亮的,偶数次则最后是关闭的。
那么如何计算操作的次数呢?这看起来是个大活儿啊。我们再来观察一下:第1个灯泡在什么时候会被操作?第1轮。第10个灯泡在什么时候会被操作?第1轮,第2轮,第5轮,第10轮。第20个灯泡在什么时候会被操作?第1轮,第2轮,第4轮,第5轮,第10轮,第20轮。我们可以发现,第 i 个灯泡只有在第 k 轮会被操作,而 k 一定是 i 的因数。并且 n>=k。所以如果一个数的因数的个数为奇数个,那么它最后一定是亮的,否则是关闭的。
这时候我们的问题已经转换成,什么数的因数的个数是奇数个?回答是完全平方数。为什么它的因数就是奇数个呢?设P,A,B 为正整数,如果 P=A*B,则A和B为P的因数。P的因数A和B总是成对出现。也就是说他们总是一起为 P 的因数个数做贡献,为2。但是如果他们相等呢?这个时候他们一起只会为因数的个数贡献 1。
所以正解就是求平方根了。
看到这里相信好多同学也觉得智商被压制了。没关系,想告诉大家的是觉得刷题吃力也不要有压力,都是这么熬过来的,没有什么路是一直轻松的,跟我一样厚着脸皮看题解就好了嘛。学到了总结出经验了就是自己的,这种需要大量经验跟智商的题做不出来也没什么丢人的嘛(自我洗脑中),前路漫漫,大家共勉。
- es6 对象的扩展
- 自定义WordPress 标签云小工具相关参数
- 检查.NET程序平台目标(Platform Target)工具CorFlags
- 哪些行业最适合抢驻小程序?
- WordPress 一键关闭/禁止页面评论功能
- 在一个.net sln中包含多个project,project引用同一个dll导致的错误
- Windows下安装MariaDB
- Quartz.net官方开发指南 第一课:使用Quartz.net
- Quartz.net官方开发指南 第二课:Jobs And Triggers
- 为你的WordPress 主题添加结构化数据/丰富文本摘要,高亮搜索结果(上)
- 复合事件处理(Complex Event Processing)介绍
- Quartz.net官方开发指南 第三课:更多关于Jobs和JobDetails
- 为你的WordPress 主题添加结构化数据/丰富文本摘要,高亮搜索结果(下)
- Quartz.net官方开发指南 第四课:关于Triggers更多内容
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法