最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 《JS玩算法系列》海王的鱼塘

    正文概述 掘金(南极大冰块)   2021-01-07   527

    写在前面

    不知为什么,感觉2020年面试过程中算法题突然流行了起来,不论你是前端后端还是架构师,面试前都得先来两道算法题热热身。

    如果你很干脆的回答不会,hr小姐姐就会吃惊地问你:什么?身为一个前端程序员竟然不会算法??? 语气口吻就好比你的亲戚问你:不会吧不会吧!身为一个程序员不会修电脑??? 让你心跳加速脸红娇喘羞愧难当...

    为了避免这种尴尬的情况出现,今天趁着*领导不在*阳光正好,我们一起来摸一条某大厂中等算法题的大鱼试试看,想看《海王的鱼塘》可以直接跳到尾部挑战一下,不过大冰块建议先从《聪明的销售》看起~


    《聪明的销售》

    样例:

    输入:
    [1,1,1,2,2,3]
    2
    输出:
    2
    

    实不相瞒,我看了三遍题目,终于看明白了出题人的意思,不就是数组中删掉n个元素,要求剩余的元素中,相同的元素越多越好嘛!

    看明白了题目意思,就已经成功了一半。

    既然已经成功了一半,那么趁热打铁,理一下思路吧!

    如果想要删掉n个元素,剩余的元素中,相同的元素越多越好,那么:删掉的元素出现的次数肯定是越少越好。

    所以这道题其实是求出每个元素出现的次数,只要求出每个元素出现的次数,答案就近在咫尺唾手可得呼之欲出了(大冰块的语文是不是比出题人要好?)。

    就这???我微微一下,劈里啪啦敲出如下demo:

    let arr = ['苹果','苹果','苹果','香蕉','香蕉','橘子','橘子','橘子','草莓','火龙果','火龙果']
    let obj = {}
    arr.forEach( item => obj.hasOwnProperty(item) ? obj[item]+=1 : obj[item] = 1 )
    console.log(obj)  // 控制台输出:{苹果: 3, 香蕉: 2, 橘子: 3, 草莓: 1, 火龙果: 2}
    

    如果要删掉5个,就从数量最少的水果删,删够5个即可,我一眼就看出来草莓1+火龙果2+香蕉2刚好等于5,删掉它们即可。

    可是程序并不知道,所以我们应该先根据水果数量对obj进行排序,才能顺利的从少到多依次删除对应水果。

    可是object对象真的能排序吗?我知道js里的object对象存在自动排序机制,但是我没有对object对象做过排序,所以本文暂时不做讨论object对象属性排序的问题。保险起见,我们采用人人都会的数组排序方式来解决。

    把代码重构如下:

    let arr = ['苹果','苹果','苹果','香蕉','香蕉','橘子','橘子','橘子','草莓','火龙果','火龙果']
    let resultArr = []
    arr.forEach( item => {
        let obj = {name: item, num: 1}
        let i = resultArr.findIndex(element => element.name == item)
        i !== -1 ? resultArr[i].num+=1 : resultArr.push(obj)
    })
    resultArr.sort((a,b)=>a.num-b.num);
    console.log(resultArr) 
    // 控制台输出:[{name: "草莓", num: 1},{name: "香蕉", num: 2},{name: "火龙果", num: 2},{name: "苹果", num: 3},{name: "橘子", num: 3}]
    Object.keys(obj).length
    

    排序完成,那么从num最小的元素开始删除吧!

    如果需要删除5个,则声明一个变量sum赋值为0,从第一个元素开始,把元素的num累加给sum,这样对比 sum是否大于5即可,如果大于5则不能删除,直接结束。如果小于5,则累加下一个元素的num,直到大于5。

    代码重构如下

    let arr = ['苹果','苹果','苹果','香蕉','香蕉','橘子','橘子','橘子','草莓','火龙果','火龙果']
    let resultArr = []
    arr.forEach( item => {
        let obj = {name: item, num: 1}
        let i = resultArr.findIndex(element => element.name == item)
        i !== -1 ? resultArr[i].num+=1 : resultArr.push(obj)
    })
    resultArr.sort((a,b)=>a.num-b.num);
    let sum = 0
    resultArr.map((item,index)=>{
        sum += item.num
        sum > 5 ? '' : delete resultArr[index]
    })
    console.log(resultArr) 
    // 控制台输出:[empty × 3,{name: "苹果", num: 3},{name: "橘子", num: 3}]
    

    虽然map()方法看起来代码精简了不少,但是从如上代码运行角度来说,map()不能终止,在多个元素的情况下效率并没有for循环高,所以我们把代码优化如下:

    let arr = ['苹果','苹果','苹果','香蕉','香蕉','橘子','橘子','橘子','草莓','火龙果','火龙果']
    let resultArr = []
    arr.forEach( item => {
        let obj = {name: item, num: 1}
        let i = resultArr.findIndex(element => element.name == item)
        i !== -1 ? resultArr[i].num+=1 : resultArr.push(obj)
    })
    resultArr.sort((a,b)=>a.num-b.num);
    let sum = 0
    for (let index = 0; index < resultArr.length; index++) {
        sum += resultArr[index].num
        // 三元运算符中不能使用return和break,因为三元运算符中要写表达式。所以暂时写if判断吧~
        if(sum > 5){ 
            break
        }else{
            resultArr.splice(index,1)
            index-- // splice()删除元素后,会改变原数组length,所以要index--
        }
    }
    console.log(resultArr) 
    // 控制台输出:[{name: "苹果", num: 3},{name: "橘子", num: 3}]
    		
    

    看起来好像满足了题目的要求,这也没什么难度嘛~下面来封装一下试试看吧:

    const smartSale = (array=[],number=0)=>{
        let resultArr = []
        array.forEach( item => {
            let obj = {name: item, num: 1}
            let i = resultArr.findIndex(element => element.name == item)
            i !== -1 ? resultArr[i].num+=1 : resultArr.push(obj)
        })
        resultArr.sort((a,b)=>a.num-b.num);
        let sum = 0
        for (let index = 0; index < resultArr.length; index++) {
            sum += resultArr[index].num
            if(sum > number){ 
                break  // 三元运算符中不能使用return和break,因为三元运算符中要写表达式。所以暂时写if判断吧~
            }else{
                resultArr.splice(index,1)
                index--  // splice()删除元素后,会改变原数组length,所以要index--
            }
        }
        return resultArr.length
    }
    let arr = ['苹果','苹果','苹果','香蕉','香蕉','橘子','橘子','橘子','草莓','火龙果','火龙果']
    smartSale(arr,3)
    // 控制台输出:3
    

    测试完美运行!那么考虑一下题目下面的限定条件吧:

    即传入的数组length : 1 ≤ array.length ≤ 1000000,传入的number : 1 ≤ number ≤ 100000

    const smartSale = (array=[],number=0)=>{
        if (array.length < 1 || array.length > 1000000) throw new Error("数组的长度范围限制为1-1000000")
        if (number < 1 || number > 100000) throw new Error("要删除的数量范围限制为1-100000")
        let resultArr = []
        array.forEach( item => {
            let obj = {name: item, num: 1}
            let i = resultArr.findIndex(element => element.name == item)
            i !== -1 ? resultArr[i].num+=1 : resultArr.push(obj)
        })
        resultArr.sort((a,b)=>a.num-b.num);
        let sum = 0
        for (let index = 0; index < resultArr.length; index++) {
            sum += resultArr[index].num
            if(sum > number){ 
                break  // 三元运算符中不能使用return和break,因为三元运算符中要写表达式。所以暂时写if判断吧~
            }else{
                resultArr.splice(index,1)
                index--  // splice()删除元素后,会改变原数组length,所以要index--
            }
        }
        return resultArr.length
    }
    

    根据这道算法题的思路,我也编了一道算法题供诸君思考:

    《海王的鱼塘》

    掏出你的大脑袋,开动你的脑筋吧~ 把你的答案码在评论区,供各位海王参考一下~

    写在后面


    起源地下载网 » 《JS玩算法系列》海王的鱼塘

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元