四道有意思的考题

前言

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

字符串相加

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

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

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

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

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

相关推荐
再吃一根胡萝卜4 小时前
08 · 前端:Vue3 + SSE 流式与执行链路可视化
面试
再吃一根胡萝卜4 小时前
03 · 后端:FastAPI 与分层架构
面试
mldong5 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排6 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60616 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角7 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!7 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰8 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
Interview Aid1128 小时前
Walmart Global Tech SDE 三轮面经|基础、并发、压力面
面试·职场和发展
mayaairi9 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js