解解Nodejs FizzBuzzWhizz这道题

解解Nodejs FizzBuzzWhizz这道题

今天看到TW发了道FizzBuzzWhizz的面试题。这道题其实就是逢3过的高级版,手痒痒来解一下。。

  1. 你首先说出三个不同的特殊数,要求必须是个位数,比如3、5、7。
  2. 让所有学生拍成一队,然后按顺序报数。
  3. 学生报数时,如果所报数字是第一个特殊数(3)的倍数,那么不能说该数字,而要说Fizz;如果所报数字是第二个特殊数(5)的倍数,那么要说Buzz;如果所报数字是第三个特殊数(7)的倍数,那么要说Whizz。
  4. 学生报数时,如果所报数字同时是两个特殊数的倍数情况下,也要特殊处理,比如第一个特殊数和第二个特殊数的倍数,那么不能说该数字,而是要说FizzBuzz, 以此类推。如果同时是三个特殊数的倍数,那么要说FizzBuzzWhizz。
  5. 学生报数时,如果所报数字包含了第一个特殊数,那么也不能说该数字,而是要说相应的单词,比如本例中第一个特殊数是3,那么要报13的同学应该说Fizz。如果数字中包含了第一个特殊数,那么忽略规则3和规则4,比如要报35的同学只报Fizz,不报BuzzWhizz。

说实话,作为程序员,如果解不出这道题,真的该考虑改行了。号称最难面试的TW考察的肯定不是仅仅能正确跑出结果。我觉得这道题的得分项在这里:

  • 强烈建议写单元测试,这个没什么说的;
  • 请展示出你超赞的面向对象/函数式编程功底,coding是一种武功,不同的领悟打出不同的招式和威力;
  • 建议尽量减少圈复杂度,我想最让人崩溃的就是看一坨充满了for/if/switch的代码;

好了,来看题。。 这道题其实就是把输入(一个数字)经过一系列的规则转换成Fizz/Buzz/Whizz,来看看这些rule:

  1. 如果这个数包含了第一个特殊数,输出Fizz;
  2. 如果这个数是某个特殊数的倍数,输出相应单词;
  3. 直接输出原数;

估计很多人到这就直接开始写分支判断了。其实这三个规则存在这样的优先级:rule1 > rule2 > rule3,而在javascript的||操作符正好适用,这样也就避免了代码里充斥分支语句。基于这样一个规则表,我们就可以写出代码了。高亮版

var _ = require('underscore');

var special_words = [“Fizz”, “Buzz”, “Whizz”]; var candidates = seq(9); // 1…9

// select 3 random numbers from candidates. var special = (3).times(function(i) { var selected = candidates[.random(candidates.length-1)]; candidates = _.without(candidates, selected); return selected; }); console.log(special);

var input = seq(100); // 1…100

// main var output = _.map(input, function yamete(n) { return rule1(n) || rule2(n) || rule3(n); });

console.log(_.zip(input, output));

function rule1(n) { return new RegExp(special[0] + ‘’).test(n + ‘’) ? special_words[0]:false; }

function rule2(n) { return _.reduce(special, function(memo, s){ this.i++; return memo + ((n%s) ? ‘’ : special_words[this.i]); }, ‘’, {i:-1});
}

function rule3(n) { return n; }

function seq(n) { return _(n).times(function(n){return n+1}); }


8 回复

解解Node.js FizzBuzzWhizz这道题

今天看到TW发了一道FizzBuzzWhizz的面试题。这道题其实就是“逢3过”的高级版,手痒痒来解一下。

题目描述

  1. 你首先说出三个不同的特殊数,要求必须是个位数,比如3、5、7。
  2. 让所有学生排成一队,然后按顺序报数。
  3. 学生报数时,如果所报数字是第一个特殊数(3)的倍数,那么不能说该数字,而要说Fizz;如果所报数字是第二个特殊数(5)的倍数,那么要说Buzz;如果所报数字是第三个特殊数(7)的倍数,那么要说Whizz。
  4. 学生报数时,如果所报数字同时是两个特殊数的倍数情况下,也要特殊处理,比如第一个特殊数和第二个特殊数的倍数,那么不能说该数字,而是要说FizzBuzz, 以此类推。如果同时是三个特殊数的倍数,那么要说FizzBuzzWhizz。
  5. 学生报数时,如果所报数字包含了第一个特殊数,那么也不能说该数字,而是要说相应的单词,比如本例中第一个特殊数是3,那么要报13的同学应该说Fizz。如果数字中包含了第一个特殊数,那么忽略规则3和规则4,比如要报35的同学只报Fizz,不报BuzzWhizz。

编程思路

说实话,作为程序员,如果解不出这道题,真的该考虑改行了。号称最难面试的TW考察的肯定不是仅仅能正确跑出结果。我觉得这道题的得分项在这里:

  • 强烈建议写单元测试;
  • 请展示出你超赞的面向对象/函数式编程功底;
  • 建议尽量减少圈复杂度。

示例代码

这道题其实就是把输入(一个数字)经过一系列的规则转换成Fizz/Buzz/Whizz,来看看这些规则:

  1. 如果这个数包含了第一个特殊数,输出Fizz;
  2. 如果这个数是某个特殊数的倍数,输出相应单词;
  3. 直接输出原数。
var _ = require('lodash');

var special_words = ["Fizz", "Buzz", "Whizz"];
var candidates = _.range(1, 10); // 1..9

// 选择3个随机数作为特殊数
var special = _.sampleSize(candidates, 3);
console.log(special);

var input = _.range(1, 101); // 1..100

// 主逻辑
var output = input.map(function(n) {
    return rule1(n) || rule2(n) || rule3(n);
});

console.log(_.zip(input, output));

function rule1(n) {
    return special.includes(n % 10) ? special_words[0] : false;
}

function rule2(n) {
    return special.map((s, i) => (n % s === 0) ? special_words[i] : '').filter(Boolean).join('');
}

function rule3(n) {
    return n.toString();
}

代码解析

  1. special_wordscandidates 分别定义了特殊词和候选数。
  2. special 从候选数中随机选取3个特殊数。
  3. input 定义了输入范围为1到100。
  4. output 是通过 rule1, rule2, rule3 规则生成的结果。
  5. rule1 检查数字是否包含特殊数的个位数。
  6. rule2 检查数字是否是特殊数的倍数,并组合相应单词。
  7. rule3 返回原始数字。

希望这个解答对你有帮助!


这题的关键点不是在解,而是要解得精,那个10行代码是关键。

好吧,如果TW招人是为了帮他们写更短的代码的话,我就无话可说了。其实这个题要是放在某某hack大赛上,更短的代码肯定是更有意思。任何实现代码都必须完成这道题里的点(循环,字符串查找,倍数判断等),如果某种语言有库或是语法能更简短的实现这里的点,那就可以写出你所谓的精。甚至我还可以依此问题域设计一门DSL,只用一行代码就可以解题了。。^^

// 获得用户输入
var nums = process.argv[2];
if (!nums) die('please enter three numbers. example: 3,5,7');
nums = nums.split(',');
if (nums.length !== 3) die('please enter three numbers. example: 3,5,7');
nums.forEach(function (n) {
  if (!(n > 0 && n < 10)) die(n + ' is not an valid number. must be greater than 0 and less than 10');
});

function die (msg) {
  console.log(msg);
  process.exit(-1);
}

function print (msg) {
  console.log(msg);
}

/******************************************************************************/

var a = nums[0], b = nums[1], c = nums[2];
var A = 'Fizz', B = 'Buzz', C = 'Whizz';

function isIn (i, n) {
  return (i.toString().indexOf(n) !== -1);
}

function isTimes (i, n, s) {
  return (i % n === 0) ? s : '';
}

// 计算
for (var i = 1; i <= 100; i++) {
  if (isIn(i, a)) {
    print(A);
  } else {
    var s = isTimes(i, a, A) + isTimes(i, b, B) + isTimes(i, c, C);
    print(s || i);
  }
}

想去TW试试的话,赶紧投了,^_^


###C#解决方案,全文20行,实现方法不超过10行,无if,else,while条件语句。


using System;
using System.Linq;

namespace FizzBuzzWhizz { class Program { static void Main(string[] args) { Output(Console.ReadLine()); Console.ReadLine(); } static void Output(string recive) { int[] Input = recive.Split(’,’).Select(i => Convert.ToInt32(i)).ToArray(); for (int i = 0; i <= 100; i++) { Console.WriteLine(i.ToString().Contains(Input[0].ToString()) ? “Fizz” : (0 != i % Input[0] && 0 != i % Input[1] && 0 != i % Input[2]) ? i.ToString() : (0 == i % Input[0] ? “Fizz” : “”) + (0 == i % Input[1] ? “Buzz” : “”) + (0 == i % Input[2] ? “Whizz” : “”)); } } } }

我感觉减少循环次数是个坑,如果都按照100×3的循环太没有创意了。。 构造答案才是王道啊。还有你们都考虑了0和负数的情况吗 function zz(a, b, c) { var result = new Array(101); add(a, result, ‘Fizz’); add(b, result, ‘Buzz’); add(c, result, ‘Whizz’); if(a<0)return result; for(var i=0;i<=9;i++){ v1 = Number(i+’’+a); result[v1] = ‘Fizz’; if(a == 0) continue; v2 = Number(a+’’+i); result[v2] = ‘Fizz’; } if(a==0)result[100] = ‘Fizz’; return result; }

function add(n, a, v) { n = Math.abs(n); if(n == 0) return; for(var i = n;i<=100;i++){ if(a[i]) a[i] += v; else a[i] = v; } }

解FizzBuzzWhizz这道题的核心在于如何根据给定的规则将输入数字转换为对应的字符串。下面是具体的实现方式:

  1. 首先定义三个特殊数 special,例如 [3, 5, 7]
  2. 定义三个特殊词 special_words,与 special 对应。
  3. 定义 rule1,检查数字是否包含任意一个特殊数。
  4. 定义 rule2,检查数字是否是任意一个特殊数的倍数。
  5. 定义 rule3,返回原始数字。

以下是示例代码:

const special = [3, 5, 7];
const special_words = ["Fizz", "Buzz", "Whizz"];

function rule1(n) {
    for (let i = 0; i < special.length; i++) {
        if (n.toString().includes(special[i].toString())) {
            return special_words[i];
        }
    }
    return false;
}

function rule2(n) {
    let result = '';
    for (let i = 0; i < special.length; i++) {
        if (n % special[i] === 0) {
            result += special_words[i];
        }
    }
    return result;
}

function rule3(n) {
    return n;
}

function fizzBuzzWhizz(n) {
    return rule1(n) || rule2(n) || rule3(n);
}

const input = Array.from({length: 100}, (_, i) => i + 1);
const output = input.map(fizzBuzzWhizz);

console.log(output);

这段代码实现了题目要求的功能,并通过优先级从高到低的规则进行转换。代码简洁,易于理解,同时遵循了题目中的建议。

回到顶部