Freecodecamp 高级算法题

Freecodecamp 高级算法题

1. Validate US Telephone Numbers

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

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

555-555-5555
(555)555-5555
(555) 555-5555
555 555 5555
5555555555
1 555 555 5555

function telephoneCheck(str) {
  //^1?表示以1开头,1匹配0次或1次
  //\(\d{3}\)匹配(一个0-9的数字三次比下面多匹配一个括号,左右括号分别需要加上转义字符\
  // \d{3}匹配一个0-9的数字三次
  //\s?表示空白字符匹配0次或1次
  //[\s\-]?表示空格或者连字符-匹配0次或1次
  //\d{4}$表示已4位数字结尾($)
  var regex = /^(1?\s?)?(\(\d{3}\)|\d{3})[\s\-]?(\d{3})[\s\-]?(\d{4})$/g;
  return regex.test(str);
}

telephoneCheck("1 555 555 5555");

2. 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 getSym(arr1, arr2) {
    // 得到在第一个数组,但不在第二个数组中的元素
    var result = arr1.filter(function(e) {
        return arr2.indexOf(e) === -1;
    });

    // 得到在第二个数组,但不在第以个数组中的元素
    result.concat(arr2.filter(function(e) {
        return arr1.indexOf(e) === -1;
    }))
    
    // 去重
    return result.filter(function(e, i) {
        return result.indexOf(e) === i;
    })
}

方法二:

/*jshint esversion: 6 */
function sym(args) {
 var arr = Array.from(arguments); 
  return arr.reduce((arr1,arr2)=>{
   return arr1.concat(arr2).filter(val=>{
     return arr1.indexOf(val) == -1 || arr2.indexOf(val) ==-1; 
   }).filter((val, index, arr) => {
      return arr.indexOf(val) === index;
    });
  });
}

sym([1, 2, 3], [5, 2, 1, 4]);

2. Exact Change

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

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

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

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

function checkCashRegister(price, cash, cid) {
  var denom = [
  { name: 'ONE HUNDRED', val: 100.00},
  { name: 'TWENTY', val: 20.00},
  { name: 'TEN', val: 10.00},
  { name: 'FIVE', val: 5.00},
  { name: 'ONE', val: 1.00},
  { name: 'QUARTER', val: 0.25},
  { name: 'DIME', val: 0.10},
  { name: 'NICKEL', val: 0.05},
  { name: 'PENNY', val: 0.01}
];
  var change = cash - price;
  var totalCid = cid.reduce(function(acc,curr){
    acc.total += curr[1];
    acc[curr[0]] = curr[1];
    return acc;
  },{total:0});
  
  if (totalCid.total === change) {
    return 'Closed';
  }

  if (totalCid.total < change) {
    return 'Insufficient Funds';
  }  
  
  var change_arr = denom.reduce(function(acc,curr){
    var value=0;
    while(totalCid[curr.name]>0 && change>=curr.val){
      change-=curr.val;
      totalCid[curr.name]-=curr.val;
      value += curr.val;
      change = Math.round(change * 100) / 100;
    }
    if(value>0){
      acc.push([ curr.name, value ]);
    }
    return acc;
  },[]);
  
  if (change_arr.length < 1 || change > 0) {
    return "Insufficient Funds";
  }
  return change_arr;
}

// Example cash-in-drawer array:
// [["PENNY", 1.01],
// ["NICKEL", 2.05],
// ["DIME", 3.10],
// ["QUARTER", 4.25],
// ["ONE", 90.00],
// ["FIVE", 55.00],
// ["TEN", 20.00],
// ["TWENTY", 60.00],
// ["ONE HUNDRED", 100.00]]

checkCashRegister(19.50, 20.00, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.10], ["QUARTER", 4.25], ["ONE", 90.00], ["FIVE", 55.00], ["TEN", 20.00], ["TWENTY", 60.00], ["ONE HUNDRED", 100.00]]);

3. Inventory Update

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

function updateInventory(arr1, arr2) {
  for(var i=0;i

4. No repeats please

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

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

function permAlone(str) {
  var arr = str.split('');
  var result = 0;
  
  function swap(a,b){
    var tmp = arr[a];
    arr[a] = arr[b];
    arr[b] = tmp;
  }
  
  
  function generate(n){
    var regex = /([a-z])\1+/;
    
    if(n===1 && !regex.test(arr.join(''))){
      result++;
    }else{
      for(var i=0;i!==n;i++){
        generate(n-1);
        swap(n%2 ? 0:i,n-1);
      }
    }
  }
  
  generate(arr.length);
  return result;
  
  
}

permAlone('aab');

5. 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 即可

let makeFriendlyDates = arr => {  
  const months = {"01" : "January","02" : "February","03" : "March", "04" : "April","05" : "May", "06" : "June", "07" : "July","08" : "August", "09" : "September","10" : "October", "11" : "November","12" : "December"  };  
  let date1 = arr[0].split("-"); 
  let date2 = arr[1].split("-");
  let date = new Date();  
  let dateChange = day => {  
    if(day[0] === "0"){  
      day = day.substr(1);  
      if(day === "1") return day + "st";  //01->1st
      if(day === "2") return day + "nd";  //02->2nd
      if(day === "3") return day + "rd";  //03->3rd
      else return day + "th";  
    }  
    else{  
      if(day.substr(1,1) === "1" && day.substr(0,1) === "2") return day + "st";  //21->21st
      if(day.substr(1,1) === "1" && day.substr(0,1) === "3") return day + "st";  //31->31st
      if(day.substr(1,1) === "2" && day.substr(0,1) === "2") return day + "nd";  //22->22nd
      if(day.substr(1,1) === "3" && day.substr(0,1) === "2") return day + "rd";  //23->23rd
      else return day + "th";   
    }    
  };  
  let sameYear = (d1, d2) => {  
    if(d2[0] - d1[0] > 1) return false;  
    else{  
      if(d1[0] === d2[0]) return true;   
      else{  //判断相减为1的时候
        if(d2[1] > d1[1]) return false;  
        if(d2[1] < d1[1]) return true; //判断在一年以内返回true
        else return d2[2] < d1[2] ? true : false; //判断是否在一年以内
      }  
    }  
  };  
  if (sameYear(date1, date2)) { 
    if(date1[0] === date2[0]){  
      if(date1[1] === date2[1]){  //月份相同 
        if(date1[2] === date2[2]){  //日期相同
          let dateArr = [];  
          dateArr.push(months[date1[1]] + " " + dateChange(date1[2]) + ", " + date1[0]);  
          return dateArr;  
        }else{  
          let dateArr = [];  
          dateArr.push(months[date1[1]] + " " + dateChange(date1[2]));  
          dateArr.push(dateChange(date2[2]));  
          return dateArr;  
        }  
      }
      else{  //月份不同
        let dateArr = [];  
        dateArr.push(months[date1[1]] + " " + dateChange(date1[2]));  
        dateArr.push(months[date2[1]] + " " + dateChange(date2[2]));  
        return dateArr;  
      }  
    }  
    if(date1[0] == date.getFullYear() - 2){  //开始年份为当前年份 
      let dateArr = [];  
      dateArr.push(months[date1[1]] + " " + dateChange(date1[2]));  
      dateArr.push(months[date2[1]] + " " + dateChange(date2[2]));  
      return dateArr;  
    }  
    else{  
      let dateArr = [];  
      dateArr.push(months[date1[1]] + " " + dateChange(date1[2]) + ", " + date1[0]);  
      dateArr.push(months[date2[1]] + " " + dateChange(date2[2]));  
      return dateArr;  
    }  
  }    
  if (date2[0] > date1[0]){  //不同年且d2比d1大时
    let dateArr = [];  
    dateArr.push(months[date1[1]] + " " + dateChange(date1[2]) + ", " + date1[0]);  
    dateArr.push(months[date2[1]] + " " + dateChange(date2[2]) + ", " + date2[0]);  
    return dateArr;  
  }  
};  
makeFriendlyDates(["2017-07-12", "2018-06-13"]);

6. Make a Person

用下面给定的方法构造一个对象.

方法有 getFirstName(), getLastName(), getFullName(), setFirstName(first), setLastName(last), and setFullName(firstAndLast).

所有有参数的方法只接受一个字符串参数.

所有的方法只与实体对象交互.

var Person = function(firstAndLast) {
  var fullName = firstAndLast;
  
  
  this.getFirstName=function(){
    return fullName.split(' ')[0];
  };
  
  this.getLastName=function(){
    return fullName.split(' ')[1];
  };
  
  this.getFullName=function(){
    return fullName;
  };
  
  this.setFirstName=function(first){
    fullName =  first+' '+ fullName.split(' ')[1];
  };
  
  this.setLastName=function(last){
    fullName =  fullName.split(' ')[0]+' '+ last;
  };
  this.setFullName=function(firstAndLast){
    fullName = firstAndLast;
  };
    return fullName;
};

var bob = new Person('Bob Ross');
bob.getFullName();

7. Map the Debris

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

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

function orbitalPeriod(arr) {
  var GM = 398600.4418;
  var earthRadius = 6367.4447;
  
  arr.forEach(function(item){
    item.orbitalPeriod=Math.round(2*Math.PI*Math.sqrt(Math.pow(earthRadius+item.avgAlt,3)/GM));
    delete item.avgAlt;
  });
  return arr;
}

orbitalPeriod([{name : "sputnik", avgAlt : 35873.5553}]);

9. 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) {
  var sum=0;
  var pairArr = arr.slice();
  for(var i=0;i

你可能感兴趣的:(Freecodecamp 高级算法题)