变得更强!思维发散练习

为什么要写这篇

想学到大神们优秀的思想,敏锐的解决问题的思路!

给定一个字符串,若字符串大于4位字符,则保留后四位,前面的字符用”#”代替

我的最优方案:

1
2
3
4
5
6
7
function maskStr(cc) {
var length = cc.length;
if (length > 4) {
return cc.substr(0, length - 4).replace(/./g, '#') + cc.substr(length - 4);
}
return cc;
}

让人眼前一亮的牛逼方案:

1
2
3
function maskify(cc) {
return cc.slice(0, -4).replace(/./g, '#') + cc.slice(-4);
}

其实就是 slice 方法负数的妙用!

这里涉及到就是同为切割字符串的函数,slice 和 substr 有什么区别?

  • slice(start,end) 接受两个参数

    start:要抽取的片断的起始下标。如果是负数,则该参数规定的是从字符串的尾部开始算起的位置。也就是说,-1 指字符串的最后一个字符,-2 指倒数第二个字符,以此类推。
    end:紧接着要抽取的片段的结尾的下标。若未指定此参数,则要提取的子串包括 start 到原字符串结尾的字符串。如果该参数是负数,那么它规定的是从字符串的尾部开始算起的位置。

常用(隐藏手机号中间四位):

1
2
3
4
function makeStr(str){
//这里可以这样记,3-7 即 x>3 && x<=7,x=4,5,6,7
return str.slice(0,3) + str.slice(3,7).replace(/./g,'#') + str.slice(7,11);
}

  • substr(start,length) 接受两个参数

    start 必需。要抽取的子串的起始下标。必须是数值。如果是负数,那么该参数声明从字符串的尾部开始算起的位置。也就是说,-1 指字符串中最后一个字符,-2 指倒数第二个字符,以此类推。
    length 可选。子串中的字符数。必须是数值。如果省略了该参数,那么返回从 stringObject 的开始位置到结尾的字串。

重要事项:ECMAscript 没有对 substr 方法进行标准化,因此反对使用它。

长度大于5位的字符串反向

需求:输入一个字符串,形式为 hello world kobe,处理长度大于5位的字符串反向。返回结果 olleh dlrow kobe
我的方案:

1
2
3
4
5
6
7
8
9
10
function spinWords(word){
word = word.split(' ');
for(var i=0;i<word.length;i++){
if(word[i].length>=5){
word[i] = word[i].split('').reverse().join('');
}
}

return word.join(' ');
}

牛逼的方案1:

1
2
3
4
5
function spinWords(word){
return word.split(' ').map((word) => {
return (word.length>4)?word.split('').reverse().join(''):word
}).join(' ');
}

牛逼的方案2:

1
2
3
4
5
function spinWords(word){
return word.replace(/\w{5,}/g,(w) => {
return w.split('').reverse().join('');
});
}

这里 word.replace(/\w{5,}/g) 中 \w 表示匹配所有的下划线,字母,数字;{5,}表示前面的字符至少出现5次,g表示全局。

牢记:字符串reverse的最常用方法 str.split(‘’).reverse().join(‘’),先转为数组reverse,然后转回字符串

输入一个正整数,计算从1加到该数的合

我的方案

1
2
3
4
5
6
7
8
9
10
function sum(n){
if(typeof n !='number' || n<=0 || n%1!=0){
return false;
}
var sum=0;
for(var i=1;i<=n;i++){
sum+=i;
}
return sum;
}

更优的解决方案

首先,从1加到某数有个公式,呃,数学差连这个都忘了 n*(n+1)/2
其次,要想办法把简单的 if 转化成 三元表达式!!!

1
2
3
function sum(n){
return (typeof n !='number' || n<=0 || n%1!=0)?false:n*(n+1)/2;
}

ps:判断一个数是否为正整数最简单的方法

1
Number.isInteger(n) && n > 0

输入一个字符串,判断该字符串中 x 和 o 的数量是否一致,不分大小写

我的方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function XO(str) {
str = str.split('');
var x = 0,
o = 0;
str.map((data) => {
switch (data.toLowerCase()) {
case 'x':
x += 1;
break;
case 'o':
o += 1;
break;
}
});

return x == o;
}

更优的解决方案:

1
2
3
4
5
function XO(str){
var x = str.match(/x/g);
var o = str.match(/o/g);
return (x && x.length) === (o && o.length);
}

发现n多次处理数据匹配都是用正则更高效!
这里 match 的用法有两种:

1
2
stringObject.match(searchvalue)
stringObject.match(regexp)

searchvalue 必需。规定要检索的字符串值。
regexp 必需。规定要匹配的模式的 RegExp 对象。如果该参数不是 RegExp 对象,则需要首先把它传递给 RegExp 构造函数,将其转换为 RegExp 对象。

注意:

如果 regexp 没有标志 g,那么 match() 方法就只能在 stringObject 中执行一次匹配。如果没有找到任何匹配的文本, match() 将返回 null。否则,它将返回一个数组,其中存放了与它找到的匹配文本有关的信息。该数组的第 0 个元素存放的是匹配文本,而其余的元素存放的是与正则表达式的子表达式匹配的文本。除了这些常规的数组元素之外,返回的数组还含有两个对象属性。index 属性声明的是匹配文本的起始字符在 stringObject 中的位置,input 属性声明的是对 stringObject 的引用。
如果 regexp 具有标志 g,则 match() 方法将执行全局检索,找到 stringObject 中的所有匹配子字符串。若没有找到任何匹配的子串,则返回 null。如果找到了一个或多个匹配子串,则返回一个数组。不过全局匹配返回的数组的内容与前者大不相同,它的数组元素中存放的是 stringObject 中所有的匹配子串,而且也没有 index 属性或 input 属性。

给定一个秒数,转换为 HH:mm:ss

大神的代码:

1
2
3
4
5
6
function humanReadable(seconds) {
var pad = function(x) { return (x < 10) ? "0"+x : x; }
return pad(parseInt(seconds / (60*60))) + ":" +
pad(parseInt(seconds / 60 % 60)) + ":" +
pad(seconds % 60)
}