JavaScript基础编程训练 更新于2019-4-18

30天JS挑战完成了,做一些基础的JS编程训练吧
训练题目来自于codewars

- 将输入的一串数字按大到小排列(12312441)=>(44322111)

我的解答:

    function descendingOrder(n) {
      var s_num = String(n).split('');
      s_num.sort((a, b) => {
        return a < b ? 1 : -1;
      });
      return parseInt(s_num.join(''));
    }

更优解:

function descendingOrder(n){
return parseInt(String(n).split('').sort().reverse().join(''))
}
讨论

思路跟更优解基本一致,函数使用的熟练度不够

- 输入一个人名数组,按要求输出文本。

空数组: 没人喜欢;1元素:XXX喜欢;2元素:XXX和XXX喜欢;3元素:XXX,XXX和XXX喜欢;4及以上元素:XXX和XXX还有N人都喜欢
我的解:

    function likes(names) {
      switch (names.length) {
        case 0:
          return "no one likes this";   break;
        case 1:
          return names[0] + " likes this"; break;
        case 2:
          return names[0] + " and " + names[1] + " like this"; break;
        case 3:
          return names[0] + ", " + names[1] + " and " + names[2] + " like this";  break;
        default:
          return (names[0] + ", " +names[1] + " and " +(names.length - 2) +  " others like this");
      }
    }

更优解:

- 判断一个数是否为1^3 +2^3+ 3^3 ……n^3,如果是返回n,如果不是返回-1

我的解:

    function findNb(m) {
      i = Math.floor(Math.pow(4 * m, 1 / 4));
      console.log(Math.pow(i * (i + 1), 2));
      if (Math.pow(i * (i + 1), 2) / 4 == m) return i;
      else return -1;
    }

其他解:

用循环写
讨论

一开始网络不好用循环写的提交失败了,还以为不能用循环写,特意去找了公式
利用整除来进行判断是否为确切值
它用来判断的例子的n值都能达到2000多,用循环写真的行吗?

- 判断pin是否符合密码规范 (4或6位数字)

我的解:

    function validatePIN(pin) {
      s = pin.split("");
      flag = true;
      s.forEach(e => {
        if (!(e <= "9" && e >= "0")) flag = false;
      });
      if ((s.length == 4 || s.length == 6) && flag) return true;
      else return false;
    }

其他解:

maybe 正则?

- 找出中间数

给一个数组,要求找出其中一个位置的左边所有数的和等于右边所有数的和
我的解:

    function findEvenIndex(arr) {
      for (var i = 0; i < arr.length - 1; i++) {
        flag = -1;
        sum = 0;
        mus = 0;
        for (var j = 0; j < i; j++) {
          sum += arr[j];
        }
        for (var n = arr.length - 1; n > i; n--) {
          mus += arr[n];
        }
        if (sum == mus) {
          flag = i;
          break;
        }
      }
      return flag;
    }

更优解:

    function findEvenIndex(arr) {
      for (var i = 1; i < arr.length - 1; i++) {
        if (
          arr.slice(0, i).reduce((a, b) => a + b) ===
          arr.slice(i + 1).reduce((a, b) => a + b)
        ) {
          return i;
        }
      }
      return -1;
    }
讨论

思路差不多,更优解用slice将数组切片后用reduce求和,避免了嵌套循环和声明变量的尴尬
数组函数熟练度亟待提高

- 用JS建一个星星塔

我的解答:

function towerBuilder(nFloors) {
  arr = [];
  for(i = 1;i

更优解:

function towerBuilder(n) {
  return Array.from({length: n}, function(v, k) {
    const spaces = ' '.repeat(n - k - 1);
    return spaces + '*'.repeat(k + k + 1) + spaces;
  });
}
讨论

repeat()!!!!!!!!!

- 判断重复出现的字母/数字的个数(不区分大小写)

我的解:

function duplicateCount(text){
s_arr = text.toLowerCase().split('');
arr = [];
count = 0;
  s_arr.forEach((e)=>{
  if(arr[e]<2) {count++;arr[e]++}
  else if(arr[e]) ;
  else arr[e] = 1;
})
  return count;
}

更优解

function duplicateCount(text){
  return (text.toLowerCase().split('').sort().join('').match(/([^])\1+/g) || []).length;
}

function duplicateCount(text){
  return text.toLowerCase().split('').filter(function(val, i, arr){
    return arr.indexOf(val) !== i && arr.lastIndexOf(val) === i;//第一个val的位置不为i,最后一个val的位置为i,即重复出现
  }).length;
}
讨论

果然我的解太粗糙了,更优解用排序然后创造新数组/筛选器的方式
直接就得出答案了

- 古怪的大小写

要求每隔单词的奇数字母大写,偶数字母小写
我的解:

function toWeirdCase(string){
  s = string.split(' ');
  b = [];
  for( i=0 ;i

更优解:

function toWeirdCase(string){
  return string.split(' ').map(function(word){
    return word.split('').map(function(letter, index){
      return index % 2 == 0 ? letter.toUpperCase() : letter.toLowerCase()
    }).join('');
  }).join(' ');
}

function toWeirdCase(string){
  return string.replace(/(\w{1,2})/g,(m)=>m[0].toUpperCase()+m.slice(1))
}
讨论

又见正则
回调!!!回调!!!

- 计算单词的“价值”并返回价值最大的单词

a价值1,b价值2,c价值3以此类推,z价值26来计算价值
我的解:

    function high(x){
      return x.split(' ').sort((a,b)=> {return count(a)

更优解:

function high(s){
  let as = s.split(' ').map(s=>[...s].reduce((a,b)=>a+b.charCodeAt(0)-96,0));
  return s.split(' ')[as.indexOf(Math.max(...as))];
}

function high(x){
  return x.split(' ')
          .map((a,i)=>[a,a.split('').map(a=>a.charCodeAt(0)-96).reduce((a,b)=>a+b,0),i])
          .sort((a,b)=>b[1]!==a[1]? b[1]-a[1]:a[2]-b[2])[0][0]
}
讨论

更优解真是浓缩到了极致
map() reduce()连用避免循环

- 古怪的反转

句子中的单词如果多于五个字母就让他顺序颠倒
我的解:

function spinWords(str){
  return str.split(' ').map(s=>{return s.length>4?s.split('').reverse().join(''):s;}).join(' ');
}

其他解:

function spinWords(string){
  return string.replace(/\w{5,}/g, function(w) { return w.split('').reverse().join('') })
}
讨论

我也有今天!努力不是白给!
(正则好强)

- 返回各整十位数和

如:10012340=>'10000000 + 10000 + 2000 + 300 + 40'
我的解:

function expandedForm(num) {
  return String(num).split('').reverse().map((e,index)=> {return e!='0'?String(parseInt(e)*Math.pow(10,index)):''; }).filter(e=> e.length>0).reverse().join(' + ');
}

更优解:

const expandedForm = n => n.toString()
                            .split("")
                            .reverse()
                            .map( (a, i) => a * Math.pow(10, i))
                            .filter(a => a > 0)
                            .reverse()
                            .join(" + ");
讨论

区别在于array.map()的应用
我怎么用的这么笨重呢
遇到的问题:
map()不能删除不符合条件的值,因此只能再加一个把空值删除的函数,主要的时间都花在这上面了,最后还是想起来了用filter()
其他问题都挺顺利的解决了
更优解的在用map的时候不加判断,直接用filter筛选
我的解相当于筛选了两遍,太笨重了

- 字符串字母计数返回类

我的解

function count (string) {  
   ns = {};
   string.split('').forEach(e=>{if(ns[e]) ns[e]++;else ns[e] = 1;});
   return ns;
}

其他解:

function count (string) {
  return string.split('').reduce(function(counts,char){
    counts[char] = (counts[char]||0) + 1;
    return counts;
  },{});
}
讨论

在?为什么不用?选择?

- 喝饮料

不知道该怎么描述直接挂原题吧:Sheldon, Leonard, Penny, Rajesh and Howard are in the queue for a "Double Cola" drink vending machine; there are no other people in the queue. The first one in the queue (Sheldon) buys a can, drinks it and doubles! The resulting two Sheldons go to the end of the queue. Then the next in the queue (Leonard) buys a can, drinks it and gets to the end of the queue as two Leonards, and so on.
For example, Penny drinks the third can of cola and the queue will look like this:
Rajesh, Howard, Sheldon, Sheldon, Leonard, Leonard, Penny, Penny
Write a program that will return the name of the person who will drink the n-th cola.
我的解:

function whoIsNext(names, r){
  for(i=0;r>names.length*(Math.pow(2,i)-1);i++) ;
  r -= names.length*(Math.pow(2,i-1)-1);
  for(j=0;r>Math.pow(2,i-1)*j;j++) ;
  return  names[j-1];
}

更优:

function whoIsNext(names, r) {
  var l = names.length;
  while (r >= l) { r -= l; l *= 2; }
  return names[Math.ceil(names.length * r / l)-1];
}

这就是算法吗!!!!!!!!!!

- 数组超过三个连续数用横杠代替

原题:
A format for expressing an ordered list of integers is to use a comma separated list of either
individual integers
or a range of integers denoted by the starting integer separated from the end integer in the range by a dash, '-'. The range includes all integers in the interval including both endpoints. It is not considered a range unless it spans at least 3 numbers. For example ("12, 13, 15-17")
Complete the solution so that it takes a list of integers in increasing order and returns a correctly formatted string in the range format.
Example:

solution([-6, -3, -2, -1, 0, 1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20]);
// returns "-6,-3-1,3-5,7-11,14,15,17-20"

我的解:

function solution(list){
 arr = [];
 for(i = 0;i1) arr.push(list[e]+'-'+list[i]);
  else if(i!=e) arr.push(list[e],list[i]);
  else arr.push(list[i]);
 }
 return arr.join(',');
}

for 嵌套while,有点笨重,但是思路还是很清晰的

其他解:

function solution(list){
   for(var i = 0; i < list.length; i++){
      var j = i;
      while(list[j] - list[j+1] == -1) j++;
      if(j != i && j-i>1) list.splice(i, j-i+1, list[i] +'-'+list[j]);
  }
  return list.join();
}

- 寻找数组中字母一样的单词

我的解跟这差不多,但是它重构了sort()方法,(节省了资源?

String.prototype.sort = function() {
  return this.split("").sort().join("");
};

function anagrams(word, words) {
  return words.filter(function(x) {
      return x.sort() === word.sort();
  });
}

- 加法

真的就是简单的加法,但是输入的是字符串而且...巨长!
我的原始解:

function sumStrings(a,b) {
  arr_b = b.split('').reverse(); //数字b每位提出
  arr_a = a.split('').reverse(); //数字a每位提出
  arr_f = []; //最终数组
  flag = false; //用于判断进位
  len = arr_b.length>arr_a.length?arr_b.length:arr_a.length; //a、b不等长
  
for(i=0;ilen-2&&numb ==0&&numa ==0) flag = false; //判断最高位是否为0
  else if(!isNaN(numa)){ //a是否存在
    if(!isNaN(numb)){  //b是否存在
      if(numa+numb>9) {  //a+b是否进位
        flag = true;
        arr_f.push(numa+numb-10);    //push个位
      }
      else {
        arr_f.push(numa+numb);    //正常加法
        flag = false; 
      }
    }
    else {arr_f.push(numa);flag = false;} //b不存在,push a
  }
  else if(!isNaN(numb)) {arr_f.push(numb); flag = false;} //a不存在b存在,push b
  else if(flag) {arr_f.push(1); flag = false;}  //a、b都不存在,但是最高位进位

//返回结果
  return arr_f.reverse().join('');
}

本来想优化一下,还是算了留个

Mark

以后再看

更优解:

function sumStrings(a, b) {
  var res = '', c = 0;
  a = a.split('');
  b = b.split('');
  while (a.length || b.length || c) {
    c += ~~a.pop() + ~~b.pop();
    res = c % 10 + res;
    c = c > 9;
  }
  return res.replace(/^0+/, '');
}

强无敌,这个熟练度...

讨论

!可以做完一个之后,就把那个剔除!用pop就可以避开循环。

- 经典算法问题——最大子列和

我的解:

var maxSequence = function(arr){
  // ...
  max = 0;
  if(arr.length<1);
  else if(arr.length<4) max =  arr.reduce((acc,e)=>{if(!e<0) return acc+e;});
  else {
    for(i=0;ia+e);
        max = Math.max(max,sum);
      }
    }
  }
  return Math.max(0,max);
}

循环嵌套,笨拙,还写了很久。。。

更优:

var maxSequence = function(arr){
  var min = 0, ans = 0, i, sum = 0;
  for (i = 0; i < arr.length; ++i) {
    sum += arr[i];
    min = Math.min(sum, min);
    ans = Math.max(ans, sum - min);
  }
  return ans;
}

循环一次,求i前所有元素的和,min记录前n项和最小值

最大值为max(sum,sum-min)

!精巧

- 求一个可无限外推的数列的第N项

原题:

Consider a sequence u where u is defined as follows:
The number u(0) = 1 is the first one in u.
For each x in u, then y = 2 * x + 1 and z = 3 * x + 1 must be in u too.
There are no other numbers in u.
Ex: u = [1, 3, 4, 7, 9, 10, 13, 15, 19, 21, 22, 27, ...]
1 gives 3 and 4, then 3 gives 7 and 10, 4 gives 9 and 13, then 7 gives 15 and 22 and so on...
Task:
Given parameter n the function dbl_linear (or dblLinear...) returns the element u(n) of the ordered (with <) sequence u (so, there are no duplicates).
Example:
dbl_linear(10) should return 22
Note:
Focus attention on efficiency

我的解:

function dblLinear(n) {
    var u =[1];
    var i=0,tempz = 0,tempy =0;
    for(i;inumz) {u.push(numz);tempz++; }
      else if(numy == numz) {tempz++;i--;}
      else {u.push(numy); tempy++;  }
   }
    return u[n];
}
讨论

代码思路:
对于u的每一项u,都有两种可能值:y = u[_y]2+1 ; z = u[_z]3+1;
数组要按递增顺序排列 ->y与z都是递增的 ->只需要比较y与z的大小然后push回原数组即可
*由于数组内的所有数都有可能值,因此要对y和z所取的值的位置分别做一个记录_y,_z
如果_y产生的y小,push(y),_y++;
如果_z产生的z小,push(z),_z++;
如果z、y一样大,有两种处理方法:1、push(y),_y++,_z++,i--
2、_z++,_i--

相当于看作两个数组y和z,把他们逐个比较,push()较小值,跳过重复值。

这样一来就能在z和y的两条路上,按大小顺序取值,去除重复值,顺序排列,且只需取到想要的n过即可。

你可能感兴趣的:(JavaScript基础编程训练 更新于2019-4-18)