freecodecamp高级算法题(个人解法)

2017-05-02  本文已影响0人  李嫑嫑_fe48

Validate US Telephone Numbers

检查是否是美国电话号码。其中有很多变体写法,也要求返回正确。

functiontelephoneCheck(str){vara = str.match(/[0-9]/g).length;varb = str.match(/^(?:(?:\(\d{3}\)|\d{3})[\s|-]?\d{3}[\s|-]?\d{4}$)/);varc = str.match(/(?:\(\d{3}\)|\d{3})[\s|-]?\d{3}[\s|-]?\d{4}$/);vard = str.match(/^1[^0-9]/);if(a ===10&& b !==null) {returntrue;    }elseif(a ===11&& c !==null&& d !==null) {returntrue;    }returnfalse;}telephoneCheck("2 757 622-7382");

本来尝试使用一个正则直接得出结果,很可惜受限于水平原因,最后放弃了尝试。

最后的代码里面,通过a检查传入字符串中有多少个数字,在后面的if条件判断中,分两种情况(是否带有国家代码)来判断。

值b用来匹配不带国家代码的电话号码,前面的部分较后面来说比较复杂。需要匹配三个数字及三个数字加括号这两种情况,但一边单括号应当不能通过验证。(?:(\d{3})|\d{3})这里,使用(?:)非捕获括号,里面用 | 做了一个条件判断,从而达到匹配三个数字或三个数字加括号这两种情况。前面的^用来防止匹配到带国家代码的电话(如果把b匹配放入if内,可以去掉这个^,因为已经通过a的数值判断了是否带国家代码)。

值c和值b没什么区别。

值d用来匹配国家代码开头部分(应该可以和c合并,当时只为通关也就没改了)。

Symmetric Difference

接受两个或者多个数组。如果是两个数组,互相判定差集,把结果作为一个集合输出。如果是多个数组,用上一次的结果作为其中一个数组,和下一个做相同的操作(就是reduce啦)。

functionsym1(a, b){varc = [];for(variina) {if(b.indexOf(a[i]) ===-1) {            c.push(a[i]);        }    }for(varyinb) {if(a.indexOf(b[y]) ===-1) {            c.push(b[y]);        }    }returnc;}functionsym(args){vard = [];for(variinarguments) {        d.push(arguments[i]);    }vare = d.reduce(sym1);varf = [e[0]];for(vari =1; i < e.length; i++) {if(e[i] !== e[i -1]) {            f.push(e[i]);        }    }returnf;}sym([1,2,3], [5,2,1,4]);

先写了一个reduce用的函数smy1。用indexOf判断元素是否在集合中,如果不存在就放入准备好的结果容器c中。

接下来在主函数中用for循环arguments取出输入的所有数组,再使用reduce依次对等差分。注意这时如果输入的数组中有多个重复的值,而这个值满足差分的要求,结果的数组中也会出现很多个相同的值。但是网站左侧给出的例子要求我们不能出现重复,因此用一个for循环进行去重。

Exact Change

写一个收银程序。

function checkCashRegister(price, cash, cid) {    var change;    var a =0;    var b = [];    var e = cash - price;    var d = [0.01,0.05,0.10,0.25,1,5,10,20,100];    for (var i in cid) {        a += cid[i][1];    }    if ((cash - price) > a) {        return 'Insufficient Funds';    } else if ((cash - price) === a) {        return 'Closed';    }    for (var i = d.length -1; i >=0; i--) {        if (i ===0&& e <= cid[i][1]) {            b.push([cid[i][0], Math.round(e *100) /100]);            e =0;        } else if (e >= d[i] && e <= cid[i][1] && cid[i][1] >0) {            b.push([cid[i][0], Math.floor(e / d[i]) * d[i]]);            e = e - Math.floor(e / d[i]) * d[i];        } else if (e >= d[i] && e >= cid[i][1] && cid[i][1] >0) {            b.push(cid[i]);            e = e - cid[i][1];        }        if (e ===0) {            break;        }    }    if (e !==0) {        return 'Insufficient Funds';    }    return b;}sym([1,2,3], [5,2,1,4]);

第一个for循环不用看,出现的原因只是代码通过了就没改。

第二个for循环是核心代码。我的思路是用for循环对大面额到小面额依次进行判断。每次会操作两个变量,一个是结果容器b(push进一个列表,包含面额,和剩余金额),一个是e(初始量是待找金额,每次循环如果面额和余额满足要求,从e中扣除一定的钱)。如果循环中出现e=0的情况,用break语句跳出,因为此时找零已经完成。如果直到循环结束,e仍有剩余,说明钱找不开。

感觉代码还是乱,有修改的余地。

Inventory Update

依照一个存着新进货物的二维数组,更新存着现有库存(在 arr1 中)的二维数组. 如果货物已存在则更新数量 . 如果没有对应货物则把其加入到数组中,更新最新的数量. 返回当前的库存数组,且按货物名称的字母顺序排列。

functionupdateInventory(arr1, arr2){vara = [];for(variinarr1) {        a.push(arr1[i][1]);    }for(variinarr2) {if(a.indexOf(arr2[i][1]) !==-1) {            arr1[a.indexOf(arr2[i][1])][0] += arr2[i][0];        }else{            arr1.push(arr2[i]);        }    }    arr1 = arr1.sort(function(a, b){returna[1].charCodeAt(0) - b[1].charCodeAt(0);    });returnarr1;}

用for循环遍历进货,用indexOf判断进货中货物名称是否已经在库存中存在,如果存在就更新货物数量,不存在则直接把这个数组加入库存。

按货物名称排序我直接用在sort内写了一个匿名函数,通过比较字母的ASCII大小排序。

No repeats please

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

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

function perms(str) {    var result = [];    var n =0;    var m =str.length;    var perm = function(str, n, m) {if(n === m -1) {            result.push(str.join(''));        }else{for(var i = n; i < m; i++) {str[i] = [str[n],str[n] =str[i]][0];                perm(str, n +1, m);str[i] = [str[n],str[n] =str[i]][0];            }        }    };    perm(str, n, m);returnresult;}function permAlone(str) {    var regex = /(.)\1+/g;str=str.split('');    var b = perms(str);    varfilter= b.filter(function(a) {return! a.match(regex);    });returnfilter.length;}

一开始当成一个数学题来做,想了很久,发现其中要判断的情况太多,写出代码要很多条件判断。最后还是用全排列做了。

我的全排列函数perms是用递归做的。思路是,有一个可用字符集合,取出其中一个,放在首位,接着更新这个字符集(集合中去除这个放在首位的字符),接着在新字符集中取出其中一个……不断循环直至其中只有一个字符。在写代码的时候变了一下实现方式,变成首字符和它后面的每一个字符依次交换,第二个字符和它后面的每一个字符依次交换,直至递归出口(倒数第二个字符)。

注意里面的匿名函数里的闭包情况(递归中每一次重新调用自身,并没有创建一个新的变量,它们都在操作同一个str,n,m。所以交换完了要再把str还原。递归出口是把此时的str组装成一个字符串。这个操作不仅有输出格式上的考量,还有一个原因是,既然操作的都是同一个str,那么push进数组的当然也是同一个str,虽然它们身处数组,但一直在随着函数里的str的变化而变化。所以我们需要把每次递归出口的str顺序固定下来,组装字符串相当于创建了一个新的字符串对象,从而达到固定顺序的作用)。

Friendly Date Ranges

functionmakeDates(str){vararr = [];    str = str.split(/[^\d*]/);for(vari in str) {        arr.push(parseInt(str[i],10));    }returnarr;}functionmakeFriendlyDates(arr){varmonth = ['','January','February','March','April','May','June','July','August','September','October','November','December'];vardays = [];vararray= [];for(varz =0; z <31; z++) {if(z >=10&& z <=20) {            days.push('th');        }else{if(z %10===1) {                days.push('st');            }elseif(z %10===2) {                days.push('nd');            }elseif(z %10===3) {                days.push('rd');            }else{                days.push('th');            }        }    }for(vari in arr) {array.push(makeDates(arr[i]));    }vara =array[1][0] -array[0][0];varb =array[1][1] -array[0][1];varc =array[1][2] -array[0][2];for(vary inarray) {array[y][0] = [array[y][2],array[y][2] =array[y][0]][0];array[y][0] = [array[y][1],array[y][1] =array[y][0]][0];        replace(array[y]);    }functionreplace(array){array[0] = month[array[0]];array[1] = String(array[1]) + days[array[1]];array[2] = String(array[2]);if(array.length ===3) {array[1] =array[1] +',';        }    }if(a *360+ b *30+ c >=360) {}elseif(a *360+ b *30+ c >30&&array[0][2] ==='2016') {array[1] =array[1].splice(0,2);array[0] =array[0].splice(0,2);    }elseif(a *360+ b *30+ c >30) {array[1] =array[1].splice(0,2);array[0] =array[0].splice(0,3);    }elseif(a *360+ b *30+ c >0) {array[1] = [array[1][1]];array[0] =array[0].splice(0,2);    }elseif(a ===0&& b ===0&& c ===0) {array= [array[0]];    }returnarray.map(function(a){returna.join(' ').replace(/,$/,'');    });}

把一大堆条件判断从人类语言转换成代码。。。。。。。这就是我写这题的感觉,也许出题人的初衷不是这个?

Make a Person

varPerson =function(name){vara = [name.split(' ')[0], name.split(' ')[1]];this.getFirstName =function(){returna[0];    };this.getLastName =function(){returna[1];    };this.getFullName =function(){returna[0] +' '+ a[1];    };this.setFirstName =function(b){        a[0] = b;    };this.setLastName =function(b){        a[1] = b;    };this.setFullName =function(b){        a[0] = b.split(' ')[0];        a[1] = b.split(' ')[1];    };};varbob =newPerson('Bob Ross');bob.getFirstName();

匿名函数function(name)在类建立时就被调用,它用来建立一个类空间,其中的内容即是建立的类的内容。变量a用一个数组来储存和修改Firstname及Lastname(把function(name)传递进类空间的name给spilt成两块),给属性赋予匿名函数,通过闭包操作变量a。这六个函数大同小异,精简成一个的话,会非常简洁,同时可以清晰地看到两个要点。第一是通过函数建立类,第二是闭包的使用。

Map the Debris

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

functionorbitalPeriod(arr){varGM =398600.4418;varearthRadius =6367.4447;functionchange(avgAlt){varr = earthRadius + avgAlt;varb =Math.pow(r,3) / GM;varT =2*Math.PI *Math.pow(b,0.5);returnMath.round(T);    }varresult = [];for(variinarr) {vara = change(arr[i].avgAlt);vardict = {};        dict.name = arr[i].name;        dict.orbitalPeriod = a;        result.push(dict);    }returnresult;}

用代码把数学公式算一下。外加一点点数据的取出。不太清楚为什么要放在高级算法里。

Pairwise

举个例子:有一个能力数组[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) {varcount=0;varred=[];for(vari=0;i

题目下面的提示是reduce,我的思路里面没有用到,自己尝试用reduce想了一下,感觉有点阻力。

我的思路,遍历每个值,每次遍历中再对目前值之后的值进行一次遍历。目的是每个值和它之后所有的值匹配,如果它们的和等于目标值,则把下标累加到变量count上。题目中还有一个值得注意的点,就是当两个值匹配后,它们便不会和其他值匹配了。这里我通过一个变量red,作为一个池子,来储存已经匹配过的变量的下标。再循环中先进行条件判断,若取出的值不在池中才进行下一步匹配(使用continue来实现,continue:跳过次循环直接执行下一次循环,也可以使用一个if,判断条件里用&&把“求和是否满足要求”及“下标是否在池中”连起来)。

上一篇下一篇

猜你喜欢

热点阅读