写一个程序,输出从 1 到 n 数字的字符串表示。
1.如果 n 是3的倍数,输出“Fizz”;
2.如果 n 是5的倍数,输出“Buzz”;
3.如果 n 同时是3和5的倍数,输出 “FizzBuzz”。示例:n = 15,
返回: [ “1”,“2”,“Fizz”, “4”, “Buzz”, “Fizz”, “7”, “8”, “Fizz”, “Buzz”,“11”,“Fizz”, “13”,“14”,“FizzBuzz” ]
方法一: 条件判断
var fizzBuzz = function(n) {
let res = [];
for(i=1;i<=n;i++){
if(i % 3 == 0 && i % 5 == 0){
res.push("FizzBuzz");
}else if(i % 3 == 0){
res.push("Fizz");
}else if(i % 5 == 0){
res.push("Buzz");
}else{
res.push(i+'');
}
}
return res;
};
复杂度分析
时间复杂度: O(N)
空间复杂度: O(1)
方法二: 字符串连接
这个方法不会降低渐进复杂度,但是当 FizzBuzz 的规则变得更复杂的时候,这将会是个更优雅的解法。比方说,玩个 FizzBuzzJazz 的游戏。规则如下:
3 —> “Fizz” , 5 —> “Buzz”, 7 —> “Jazz”
如果你还是用之前的方法来解决这个问题的话,那将会有非常多的条件需要判断。
能不能被 3 整除
能不能被 5 整除
能不能被 7 整除
能不能同时被 3 和 5 整除
能不能同时被 5 和 7 整除
能不能同时被 3 和 7 整除
能不能同时被 3,5,7 整除
不能被 3,5,7 其中任何一个数整除
如果 FizzBuzz 照着这种方式变地更复杂的话,那么你要写的判断可能会让你抓狂。
我们放弃使用之前的联合判断,取而代之依次判断是否能被给定的数整数。这道题中,就是依次判断能不能被 3 整除,能不能被 5 整除。如果能被 3 整除,就把对应的 Fizz 连接到答案字符串,如果能被 5 整除,就把 Buzz 连接到答案字符串。
举个例子,现在需要判断 15,步骤将会是下面这样的:
条件 1: 15 % 3 == 0, ans = “Fizz”
条件 2: 15 % 5 == 0, ans += “Buzz”
=> ans = “FizzBuzz”
对于 FizzBuzz 来说,只需要判断两个条件就可以了,而不需要像方法一中那样判断三个条件。
同样的,对于 FizzBuzzJazz,现在只需要判断三个条件就可以了。
var fizzBuzz = function(n) {
let res = [];
for(i=1;i<=n;i++){
let ans = "";
if(i % 3 == 0){
ans += "Fizz";
}
if(i % 5 == 0){
ans += "Buzz";
}
if(ans === ""){
ans += i;
}
res.push(ans);
}
return res;
};
复杂度分析
时间复杂度: O(N)
空间复杂度: O(1)
方法三:用散列表
这个方法是对方法二的优化。当数字和答案的映射是定好的,那么方法二用起来也还可以。但是如果需要更自由的映射,每个映射一个判断显然是不可行的,这样写出来的代码一定是丑陋不堪且难以维护的。如果需要把映射关系换掉或者删除一个映射关系吧。对于这种要求,只能一个个去修改判断条件的代码。但我们实际上有个更优雅的做法,那就是把映射关系放在 散列表 里面。
通过这样的方式你可以对散列表添加/删除映射关系,同时还不需要修改太多代码。而对于 FizzBuzzJazz 这个问题,散列表就可以是这样的,{ 3: ‘Fizz’, 5: ‘Buzz’, 7: ‘Jazz’ }。
/**
* @param {number} n
* @return {string[]}
*/
var fizzBuzz = function(n) {
let res = [];
let map = new Map();
map.set(3,"Fizz");
map.set(5,"Buzz");
for(i=1;i<=n;i++){
let ans = "";
for (let key of map) {
if(i % key[0] == 0){
ans += key[1];
}
}
if(ans == "") ans = i +'';
res.push(ans);
}
return res;
};
复杂度分析
时间复杂度: O(N)
空间复杂度: O(1)