412. FizzBuzz 是一个相当经典的题目,号称是 Google 面题题 之一,这个题目虽然看似简单的但有许多细节值得深究。
Given an integer n, return a string array answer (1-indexed) where:
answer[i] == "FizzBuzz" if i is divisible by 3 and 5.
answer[i] == "Fizz" if i is divisible by 3.
answer[i] == "Buzz" if i is divisible by 5.
answer[i] == i if non of the above conditions are true.
Input: n = 3
Output: ["1","2","Fizz"]
Input: n = 15
Output: ["1","2","Fizz","4","Buzz","Fizz","7","8","Fizz","Buzz","11","Fizz","13","14","FizzBuzz"]
让使用者输入一个数字 n,产生一个从 1 到 n 的容器,当遇到三的倍数改成 Fizz、 五的倍数改成 Buzz、同时满足改成 FizzBuzz。
看完这个题目描述之後,你是不是心想「这麽简单的题目,不就是条件判断吗?」,那就让我们继续看下去!
在理解完题目与条件之後,那我们下一步就开始「#初探直觉解」并且一起尝试「#刻意优化」的过程:
第一种想法就是真的从 1 开始跑一个回圈,用三个条件分别判断「三的倍数」、「五的倍数」和「同时满足三和五的倍数」。唯一要注意的点就是「同时满足三和五的倍数」条件比较严格,所以要放在前面作判断。
class Solution:
def fizzBuzz(self, n):
ans = []
for num in range(1,n+1):
if num % 3 == 0 and num % 5 == 0:
ans.append("FizzBuzz")
elif num % 3 == 0:
ans.append("Fizz")
elif num % 5 == 0:
ans.append("Buzz")
else:
ans.append(str(num))
return ans
var fizzBuzz = function(n) {
let ans = [];
for (let i = 1; i <= n; i++) {
if (i % 15 === 0) {
ans.push('FizzBuzz');
} else if (i % 5 === 0) {
ans.push('Buzz');
} else if (i % 3 === 0) {
ans.push('Fizz');
} else {
ans.push(i + '');
}
}
return ans;
};
试着思考一下,本题有两个数的倍数,所以有三个;但如果题数有三个数字,当遇到三的倍数改成 Fizz、 五的倍数改成 Buzz、七的倍数变成 Jazz 的情况,那需要考虑的规则就有:
这就是所谓的条件会变成指数的成长,第一种方法会造成程序码撰写的复杂度急剧上升。根据观察之後,我们发现这个转换规则会有先後的顺序关系:
因此,我们想到的方法可以利用字串组装的方式,几个数字只需要跑几个条件:
s = ''
if num % 3 == 0:
s += "Fizz"
if num % 5 == 0:
s += "Buzz"
class Solution:
def fizzBuzz(self, n):
ans = []
for num in range(1,n+1):
s = ""
if num % 3 == 0:
s += "Fizz"
if num % 5 == 0:
s += "Buzz"
if not num_ans_str:
s = str(num)
ans.append(s)
return ans
var fizzBuzz = function(n) {
let ans = [];
for (let i = 1; i <= n; i++) {
let s = '';
if (i % 3 === 0)
s += 'Fizz';
if (i % 5 === 0)
s += 'Buzz';
if (!str)
s = i + '';
ans.push(s);
}
return ans
};
刚刚的想法是,如果 n 个数字需要有 n 个判断,那要如何可以自动化产生 n 个判断呢?可以把 n 个数字的转换关系写成一个 Hashmap,像这样子:
d = {3 : "Fizz", 5 : "Buzz"}
for key in d.keys():
if num % key == 0:
s += d[key]
class Solution:
def fizzBuzz(self, n):
ans = []
d = {3 : "Fizz", 5 : "Buzz"}
for num in range(1,n+1):
s = ""
for key in d.keys():
if num % key == 0:
s += d[key]
if not num_ans_str:
s = str(num)
ans.append(s)
return ans
let fizzBuzz = function(n) {
let ans = [];
let d = { 3: 'Fizz', 5: 'Buzz', ...};
for (let i = 1; i <= n; i++) {
let s = '';
for (let key in d) {
if (i % parseInt(key, 10) === 0) {
s += d[key];
}
}
if (!s) {
s += i;
}
ans.push(s);
}
return result;
};
最後一种方法是利用「三元运算子」或「模数运算」做优化,这边就当成一种火力展力给大家看看就好!
class Solution:
def fizzBuzz(self, n):
ans = []
for n in range(1, N+1):
ans.append(int(not(n % 3)) * 'Fizz' + int(not(n % 5)) * 'Buzz' or n)
return ans
var fizzBuzz = function(n) {
let ans = [];
for (let i = 1; i <= n; i++) {
s = ((i % 3 == 0 ? 'Fizz' : '') + (i % 5 == 0 ? 'Buzz' : '')) || (i + '');
ans.push(s);
}
return ans
};
这个题目绝对不是一个难题,决大部分会写程序的人一定写得出来!但这个过程中的几种延伸思考跟优化技巧反而就蛮有趣的,这就是我前面强调「#刻意优化」的例子。能写出一个程序不难,但要写出一个好的程序很难非常难。当你从「方法 ④:炫技法」再回头看「方法 ①:暴力法」应该就可以明显看受到「好」程序的的差异。所以这个题目虽然看似简单的但有许多细节值得深究,也希望大家在一个例子中一起感受优化的过程。
最後可以从题目提供的相似题看一下有哪些类似的题目,适合作为你下一个尝试的练习:
嗨,大家好!我是维元,一名擅长网站开发与资料科学的双栖工程师,斜杠於程序社群【JSDC】核心成员及【资料科学家的工作日常】粉专经营。目前在 ALPHACamp 担任资料工程师,同时也在中华电信、工研院与多所学校等单位持续开课。拥有多次大型技术会议讲者与竞赛获奖经验,持续在不同的平台发表对 #资料科学、 #网页开发 或 #软件职涯 相关的分享,邀请你加入 订阅 接收最新资讯。
<<: Day8:今天来谈一下Parrot Security上的Metasploit工具
Hi Dai Gei Ho~ 我是Winnie~ 延续上篇没有说完的内容,今天我们要来看看 Vite...
本篇是 30 天铁人赛的最後一篇,本篇做个小节与心得 课程内容与代码会放在 Github 上: ht...
我们现在设定两种权限,管理员(ADMIN)&正常(NORMAL) 要实作权限功能,我们先在u...
在IT行业工作了26年左右之後,我在2018年成功实现了年度目标,在9个月内通过了19项考试,重新...
#odoo #开源系统 #数位赋能 #E化自主 部落格是网站功能的一种型态,与一般网页较不同的地方是...