leetcode讲讲暴力解决「 263.丑数」过程中暴露出来的问题
Posted 妙七先生
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode讲讲暴力解决「 263.丑数」过程中暴露出来的问题相关的知识,希望对你有一定的参考价值。
最开始,我是直接暴力求解丑数的。抛开时间上的限制,我没想到会出现这么多意料之外的错误。在这个过程中,暴露了一些问题。这篇博客记录一下。
问题描述
给你一个整数 n ,请你判断 n 是否为 丑数 。如果是,返回 true ;否则,返回 false 。
丑数 就是只包含质因数 2、3 、 5 的正整数。
简单分析
根据丑数的定义,一个数如果是丑数,那么它将满足两个条件:
- 该数是一个正整数
- 该数的因子只会是 2、3、5,没有其他的因数存在。
- 1 是丑数
错误一
相比于后面两个问题,这个问题让我学到的东西最多。先把代码放下来:
class Solution
public boolean isUgly(int n)
if(n == 1)
return true;
for(int i = 2; i < n; ++i)
if(n % i == 0)
if(i != 2 || i != 3 || i != 5)
return false;
return true;
错误是在输入 6 的时候出错的。我不太明白问题出在哪?所以我便debug了一下。发现在 第二层 if
语句中便出现了错误。
在因子为2 的时候,程序竟然会执行到 if
里面?按照我的逻辑
在该因子不是2 或者 不是3 或者 不是5的时候才会返回 false。
但是,在因子是2的情况下,竟然还会输出false。慢慢地,我发现,这程序在运算 i != 2
之后还会运行 i != 3
…我当时脑子一下子就瓦特了。不对呀,||会短路呀,i!=2
是false, 为什么还会执行 i!=3
。于是,我便重新搜索了一下 ||
。
「短路」运算符
&&、|| 都是一个短路 的逻辑运算符。如果该表达式可以通过一侧的运算结果确定「最终的结果」的情况下,那么另一侧的表达式将不会运行。
对于 || 来说, 左侧的表达式为 false
,并不能说明最终的结果究竟是 true
还是 false
。所以,程序最终还会执行 i !=3
。
a | b | a||b |
---|---|---|
true | false | true |
true | true | true |
false | true | true |
false | false | false |
总结一下:对于 || 来说,只有当左侧为true时,才会短路
我把它和 &&
搞混了:
a | b | a&&b |
---|---|---|
true | true | true |
true | false | false |
false | false | false |
false | true | false |
总结一下:对于&&来说,只有当左侧为false时,才会短路。
正是因为当 i=2
时,i!=2
是 false
,所以才会执行 i!=3
。
那么,对于我这个程序来说,只要输入的 n 是 2 的倍数,那么该程序一定会输出 false。
修改后的程序为:
class Solution
public boolean isUgly(int n)
if(n == 1)
return true;
for(int i = 2; i < n; ++i)
if(n % i == 0)
if(i == 2 || i == 3 || i == 5)
continue;
else
return false;
return true;
这样简单的修改,直接导致了 错误二的诞生。
错误二
由于我是直接枚举每一个数,进行遍历,所以在遇见 2、3、5的倍数时,便不会达到预期结果。修改很简单:
class Solution
public boolean isUgly(int n)
if(n == 1)
return true;
for(int i = 2; i < n; ++i)
if(n % i == 0)
if(i % 2 == 0 || i % 3 == 0|| i % 5 == 0)
continue;
else
return false;
return true;
错误三
我一开始并没有意识到「丑数是一个正整数」这一个条件,最终导致的结果便是在处理负数的时候出现了错误。
由于这个数值的特殊性,我最开始以为,这是由于代码溢出造成的。看了半天代码之后,没有发现会导致溢出的地方。我没有做任何的加或者乘运算,怎么可能会出现这种错误?代码如下:
class Solution
public boolean isUgly(int n)
if(n == 1)
return true;
for(int i = 2; i < n; ++i)
if(n % i == 0)
if(i % 2 == 0 || i % 3 == 0|| i % 5 == 0)
continue;
else
return false;
return true;
所以,我又去猜测 %
在处理负数时不太一样。然后发现并没有什么不同。
(羞耻~ 后来发现,负数连for循环都进不去,怎么可能会执行 %
操作)
那么,到底问题出现在哪儿?我最终看了一遍题目,发现 丑数是一个正整数。
修改后的代码如下:
class Solution
public boolean isUgly(int n)
if(n <= 0)
return false;
if(n == 1)
return true;
for(int i = 2; i < n; ++i)
if(n % i == 0)
if(i % 2 == 0 || i % 3 == 0|| i % 5 == 0)
continue;
else
return false;
return true;
错误三
这个错误出现的原因很简单:7是素数。因为我遍历的范围是[2,n),所以,输入7之后,程序不会进入 if 语句中,更别说输出 false
了。
为了修正这个错误,我把范围改为[2,n]。
class Solution
public boolean isUgly(int n)
if(n <= 0)
return false;
if(n == 1)
return true;
for(int i = 2; i <= n; ++i)
if(n % i == 0)
if(i % 2 == 0 || i % 3 == 0|| i % 5 == 0)
continue;
else
return false;
return true;
暴力成功,虽然时间超出了。
正确的代码——非暴力求解
class Solution
public boolean isUgly(int n)
if(n <= 0)
return false;
if(n == 1)
return true;
int[] factors = 2,3,5;
for(int factor : factors)
while(n % factor == 0)
n /= factor;
return n == 1;
总结
- 基础知识掌握的不牢固,或者说,只会纸上谈兵。
以上是关于leetcode讲讲暴力解决「 263.丑数」过程中暴露出来的问题的主要内容,如果未能解决你的问题,请参考以下文章