美文网首页
Freecodecamp 刷题记录——前端高级算法

Freecodecamp 刷题记录——前端高级算法

作者: 篮筐轰炸机5号 | 来源:发表于2019-03-26 21:55 被阅读0次

    Validate US Telephone Numbers
    如果传入字符串是一个有效的美国电话号码,则返回 true.

    用户可以在表单中填入一个任意有效美国电话号码. 下面是一些有效号码的例子(还有下面测试时用到的一些变体写法):

    555-555-5555
    (555)555-5555
    (555) 555-5555
    555 555 5555
    5555555555
    1 555 555 5555
    在本节中你会看见如 800-692-7753 or 8oo-six427676;laskdjf这样的字符串. 你的任务就是验证前面给出的字符串是否是有效的美国电话号码. 区号是必须有的. 如果字符串中给出了国家代码, 你必须验证其是 1. 如果号码有效就返回 true ; 否则返回 false.

    function telephoneCheck(str) {
      // 祝你好运
        var reg = new RegExp(/^(1\s?)?((\(\d{3}\))|\d{3})[\s-]?\d{3}[\s-]?\d{4}$/);
        if (str.search(reg)>=0){
            return true;
        }
    
        return false;
    }
    
    str = telephoneCheck("1(555)555-5555");
    
    console.log(str);
    

    Symmetric Difference

    创建一个函数,接受两个或多个数组,返回所给数组的 对等差分(symmetric difference) (△ or ⊕)数组.

    给出两个集合 (如集合 A = {1, 2, 3} 和集合 B = {2, 3, 4}), 而数学术语 "对等差分" 的集合就是指由所有只在两个集合其中之一的元素组成的集合(A △ B = C = {1, 4}). 对于传入的额外集合 (如 D = {2, 3}), 你应该安装前面原则求前两个集合的结果与新集合的对等差分集合 (C △ D = {1, 4} △ {2, 3} = {1, 2, 3, 4}).

    function sym() {
        if (arguments.length === 2){
            var arr1 = arguments[0];
            var arr2 = arguments[1];
    
            var tempArr = [];
            return arr1.filter(function(item){
                if (Array.from(arr2).indexOf(item) >= 0){
                    return false;
                }
                return true;
            }).concat(arr2.filter(function(item){
                if (Array.from(arr1).indexOf(item) >= 0){
                    return false;
                }
                return true;
            })).filter(function(item){ //去重
                if (tempArr.indexOf(item) >= 0){
                    return false;
                }
                else {
                    tempArr.push(item);
                    return true;
                }
            });
    
        }
        else if(arguments.length > 2){
            var newArgs = [];
            var oldArgs = arguments;
            newArgs.push(sym(arguments[0], arguments[1]));
            for (var i=2; i<oldArgs.length; i++){
                newArgs.push(oldArgs[i]);
            }
            return sym.apply(this, newArgs);  //将数组作为参数传递,需要用apply,而不能直接apply(newArgs),因为参数并不是数组
        }
    }
    
    str = sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3]);
    
    console.log(str);
    
    

    tip1:sym.apply(this, newArgs); //将数组作为参数传递,需要用apply,而不能直接apply(newArgs),因为参数并不是数组;

    tip2:注意需要对数组去重。

    Exact Change
    设计一个收银程序 checkCashRegister() ,其把购买价格(price)作为第一个参数 , 付款金额 (cash)作为第二个参数, 和收银机中零钱 (cid) 作为第三个参数.

    cid 是一个二维数组,存着当前可用的找零.

    当收银机中的钱不够找零时返回字符串 "Insufficient Funds". 如果正好则返回字符串 "Closed".

    否则, 返回应找回的零钱列表,且由大到小存在二维数组中.

    function checkCashRegister(price, cash, cid) {
        var change = [];
        //都换成整数,防止浮点数陷阱。
        var VALUE = [1, 5, 10, 50, 100, 500, 1000, 2000, 10000];
        var money = (cash - price) * 100;
        cid = cid.map(function(item){
            item[1] *= 100;
            return item;
        });
    
        var i = 8;
        while (money > 0){
            if (i<0){
                return "Insufficient Funds";
            }
    
            var sum = 0;
            while (money>=VALUE[i] && cid[i][1]>0){
                money -= VALUE[i];
                cid[i][1] -= VALUE[i];
                sum += VALUE[i];
            }
    
            if (sum>0){
                //直接temp=cid的话,修改temp会影响cid的值,影响后面零钱是否用光的判断
                var temp = cid.slice(); // this is how to make a copy 
                temp[1] = sum / 100;
                change.push(temp);
            }
    
            i--;
        }
    
        //零钱是否用光
        for (i=0; i<9; i++){
            if (cid[i][1]>0){
                return change;
            }
        }
    
        return "Closed";
    }
    
    str = checkCashRegister(19.50, 20.00, [["PENNY", 0.50], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]); 
    console.log(str);
    
    

    tips1:数组是指针!赋值给其它数组后,是把指针传递了过去,新数组改变会影响原数组!!!

                console.log('before:' + cid[i]);
                var temp = cid;
                temp[i][1] = sum / 100;
                console.log('after:' + cid[i]);
    

    打印结果:

    before:PENNY,0
    freecodecamp.js:28 after:PENNY,0.5
    

    参考:javascript中把一个数组的内容全部赋值给另外一个数组 - ..._博客园

    Inventory Update

    function updateInventory(arr1, arr2) {
        for (var j=0; j<arr2.length; j++){
    
            var i = 0;
            //在有序表中寻找位置
            while (i<arr1.length && arr2[j][1]>arr1[i][1]){
                i++;
            }
            console.log(i);
            if (i===arr1.length){
                arr1.push(arr2[j]);
            }
            else{
                //如果存在
                if (arr1[i][1] === arr2[j][1]){
                    arr1[i][0] += arr2[j][0];
                }
                //如果未存在
                else{
                    var tempArr = arr1.slice(0, i);
                    tempArr.push(arr2[j]);
                    arr1 = tempArr.concat(arr1.slice(i));
                }
    
            }
    
        }
        return arr1;
    }
    
    var curInv = [
        [21, "Bowling Ball"],
        [2, "Dirty Sock"],
        [1, "Hair Pin"],
        [5, "Microphone"]
    ];
    var newInv = [
        [2, "Hair Pin"],
        [3, "Half-Eaten Apple"],
        [67, "Bowling Ball"],
        [7, "Toothpaste"]
    ];
    
    str = updateInventory(curInv, newInv);
    
    console.log(str);
    
    
    

    tips1:
    原先写的如下代码:

    for (var j=0; j<arr2.length; j++){
    
            var i = 0;
            //在有序表中寻找位置
            while (arr2[j][1][0] > arr1[i][1][0]){
                i++;
            }
            ……
    }
    

    报错:
    freecodecamp.js:6 Uncaught TypeError: Cannot read property '1' of undefined

    一开始以为是不能把arr2视为多维数组,对其直接取下标。而结果是,直接把参数视为多维数组没毛病,错误是没限制i的范围,我越界了!!!

    tips2:
    字符串可以直接比较大小,会根据第一个不同的字符的ascii值码进行比较,当数字(number)与字符串(string)进行比较大小时,会强制的将数字(number)转换成字符串(string)然后再进行比较。
    例如:

    console.log('13'>'3'); // 输出:false,因为第一位'1'<'3'
    

    No repeats please

    把一个字符串中的字符重新排列生成新的字符串,返回新生成的字符串里没有连续重复字符的字符串个数.连续重复只以单个字符为准

    例如, aab 应该返回 2 因为它总共有6中排列 (aab, aab, aba, aba, baa, baa), 但是只有两个 (aba and aba)没有连续重复的字符 (在本例中是 a).

    function swap(array, i, j){
        if (i!=j){
            var temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
    }
    
    
    function permAlone(str){
        var count = 0;
    
        function allSort(array, start, end) {
            if (start < end - 1){
                for (var i=start; i<end; i++){
                    swap(array, start, i);
                    allSort(array, start+1, end);
                    swap(array, start, i);
                }
            }
            //得到一种全排列
            else{
                //判断是否有连续重复字符
                //如果有,返回,不计数。
                for (var j=0; j < array.length - 1; j++){
                    if (array[j]===array[j+1]){
                        break;
                    }
                }
                if (array[j]!==array[j+1]){
                    count++;
                    console.log(array);
                }
            }
            return count;
        }
    
        //使用闭包,以便使allSort函数能直接修改count的值;
        //将字符串转换为数组,否则string类型是无法修改的,函数只能传递形参,
        //而数组作为对象则传递的是地址。
        allSort(str.split(''), 0, str.length);
    
        return count;
    }
    
    console.log(permAlone('aab'));
    

    感觉是前端算法中最难的一道题了,用到递归的思路。

    Friendly Date Ranges
    让日期区间更友好!

    把常见的日期格式如:YYYY-MM-DD 转换成一种更易读的格式。

    易读格式应该是用月份名称代替月份数字,用序数词代替数字来表示天 (1st 代替 1).

    记住不要显示那些可以被推测出来的信息: 如果一个日期区间里结束日期与开始日期相差小于一年,则结束日期就不用写年份了;在这种情况下,如果月份开始和结束日期如果在同一个月,则结束日期月份也不用写了。

    另外, 如果开始日期年份是当前年份,且结束日期与开始日期小于一年,则开始日期的年份也不用写。

    例如:

    包含当前年份和相同月份的时候,makeFriendlyDates(["2017-01-02", "2017-01-05"]) 应该返回 ["January 2nd","5th"]

    不包含当前年份,makeFriendlyDates(["2003-08-15", "2009-09-21"]) 应该返回 ["August 15th, 2003", "September 21st, 2009"]。

    请考虑清楚所有可能出现的情况,包括传入的日期区间是否合理。对于不合理的日期区间,直接返回 undefined 即可

    function dayAppendix(day){
        var str;
        switch (day){
        case 1: 
        case 21:
        case 31: str = "st";break;
        case 2:
        case 22: str = "nd";break;
        case 3:
        case 23: str = "rd";break;
        default: str = "th";
        }
        return str; 
    }
    
    function makeFriendlyDates(arr) {
        var d1 = arr[0].split('-').map(function(item){
            return parseInt(item);
        });
        var d2 = arr[1].split('-').map(function(item){
            return parseInt(item);
        });
    
        if ((d1[0]>d2[0]) || 
            (d1[0]===d2[0] && d1[1]>d2[1]) || 
            (d1[0]===d2[0] && d1[1]===d2[1] && d1[2]>d2[2])){
            return undefined;
        }
    
        var Month = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
        var retArr = [];
    
        var str1 = Month[d1[1]-1] + " " + d1[2];
        var str2 = "";
    
        str1 += dayAppendix(d1[2]);
    
        var withinAYear = false;
    
        var deltaY = d2[0] - d1[0];
        var deltaM = d2[1] - d1[1];
        var deltaD = d2[2] - d1[2];
    
        if ((deltaY===0)||
            (deltaY===1 && deltaM<0)||
            (deltaY===1 && deltaM===0 && deltaD<0)){
            withinAYear = true;
        }
    
        var curYear = 2017;
        if (d1[0]!==curYear || !withinAYear){
            str1 = str1 + ', ' + d1[0];
        }
        retArr.push(str1);
    
        if (deltaY===0 && deltaM===0 && deltaD===0){
            return retArr;
        }
    
        if (d1[0]!==d2[0] || d1[1]!==d2[1] || !withinAYear){
            str2 += Month[d2[1]-1] + ' ';
        }
        str2 += d2[2];
    
        str2 += dayAppendix(d2[2]);
    
    
        if (!withinAYear){
            str2 = str2 + ', ' + d2[0];
        }
    
        retArr.push(str2);
    
        return retArr;
    
    }
    
    
    str =makeFriendlyDates(["2010-10-23", "2011-10-22"]);
    
    
    console.log(str);
    

    tips1:英文日期简写是根据词尾判别的,即个位是1就是st,个位是2就是nd,个位是3就是rd,其他个位就是th,但11,12,13是例外,都用th。(根据读音,eleven总不能加st吧)
    tips2:将多个条件写下来,验算逻辑,比较容易捋清楚。
    tips3:“开始和结束日期如果在同一个月”指的是同一年&&同一月。

    Make a Person

    基于原型的语言(如 JavaScript)并不存在这种区别:它只有对象。基于原型的语言具有所谓原型对象的概念。原型对象可以作为一个模板,新对象可以从中获得原始的属性。任何对象都可以指定其自身的属性,既可以是创建时也可以在运行时创建。而且,任何对象都可以作为另一个对象的原型,从而允许后者共享前者的属性。

    JavaScript构造函数及原型对象 - 王浴昊 - CSDN博客

    var Person = function(firstAndLast) {
        var arr = firstAndLast.split(' ');
        var firstName = arr[0];
        var lastName = arr[1];
    
        this.getFirstName = function(){
            return firstName;
        };
        this.getLastName = function(){
            return lastName;
        };
        this.getFullName = function(){
            return firstName + ' ' + lastName;
        };
        this.setFirstName = function(first){
            firstName = first;
        };
        this.setLastName = function(last){
            lastName = last;
        };
        this.setFullName = function(fullName){
            firstAndLast = fullName;
            var tempArr = fullName.split(' ');
            firstName = tempArr[0];
            lastName = tempArr[1];
        };
    };
    
    var bob = new Person('Bob Ross');
    console.log(bob);
    

    Map the Debris
    返回一个数组,其内容是把原数组中对应元素的平均海拔转换成其对应的轨道周期.

    原数组中会包含格式化的对象内容,像这样 {name: 'name', avgAlt: avgAlt}.

    至于轨道周期怎么求,戳这里 on wikipedia (不想看英文的话可以自行搜索以轨道高度计算轨道周期的公式).

    求得的值应该是一个与其最接近的整数,轨道是以地球为基准的.

    地球半径是 6367.4447 kilometers, 地球的GM值是 398600.4418, 圆周率为Math.PI

    function orbitalPeriod(arr) {
        var GM = 398600.4418;
        var earthRadius = 6367.4447;
        return arr.map(function(obj){
            var R = (obj.avgAlt + earthRadius);
    
            var retObj = {};
            retObj.name = obj.name;
            retObj.orbitalPeriod = Math.round(2 * Math.PI * R * Math.pow(R/GM, 0.5));
    
            return retObj;
        });
    }
    
    str = orbitalPeriod([{name : "sputnik", avgAlt : 35873.5553}]);
    
    console.log(str);
    

    Pairwise
    找到你的另一半

    都说优秀的程序员擅长面向对象编程,但却经常找不到另一半,这是为什么呢?因为你总是把自己局限成为一个程序员,没有打开自己的思维。

    这是一个社群的时代啊,在这里你应该找到与你有相同价值观但又互补的另一半。

    譬如:你编程能力强,估值11分,如果以20分为最佳情侣来计算,你应该找一个设计能力强,估值为9分的女生。

    那么当你遇到一个设计能力为9分的女生,千万别犹豫,大胆去表白。千万别以为后面的瓜比前面的甜哦。

    举个例子:有一个能力数组[7,9,11,13,15],按照最佳组合值为20来计算,只有7+13和9+11两种组合。而7在数组的索引为0,13在数组的索引为3,9在数组的索引为1,11在数组的索引为2。

    所以我们说函数:pairwise([7,9,11,13,15],20) 的返回值应该是0+3+1+2的和,即6。

    function pairwise(arr, arg) {
        var flag = [];
        var sum = 0;
    
        for (var i=0; i<arr.length; i++){
            if (flag[i]){
                continue;
            }
            for (var j=i+1; j<arr.length; j++){
                if (flag[j]){
                    continue;
                }
                if ((arr[i]+arr[j])===arg){
                    flag[i] = true;
                    flag[j] = true;
                    sum += i;
                    sum += j;
                    break;
                }
            }
        }
    
        return sum;
    }
    
    pairwise([1,4,2,3,0,5], 7);
    

    相关文章

      网友评论

          本文标题:Freecodecamp 刷题记录——前端高级算法

          本文链接:https://www.haomeiwen.com/subject/qpenqqtx.html