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<nFloors+1;i++){
  n = '';  
    for(j = 0;j<2*i-1;j++){
      n = n + '*';
    }
    for(j = 0;j< nFloors -i;j++){
      n = ' ' + n + ' ';
    }
    arr.push(n);
  }
  return arr;
}

更优解:

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<s.length;i++){
     b[i] = s[i].split('');
     for(j = 0;j<b[i].length; j++){
       b[i][j] = j%2!=0?b[i][j].toLowerCase():b[i][j].toUpperCase();
     }
     b[i] = b[i].join('');
  }
  return b.join(' ');
}

更优解:

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)<count(b)?1:-1;})[0];
      function count(str){
        cou = 0;
        for(i=0;i<str.length;i++){
          cou = cou+ (str.charCodeAt(i)-96);
        }
        return cou;
      }
}

更优解:

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;i<list.length;i++){
 e = i;
 while( (list[i+1]-list[i])== 1){
     i++;
 }
  if(i-e>1) 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;i<len+1;i++){
      //a、b每位数字
      numa = parseInt(arr_a[i]);
      numb = parseInt(arr_b[i]);

//是否进位
  if(flag&&!isNaN(numa)) numa ++;
  else if(flag&&!isNaN(numb)) numb ++;
 
//进行加法运算
  if(i>len-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;i<arr.length;i++){
      for(j = i+1;j<arr.length+1;j++){
        sum = arr.slice(i,j).reduce((a,e)=>a+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;i<n;i++){
      var numy = u[tempy]*2+1;
      var numz = u[tempz]*3+1;
      
      if(numy>numz) {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过即可。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容

  • 今天是今年来我最放松和偷懒的曰子。 平时,每一天,每一刻时间都安排紧凑,总担心把时间浪费了,不敢稍有松泄。心里...
    谭皓匀阅读 324评论 0 3
  • 国庆放假的时候,决定不回去。。看到这样的黄昏突然就有点想念家乡山中的黄昏,所以,用手机定格了这一时刻。。 最后两张...
    山隐结发阅读 207评论 0 1