四道有意思的考题

前言

今天总结一下前几天所学到的个四个考题,快来看看你能不能全部答对吧!

字符串相加

有人会说数字求和不是很简单吗,加法谁不会算呢?

虽然说加法算数确实不能,但是如果数字是一个非常非常大,简单的加法就无法得到正确的结果了。我们需要采用特殊的方法计算正确的结果。

当数字非常大的时候,如果使用普通的加法,是无法得到正确结果的,超出了计算范围。所以,这时候就需要我们把数字转成字符串,然后从末尾进行相加。这种题目是高精度的板子题也不算太难,只需要把加法过程用代码表示出来,就能解出来。

js 复制代码
/**
 * @param {string} num1
 * @param {string} num2
 * @return {string}
 */
var addStrings = function(num1, num2) {
    let i=num1.length-1  //从后往前加
    let j=num2.length-1
    let carry=0
    let res=[]
    while(i>=0||j>=0||carry!==0){
        let dig1=i>=0?num1.charAt(i)-'0':0
        let dig2=j>=0?num2.charAt(j)-'0':0
        let sum=dig1+dig2+carry
        res.push(sum%10)
        carry=Math.floor(sum/10)
        i--
        j--
    }
    return res.reverse().join('')
};

0.1 + 0.2===0.3

这个问题也是非常常见,也非常简单的,结果是false。为什么会不相等呢?在我们的日常生活里,0.1+0.2计算得到0.3是非常简单且不用思考的。但是,计算机的计算方式和我们正常的计算方式是有差异的。

首先,JS要把0.1 和 0.2转换成对应的二进制。

0.1: 0 01111111011 1001100110011001100110011001100110011001100110011010 0.2:0 01111111100 1001100110011001100110011001100110011001100110011010

然后把两个进行相加,得到结果再转换成十进制,0.3000000000000004。显然和0.3不相等,最终返回false

0 01111111101 0011001100110011001100110011001100110011001100111010

想必这样解释应该是非常易懂了。要是问起来为什么不等于0.3,我们只需要回答计算机采用了IEEE754编码存储浮点数,无法精确表示十进制的数字。那么,如何实现0.1+0.2==0.3呢?

在数学里,判断两个数字是否相等,我们可以采用让二者进行相减,得到的结果和一个极小的数字进行比较。要是比极小的数字还小,那么就可以认为两个数字相等。而Number里面有个Number.EPSILON表示非常小的数。

js 复制代码
function isSame(num1,num2){
    return (num1-num2)<Number.EPSILON
}

红包算法

抢红包是一件非常常见的事情,请你设计一个红包算法。

这个抢红包算法,看似非常简单,只需要生成随机数就行。但是,还是有很多细节需要考虑的。

看着如此多的要求,设计一个好的红包算法还是有点难度的。

首先,需要有个红包数组来存储,红包数组的长度为红包总个数。

我们生成随机数,只需要生成n-1个。最后一个红包的金额就是最终剩下的金额。我们还需确保生成的随机数至少是0.01,总可不能出现一个空红包吧?

其次,我们要让这个算法生成的随机数组不能太平均,也不能差异太大。 最后把生成的随机数组返回即可。

ini 复制代码
function redPackets(total, num) {
    const res = [];
    let restAmount = total;
    let restNum = num;
    for (let i = 0; i < num - 1; i++) {
        // 每个红包的最小金额为 0.01
        let max = (restAmount / restNum) * 2;
        let amount = Math.random() * max;
        amount = Math.floor(amount * 100) / 100; // 保留两位小数
        if (amount < 0.01) amount = 0.01;
        restAmount -= amount;
        restAmount = Math.floor(restAmount * 100) / 100;
        restNum--;
        res.push(amount);
    }
    // 最后一个红包为剩余金额,保留两位小数
    res.push(Math.floor(restAmount * 100) / 100);
    return res;
}

for (let i = 0; i < 10; i++) {
    console.log([...redPackets(100, 10)]);
}

奇怪的输出

"1","2","3"\].map(parseInt) 的输出结果是什么?

看到这题,我们很容易误认为输出的结果会是1,2,3。要是回答了这个结果,面试官可能就让你回家等通知了。

实际上这个结果是[1,NAN,NAN],是不是和你想的完全不一样。那么为什么会出现这个结果呢?

就让我们再看仔细看Map函数和parseInt函数吧。
Map函数 :在绝大多数情况下,我们用map都只用它的第一个参数,即当前遍历的元素。而map还有第二个参数(当前的下标),第三个参数(数组本身)。
parseInt函数:parseInt(string,radix)函数有两个参数,第一个参数是传入的字符串,而第二个参数就是用来描述传入字符串是几进制。如果没有传入第二个参数,那么它会根据以下规则自动判断string是几进制。

  • 如果字符串string以'0x'开头,parseInt()会把string的其余部分解析为十六进制的整数
  • 如果string以0开头,那么ECMAScipt v3允许parseInt()的一个实现把其后的字符串解析为八进制或十六进制的数字。
  • 如果string以1~9的数字开头,parseInt()将把它解析为十进制的数字。

根据以上规则,我们来分析这个遍历过程: 第一次循环:

javascript 复制代码
parseInt('1',0) //参数:'1',进制默认为十进制,返回结果1

第二次循环:

javascript 复制代码
parseInt('2',1) //参数:'2',进制为一进制,由于没有一进制,所以返回NAN

第三次循环:

javascript 复制代码
parseInt('3',2) //参数:'3',进制为二进制,3无法用二进制表达,返回NAN

因此最终返回[1,NAN,NAN]

Ending

看完这四道题目,是不是觉得有点意思呢?以上就是本人对前几天学习的部分总结了,感谢阅读。

相关推荐
用户251916242711几秒前
Node之EventEmitter
前端·javascript·node.js
鹏多多8 分钟前
flutter-详解控制组件显示的两种方式Offstage与Visibility
前端·flutter
用户7236237370588 分钟前
农业银行转账模拟器, 银行卡余额模拟器,jar最新逆向插件开源
前端
小岛前端11 分钟前
sass-embedded:高性能版的 Sass
前端·vue.js
甜瓜看代码17 分钟前
面试题---安卓
面试
天蓝色的鱼鱼22 分钟前
Vue Router 动态路由完全指南:灵活掌控前端路由
前端·vue.js
道可到23 分钟前
Java 面试通关笔记 01|拆箱与装箱:你真的理解了吗?
后端·面试
β添砖java30 分钟前
CSS定位布局
前端·css·html
whysqwhw36 分钟前
整个 KMP 的日期时间工具
前端
聪明的笨猪猪1 小时前
Java SE “概念与优势”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试