牛客网前端算法题记录

1、修改this指向:封装函数 f,使 f 的 this 指向指定的对象

//解法1:apply
function bindThis(f, oTarget) {
    return function(){
        return f.apply(oTarget,arguments);
    }
}
//解法2:bind
function bindThis(f, oTarget) {
    return f.bind(oTarget);
}
//解法3:call
function bindThis(f, oTarget) {
    return function(x,y){
        return f.call(oTarget,x,y);
    };
}
View Code

2、获取 url 中的参数
  1. 指定参数名称,返回该参数的值 或者 空字符串
  2. 不指定参数名称,返回全部的参数对象 或者 {}
  3. 如果存在多个同名参数,则返回数组

  输入:http://www.nowcoder.com?key=1&key=2&key=3&test=4#hehe key

  输出:[1, 2, 3]

function getUrlParam(sUrl, sKey) {
     var result = {};
  sUrl.replace(/\??(\w+)=(\w+)&/g, function (a,b, c) {
    if (result[b]) {
      result[b] = [].concat(result[b], c);
    } else {
      result[b] = c;
    }
  });
  if (sKey) {
    return result[sKey] || '';
  } else {
    return result;
  }
}
View Code

3、dom节点查找,查找两个节点的最近的一个共同父节点,可以包括节点自身

  输入:oNode1 和 oNode2 在同一文档中,且不会为相同的节点

function commonParentNode(oNode1, oNode2) {
    for(;oNode1;oNode1=oNode1.parentNode){
        if(oNode1.contains(oNode2)){
            return oNode1;
        }
    }
}
View Code

4、根据包名,在指定空间中创建对象

  输入:namespace({a: {test: 1, b: 2}}, 'a.b.c.d')

  输出:{a: {test: 1, b: {c: {d: {}}}}}

function namespace(oNamespace, sPackage) {
    var package = sPackage.split('.');
    var obj = oNamespace;
    for(var i=0;i<package.length;i++){
        if(typeof obj[package[i]]!=='object'){
            obj[package[i]]={};
        }
        obj=obj[package[i]];
    }
    return oNamespace;
}
View Code

5、数组去重,为 Array 对象添加一个去除重复项的方法

  输入:[false, true, undefined, null, NaN, 0, 1, {}, {}, 'a', 'a', NaN]

  输出:[false, true, undefined, null, NaN, 0, 1, {}, {}, 'a']

//解法1:
Array.prototype.uniq = function () {
      return [...new Set(this)];
}
//解法2:
Array.prototype.uniq = function () {
    var resArr = [];
   var flag = true;
 
   for(var i=0;i<this.length;i++){
       if(resArr.indexOf(this[i]) == -1){
           if(this[i] != this[i]){   //排除 NaN
              if(flag){
                   resArr.push(this[i]);
                   flag = false;
              }
           }else{
                resArr.push(this[i]);
           }
       }
   }
    return resArr;
}
View Code

6、斐波那契数列,用 JavaScript 实现斐波那契数列函数,返回第n个斐波那契数。 f(1) = 1, f(2) = 1 等

//解法1:
function fibonacci(n) {
    if(n==1||n==2)
        return 1;
    return fibonacci(n-1)+fibonacci(n-2);
}
//解法2:
function fibonacci(n) {
        //一、递归解法
        //return n<=2?1:fibonacci(n-1)+fibonacci(n-2);
         
        //二、循环解法
        var num1=1;
        var num2=1;
        for(var i=2;i<n;i++){
                num2+=num1;
                num1=num2-num1;
        }
        return num2;
}
View Code

7、时间格式化输出,按所给的时间格式输出指定的时间,格式说明:对于 2014.09.05 13:14:20

  yyyy: 年份,2014
  yy: 年份,14
  MM: 月份,补满两位,09
  M: 月份, 9
  dd: 日期,补满两位,05
  d: 日期, 5
  HH: 24制小时,补满两位,13
  H: 24制小时,13
  hh: 12制小时,补满两位,01
  h: 12制小时,1
  mm: 分钟,补满两位,14
  m: 分钟,14
  ss: 秒,补满两位,20
  s: 秒,20
  w: 星期,为 ['日', '一', '二', '三', '四', '五', '六'] 中的某一个,本 demo 结果为 五

function formatDate(t,str){
  var obj = {
    yyyy:t.getFullYear(),
    yy:(""+ t.getFullYear()).slice(-2),
    M:t.getMonth()+1,
    MM:("0"+ (t.getMonth()+1)).slice(-2),
    d:t.getDate(),
    dd:("0" + t.getDate()).slice(-2),
    H:t.getHours(),
    HH:("0" + t.getHours()).slice(-2),
    h:t.getHours() % 12,
    hh:("0"+t.getHours() % 12).slice(-2),
    m:t.getMinutes(),
    mm:("0" + t.getMinutes()).slice(-2),
    s:t.getSeconds(),
    ss:("0" + t.getSeconds()).slice(-2),
    w:['日', '一', '二', '三', '四', '五', '六'][t.getDay()]
  };
  return str.replace(/([a-z]+)/ig,function($1){return obj[$1]});
}
View Code

8、获取字符串长度,如果第二个参数 bUnicode255For1 === true,则所有字符长度为 1,否则如果字符 Unicode 编码 > 255 则长度为 2

  输入:'hello world, 牛客', false

  输出:17

//解法1:
function strLength(s, bUnicode255For1) {
    let len = s.length
    if(bUnicode255For1 !== true){
        for(let i in s){
            if(s.charCodeAt(i)>255)len++
        }       
    }
    return len
}
//解法2:
function strLength(s, bUnicode255For1) {
     let length = s.length
    if(!bUnicode255For1){
        for(let i = 0,len = s.len;i<length;i++){
            if(s.charCodeAt(i)>255){
                length++
            }
        }
    }
    return length
}
//解法3:
function strLength(s, bUnicode255For1) {
    let size = s.length;
     if(bUnicode255For1) return size;
    for(let i = 0; i < s.length; i++) {
        if(s.charCodeAt(i) > 255) size++;
    }
    return size;
}
View Code

9、邮箱字符串判断,判断输入是否是正确的邮箱格式

  输入:邮箱字符串

  输出:true表示格式正确

function isAvailableEmail(sEmail) {
    var reg=/^([\w+\.])+@\w+([.]\w+)+$/;
    return reg.test(sEmail);
}
View Code

10、颜色字符串转换,将 rgb 颜色字符串转换为十六进制的形式,如 rgb(255, 255, 255) 转为 #ffffff
  1. rgb 中每个 , 后面的空格数量不固定
  2. 十六进制表达式使用六位小写字母
  3. 如果输入不符合 rgb 格式,返回原始输入

  输入:'rgb(255, 255, 255)'

  输出:#ffffff

//解法1
function rgb2hex(sRGB) {
   return sRGB.replace(/^rgb\((\d+)\s*\,\s*(\d+)\s*\,\s*(\d+)\)$/g, function(a, r, g, b){
       return '#' + hex(r) + hex(g) + hex(b);
   });
}
function hex(n){
    return n < 16 ? '0' + (+n).toString(16) : (+n).toString(16);
}
//解法2:
function rgb2hex(sRGB) {
    return sRGB.replace(/^rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\)$/,function($0,$1,$2,$3){
        return '#'+toHex($1)+toHex($2)+toHex($3);
    });
}
function toHex(str){
    return ('0'+(+str).toString(16)).slice(-2);
}
//解法3:
function rgb2hex(sRGB){
    var result=['#'];
    if(!/rgb\(\d+(,\s*\d+){2}\)/.test(sRGB)){
        return sRGB;
    }
    sRGB.replace(/\d+/g,function($0){
        result.push(('0'+(+$0).toString(16)).slice(-2));
    });
    return result.join('');
}
View Code

11、字符串字符统计,统计字符串中每个字符的出现频率,返回一个 Object,key 为统计字符,value 为出现频率
  1. 不限制 key 的顺序
  2. 输入的字符串参数不会为空
  3. 忽略空白字符

  输入:'hello world'

  输出:{h: 1, e: 1, l: 3, o: 2, w: 1, r: 1, d: 1}

//解法1:
function count(str) {
    var obj = {};
    str.replace(/\S/g,function(s){
        !obj[s]?obj[s]=1:obj[s]++;
    })
    return obj;
}
//解法2:
function count(str) {
    for(var i=0, m=str.length, res={}; i<m; i++){
        if(str.charAt(i) in res) res[str.charAt(i)]++;
        else res[str.charAt(i)] = 1;
    }
    return res;
}
//解法3:
function count(str) {
    var obj = {};
     
    for (var i = 0; i < str.length; ++i) {
        if (str[i] !== ' ') {
            obj[str[i]] = obj[str[i]] ? ++obj[str[i]] : 1;
        }
    }
     
    return obj;
}
View Code

 12、将字符串转换为驼峰格式,css 中经常有类似 background-image 这种通过 - 连接的字符,通过 javascript 设置样式的时候需要将这种样式转换成 backgroundImage 驼峰格式,请完成此转换功能
  1. 以 - 为分隔符,将第二个起的非空单词首字母转为大写
  2. -webkit-border-image 转换后的结果为 webkitBorderImage

  输入:'font-size'

  输出:fontSize

//解法1:
function cssStyle2DomStyle(sName) {
    return sName.replace(/\-[a-z]/g , function(a, b){
    return b == 0 ? a.replace('-','') : a.replace('-','').toUpperCase();
});
}
//解法2:
function cssStyle2DomStyle(sName) {
    var arr = sName.split(''); 
    //判断第一个是不是 '-',是的话就删除
    if(arr.indexOf('-') == 0)
        arr.splice(0,1);
   //处理剩余的'-'
    for(var i=0; i<arr.length; i++){
        if(arr[i] == '-'){
            arr.splice(i,1);
            arr[i] = arr[i].toUpperCase();
        }
    }
    return arr.join('');
}
//解法3:
 function cssStyle2DomStyle(sName) {
    //使用正则将 前一位有-的字符替换为大写【-([a-z])】
    //replace第二个参数为函数时:
    //函数的第一个参数是匹配模式的字符 【t】
    //接下来的参数是与模式中的子表达式匹配的字符,可以有0个或多个这样的参数。【m】
    //接下来的参数是一个整数,代表匹配在被替换字符中出现的位置【i】
    //最后一个参数是被替换字符本身【这里没有用到】
    return sName.replace(/-([a-z])/g,function(t,m,i){return i?m.toUpperCase():m;})
}
View Code

13、字符串字符统计,统计字符串中每个字符的出现频率,返回一个 Object,key 为统计字符,value 为出现频率

  1. 不限制 key 的顺序
  2. 输入的字符串参数不会为空
  3. 忽略空白字符

  输入:'hello world'

  输出:{h: 1, e: 1, l: 3, o: 2, w: 1, r: 1, d: 1}

//解法1:
function count(str) {
    var obj = {};
    str.replace(/\S/g,function(s){
        !obj[s]?obj[s]=1:obj[s]++;
    })
    return obj;
}
//解法2:
function count(str) {
    for(var i=0, m=str.length, res={}; i<m; i++){
        if(str.charAt(i) in res) res[str.charAt(i)]++;
        else res[str.charAt(i)] = 1;
    }
    return res;
}
//解法3:
function count(str) {
    return str.split('').reduce(function(prev, item) {
        if (item !== ' ') {
            prev[item] ? prev[item]++ : prev[item] = 1;
        }
         
        return prev;
    }, {});
}
View Code

14、查找数组元素位置,找出元素 item 在给定数组 arr 中的位置,如果数组中存在 item,则返回元素在数组中的位置,否则返回 -1

  输入:[ 1, 2, 3, 4 ], 3

  输出:2

//解法1:indexOf()方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。
function indexOf(arr,item){
    return arr.indexOf(item);
}
//解法2:
function indexOf(arr, item){
    var index = -1;
    arr.forEach(function(res,i){
        if(res === item && index === -1){
            index = i;
        }
    });
    return index;
};
//解法3:
function indexOf(arr, item) {
  if (Array.prototype.indexOf){
      return arr.indexOf(item);
  } else {
      for (var i = 0; i < arr.length; i++){
          if (arr[i] === item){
              return i;
          }
      }
  }     
  return -1;
}
View Code

15、数组求和,计算给定数组 arr 中所有元素的总和,数组中的元素均为 Number 类型

  输入:[ 1, 2, 3, 4 ]

  输出:10

//解法1:递归
function sum(arr) {
    var len = arr.length;
    if(len == 0){
        return 0;
    } else if (len == 1){
        return arr[0];
    } else {
        return arr[0] + sum(arr.slice(1));
    }
}
//解法2:循环添加
function sum(arr) {
    var s = 0;
    for (var i=arr.length-1; i>=0; i--) {
        s += arr[i];
    }
    return s;
}
//解法3:reduce
function sum(arr) {
    return arr.reduce(function(prev, curr, idx, arr){
        return prev + curr;
    });
}
//解法4:forEach
function sum(arr) {
    var s = 0;
    arr.forEach(function(val, idx, arr) {
        s += val;
    }, 0);
    return s;
};
//解法5:eval
function sum(arr) {
    return eval(arr.join("+"));
};
View Code

16、移除数组中的元素,移除数组 arr 中的所有值与 item 相等的元素。不要直接修改数组 arr,结果返回新的数组

  输入:[1, 2, 3, 4, 2], 2

  输出:[1, 3, 4]

//解法1:splice
function remove(arr,item){
    var newarr = arr.slice(0);
    for(var i=0;i<newarr.length;i++){
        if(newarr[i] == item){
            newarr.splice(i,1);
            i--;
        }
    }
    return newarr;
}
//解法2:push
function remove(arr,item){
    var newarr = [];
    for(var i=0;i<arr.length;i++){
        if(arr[i] != item){
            newarr.push(arr[i]);
        }
    }
    return newarr;
}
//解法3:Array
function remove(arr,item){
    return arr.filter(function(ele){
         return ele != item;
    })
}
//解法4:正则
function remove(arr, item) {
    return arr.filter(function (elem) {
        return elem !== item;
    });
}
View Code

17、移除数组中的元素,移除数组 arr 中的所有值与 item 相等的元素,直接在给定的 arr 数组上进行操作,并将结果返回

  输入:[1, 2, 2, 3, 4, 2, 2], 2

  输出:[1, 3, 4]

//解法1:把数组看成是队列,等于item元素直接删除,不等于的,先push再删除
function removeWithoutCopy(arr, item) {
    var n=arr.length;
     for(var i=0;i<n;i++){
         if(arr[0]!==item)   
             arr.push(arr[0]);
         arr.shift();
           
    }
    return arr;
}
//解法2:while
function removeWithoutCopy(arr, item) {
 while(arr.indexOf(item) != -1){
        arr.splice(arr.indexOf(item),1);
    }
    return arr;
}
//解法3:splice
function removeWithoutCopy(arr, item) {
     for(var i = 0; i < arr.length; i++){
         if(arr[i] == item){
             //splice方***改变数组长度,当减掉一个元素后,后面的元素都会前移,因此需要相应减少i的值
             arr.splice(i,1);
             i--;
         }
     }
     return arr;
 }
//解法4:set
function removeWithoutCopy(arr, item) {
    arr=Array.from(new Set(arr));
    var a=arr.indexOf(item);
    arr.splice(a,1);
    return arr;
}
View Code

18、添加元素,在数组 arr 末尾添加元素 item。不要直接修改数组 arr,结果返回新的数组

  输入:[1, 2, 3, 4], 10

  输出:[1, 2, 3, 4, 10]

//解法1:slice
function append(arr, item) {
  var newArr = arr.slice(0);  // slice(start, end)浅拷贝数组
    newArr.push(item);
    return newArr;
}
//解法2:concat
function append(arr, item) {
     return arr.concat(item);
}
//解法3:...
function append(arr, item) {
    return [...arr,item]
}
View Code

19、删除数组最后一个元素,删除数组 arr 最后一个元素。不要直接修改数组 arr,结果返回新的数组

  输入:[1, 2, 3, 4]

  输出:[1, 2, 3]

//解法1:pop
function truncate(arr) {
 var a = arr.slice(0);
     a.pop();
     return a;
 }
//解法2:slice
function truncate(arr) {
    return arr.slice(0,-1);
}
//解法3:filter
function truncate(arr) {
    return arr.filter(function(v,i,ar) {
        return i!==ar.length-1;
    });
}
//解法4:迭代拷贝
function truncate(arr, item) {
    var newArr=[];
    for(var i=0;i<arr.length-1;i++){
        newArr.push(arr[i]);
    }
    return newArr;
}
View Code

20、添加元素,在数组 arr 开头添加元素 item。不要直接修改数组 arr,结果返回新的数组

  输入:[1, 2, 3, 4], 10

  输出:[10, 1, 2, 3, 4]

//解法1:concat
function prepend(arr, item) {
    return [item].concat(arr);
}
//解法2:push.apply
function prepend(arr, item) {
    var newArr=[item];
    [].push.apply(newArr, arr);
    return newArr;
}
//解法3:slice+unshift/splice
function prepend(arr, item) {
    var newArr=arr.slice(0);
    newArr.unshift(item);//newArr.splice(0,0,item);
    return newArr;
}
//解法4:使用join+split+unshift/splice组合
function prepend(arr, item) {
    var newArr=arr.join().split(',');
    newArr.unshift(item);//newArr.splice(0,0,item);
    return newArr;
}
//解法5普通的迭代拷贝
function prepend(arr, item) {
    var newArr=[];
    for(var i=0;i<arr.length;i++){
        newArr.push(arr[i]);
    }
    newArr.unshift(item);
    return newArr;
}
View Code

21、删除数组第一个元素。不要直接修改数组 arr,结果返回新的数组

  输入:[1, 2, 3, 4]

  输出:[2, 3, 4]

//解法1:slice
function curtail(arr) {
    return arr.slice(1);
}
//解法2:filter
function curtail(arr) {
    return arr.filter(function(v,i) {
        return i!==0;
    });
}
//解法3:push.apply+shift
function curtail(arr) {
    var newArr=[];
    [].push.apply(newArr, arr);
    newArr.shift();
    return newArr;
}
//解法4:concat+shift
function curtail(arr) {
    var newArr = arr.concat();
    newArr.shift();
    return newArr;
}
//解法5:普通的迭代拷贝
function curtail(arr) {
    var newArr=[];
    for(var i=1;i<arr.length;i++){
        newArr.push(arr[i]);
    }
    return newArr;
}
View Code

22、数组合并,合并数组 arr1 和数组 arr2。不要直接修改数组 arr,结果返回新的数组

  输入:[1, 2, 3, 4], ['a', 'b', 'c', 1]

  输出:[1, 2, 3, 4, 'a', 'b', 'c', 1]

//解法1:concat
function concat(arr1, arr2) {
    return arr1.concat(arr2);
}
//解法2:slice+push.apply
function concat(arr1, arr2) {
    var newArr=arr1.slice(0);
    [].push.apply(newArr, arr2);
    return newArr;
}
//解法3:slice+push
function concat(arr1, arr2) {
    var newArr=arr1.slice(0);
    for(var i=0;i<arr2.length;i++){
        newArr.push(arr2[i]);
    }
    return newArr;
}
//解法4:普通的迭代拷贝
function concat(arr1, arr2) {
    var newArr=[];
    for(var i=0;i<arr1.length;i++){
        newArr.push(arr1[i]);
    }
    for(var j=0;j<arr2.length;j++){
        newArr.push(arr2[j]);
    }
    return newArr;
}
View Code

23、添加元素,在数组 arr 的 index 处添加元素 item。不要直接修改数组 arr,结果返回新的数组

  输入:[1, 2, 3, 4], 'z', 2

  输出:[1, 2, 'z', 3, 4]

//解法1:slice+concat
function insert(arr, item, index) {
    return arr.slice(0,index).concat(item,arr.slice(index));
}
//解法2:concat +splice
function insert(arr, item, index) {
    var newArr=arr.concat();
    newArr.splice(index,0,item);
    return newArr;
}
//:解法3:slice+splice
function insert(arr, item, index) {
    var newArr=arr.slice(0);
    newArr.splice(index,0,item);
    return newArr;
}
//解法4:普通的迭代拷贝
function insert(arr, item, index) {
    var newArr=[];
    for(var i=0;i<arr.length;i++){
        newArr.push(arr[i]);
    }
    newArr.splice(index,0,item);
    return newArr;
}
View Code

24、计数,统计数组 arr 中值等于 item 的元素出现的次数

  输入:[1, 2, 4, 4, 3, 4, 3], 4

  输出:3

//解法1:filter
function count(arr, item) {
    var count = arr.filter(function(a) {
        return a === item;   //返回true的项组成的数组
    });
    return count.length;
}
//解法2:map
function count(arr, item) {
    var count = 0;
    arr.map(function(a) {
        if(a === item) {
           count++;
        }
   });
   return count;
}
//解法3:reduce
function count(arr, item) {
    var count = arr.reduce(function(prev, curr) {
        return curr === item ? prev+1 : prev;
    }, 0);
    return count;
}
//解法4:forEach
function count(arr, item) {
    var count = 0;
    arr.forEach(function(a) {
       a === item ? count++ : 0;
    });
    return count;
}
View Code

25、查找重复元素,找出数组 arr 中重复出现过的元素

  输入:[1, 2, 4, 4, 3, 3, 1, 5, 3]

  输出:[1, 3, 4]

//解法1:forEach
function duplicates(arr) {
 var result = [];
    arr.forEach(function(elem){
       if(arr.indexOf(elem) !=arr.lastIndexOf(elem) && result.indexOf(elem) == -1){
           result.push(elem);
       }
    });
    return result;
}
//解法2:filter
function duplicates(arr) {
    return arr.filter(function(item,index,array){
            return array.indexOf(item) !== array.lastIndexOf(item) && array.indexOf(item) === index;
    })
} 
View Code

 26、求二次方,为数组 arr 中的每个元素求二次方。不要直接修改数组 arr,结果返回新的数组

  输入:[1, 2, 3, 4]

  输出:[1, 4, 9, 16]

//解法1:map + 箭头函数
 function square(arr) {
      return arr.map(a => a*a);
} 
//解法2:forEach+push
function square(arr) { 
     var a = [];
     arr.forEach(function(e){ 
         a.push(e*e);
     });
     return a;
 }
//解法3:map+数学函数
function square(arr) {
    return arr.map(e => Math.pow(e,2));
}
View Code

 27、查找元素位置,在数组 arr 中,查找值与 item 相等的元素出现的所有位置

  输入:['a','b','c','d','e','f','a','b','c'] 'a'

  输出:[0, 6]

//解法1:forEach
function findAllOccurrences(arr, target) { 
    var temp = []; 
    arr.forEach(function(val,index){ 
        val !== target ||  temp.push(index); 
    }); 
    return temp;
}
//解法2:filter
function findAllOccurrences(arr, target) {
    var result=[];
    arr.filter(function(item,index){
        return item===target&&result.push(index);
    });
    return result;
}
//解法3:indexOf
function findAllOccurrences(arr, target) {
    var result=[],index=arr.indexOf(target);
    while(index>-1){
        result.push(index);
        index=arr.indexOf(target,index+1);
    }
    return result;
}
//解法4:forEach + 箭头函数
function findAllOccurrences(arr, target) { 
   res = [];
    arr.forEach((e, i) => target == e ? res.push(i): res);
    return res;
}
View Code

28、计时器,实现一个打点计时器,要求
  1、从 start 到 end(包含 start 和 end),每隔 100 毫秒 console.log 一个数字,每次数字增幅为 1
  2、返回的对象中需要包含一个 cancel 方法,用于停止定时操作
  3、第一个数需要立即输出

//解法1:setTimeout
function count(start, end) {
    console.log(start)
    var dingshi = setInterval(function () {
        if (start < end) {
            console.log(start += 1)
        }
    }, 100)
    return { cancel: function () { clearInterval(dingshi)} }
}
//解法2:setInterval
function count(start, end) {
  //立即输出第一个值
  console.log(start++);
     var timer = setInterval(function(){
         if(start <= end){
             console.log(start++);
         }else{
             clearInterval(timer);
         }
     },100);
    //返回一个对象
     return {
         cancel : function(){
             clearInterval(timer);
         }
     };
 }
View Code

29、流程控制,实现 fizzBuzz 函数,参数 num 与返回值的关系如下:
  1、如果 num 能同时被 3 和 5 整除,返回字符串 fizzbuzz
  2、如果 num 能被 3 整除,返回字符串 fizz
  3、如果 num 能被 5 整除,返回字符串 buzz
  4、如果参数为空或者不是 Number 类型,返回 false
  5、其余情况,返回参数 num

  输入:15

  输出:fizzbuzz

//解法1:
function fizzBuzz(num) {
 if(isNaN(num)){
        return false;
    }
    var str='';
    if(num%3===0){
        str+='fizz';
    }
    if(num%5===0){
        str+='buzz';
    }
    return str||num;
}
//解法2:
function fizzBuzz(num) {
    if(typeof num != 'number'){
        return false;
    }else{
        return (num%3 == 0 && num%5 ==0) ? 'fizzbuzz' :(num%3 == 0 ? 'fizz' :(num%5 == 0 ? 'buzz':num));
    }
}
View Code

30、函数传参,将数组 arr 中的元素作为调用函数 fn 的参数

  输入:function (greeting, name, punctuation) {return greeting + ', ' + name + (punctuation || '!');}, ['Hello', 'Ellie', '!']

  输出:Hello, Ellie!

//解法1:...
function argsAsArray(fn, arr) {
    return fn(...arr)
}
//解法2:apply
function argsAsArray(fn, arr) {
 return fn.apply(this,arr);
}
//解法3:call
function argsAsArray(fn, arr) {
   return fn.call(this, ...arr);
}
//解法4:bind
function argsAsArray(fn, arr) {
    return fn.bind(this, ...arr)();
}
View Code

31、函数的上下文,将函数 fn 的执行上下文改为 obj 对象

  输入:function () {return this.greeting + ', ' + this.name + '!!!';}, {greeting: 'Hello', name: 'Rebecca'}

  输出:Hello, Rebecca!!!

//apply
function speak(fn, obj) {
    return fn.apply(obj);
}
//call
function speak(fn, obj) {
    return fn.call(obj);
}
//bind
function speak(fn, obj) {
    return fn.bind(obj)();
}
View Code

32、返回函数,实现函数 functionFunction,调用之后满足如下条件:
  1、返回值为一个函数 f
  2、调用返回的函数 f,返回值为按照调用顺序的参数拼接,拼接字符为英文逗号加一个空格,即 ', '
  3、所有函数的参数数量为 1,且均为 String 类型  

  输入:functionFunction('Hello')('world')

  输出:Hello, world

//解法1:
function functionFunction(str) {
    var f = function(s){
         return str+", "+s;
     }
     return f;
}
//解法2:
function functionFunction(str) { 
    return function(anotherStr){
        return str+', '+anotherStr;
    }
}
//解法3:
function functionFunction(str) {
    var args = Array.prototype.slice.call(arguments)
    return function(){
        return args.concat(Array.prototype.slice.call(arguments)).join(', ')
    }
}
View Code

33、使用闭包,实现函数 makeClosures,调用之后满足如下条件:
  1、返回一个函数数组 result,长度与 arr 相同
  2、运行 result 中第 i 个函数,即 result[i](),结果与 fn(arr[i]) 相同

  输入:[1, 2, 3], function (x) {  return x * x;}

  输出:4

//解法1:
function makeClosures(arr, fn) { 
    var result=new Array();
    for(i=0;i<arr.length;i++){
        result[i]=function(num){
           return function(){
               return fn(num)
           } 
        }(arr[i]);
    }
    return result;
}
//解法2:
function makeClosures(arr, fn) {
    let result = []
    for(let i = 0;i < arr.length; i++) {
        result[i] = fn.bind(this,arr[i])
    }
    return result
}
//解法3:
function makeClosures(arr, fn) {
    const newArr = []
    arr.forEach(item=>{
        newArr.push(()=>{
            return fn(item)
        })
    })
    return newArr
}
View Code

34、二次封装函数,已知函数 fn 执行需要 3 个参数。请实现函数 partial,调用之后满足如下条件:
  1、返回一个函数 result,该函数接受一个参数
  2、执行 result(str3) ,返回的结果与 fn(str1, str2, str3) 一致

  输入:var sayIt = function(greeting, name, punctuation) { return greeting + ', ' + name + (punctuation || '!'); }; partial(sayIt, 'Hello', 'Ellie')('!!!');

  输出:Hello, Ellie!!!

// call
function partial(fn, str1, str2) {
    function result(str3) {
        return fn.call(this, str1, str2, str3);
    } 
     return result;
} 
// apply
function partial(fn, str1, str2) {
    function result(str3) {
        return fn.apply(this, [str1, str2, str3]);
    } 
    return result;
} 
//bind
function partial(fn, str1, str2) {
    return fn.bind(this, str1, str2); 
}
//匿名函数
function partial(fn, str1, str2) {
     return function(str3) {
            return fn.call(this, str1, str2, str3);
     }  
}
View Code

35、使用arguments,函数 useArguments 可以接收 1 个及以上的参数。请实现函数 useArguments,返回所有调用参数相加后的结果。本题的测试参数全部为 Number 类型,不需考虑参数转换。

  输入:1,2,3,4

  输出:10

//解法1:slice call
function useArguments() {
 var arr=Array.prototype.slice.call(arguments)//把arguments类数组转化为数组
    return eval(arr.join("+"));//求和
}
//解法2:reduce call
function useArguments() {
 var result = Array.prototype.reduce.call(arguments,function(a,b){return a+b;});
    return result;
}
//解法3:...
function useArguments() {
    return [...arguments].reduce((a,b)=>a+b)
}
View Code

36、使用apply调用函数,实现函数 callIt,调用之后满足如下条件
  1、返回的结果为调用 fn 之后的结果
  2、fn 的调用参数为 callIt 的第一个参数之后的全部参数

  输入:无

  输出:无

//解法1:
function callIt(fn) {
     return fn.apply(this,[].slice.call(arguments,1));
}
//解法2:
function callIt(fn) {
    return fn.apply(this, [ ...arguments].slice(1));
}
View Code

37、柯里化,已知 fn 为一个预定义函数,实现函数 curryIt,调用之后满足如下条件:
  1、返回一个函数 a,a 的 length 属性值为 1(即显式声明 a 接收一个参数)
  2、调用 a 之后,返回一个函数 b, b 的 length 属性值为 1
  3、调用 b 之后,返回一个函数 c, c 的 length 属性值为 1
  4、调用 c 之后,返回的结果与调用 fn 的返回值一致
  5、fn 的参数依次为函数 a, b, c 的调用参数

  输入:var fn = function (a, b, c) {return a + b + c}; curryIt(fn)(1)(2)(3);

  输出:6

//解法1:
function curryIt(fn) {
     var arr=[],l = fn.length;
     return function(x){ 
        arr.push(x);
        return arr.length < l ? arguments.callee : fn.apply(null,arr);
      }
}
//解法2:
function curryIt(fn) {
     return (a)=>(b)=>(c)=>fn(a,b,c);
}
View Code

38、模块,完成函数 createModule,调用之后满足如下要求:
  1、返回一个对象
  2、对象的 greeting 属性值等于 str1, name 属性值等于 str2
  3、对象存在一个 sayIt 方法,该方法返回的字符串为 greeting属性值 + ', ' + name属性值

//解法1:
function createModule(str1, str2) {
 var obj =
            {
                greeting : str1,
                name : str2,
                sayIt : function(){return this.greeting + ", " + this.name;}
            };
    return obj; 
}
//使用构造函数法
function createModule(str1, str2) {
    function Obj(){
        this.greeting = str1;
        this.name = str2;
        this.sayIt = function(){
            return this.greeting + ', ' + this.name;
        };
    }
    return new Obj();
}
//构造函数与原型组合
function createModule(str1, str2) {
    function CreateMod(){
        this.greeting = str1;
        this.name = str2;
    }
    CreateMod.prototype.sayIt = function(){
        return this.greeting + ', '  + this.name;
    }
    return new CreateMod();
}
View Code

39、二进制转换,获取数字 num 二进制形式第 bit 位的值。注意:
  1、bit 从 1 开始
  2、返回 0 或 1
  3、举例:2 的二进制为 10,第 1 位为 0,第 2 位为 1

  输入:128,8

  输出:1

//解法1:
function valueAtBit(num, bit) {
     return (num >> (bit -1)) & 1;
}
//解法2:
function valueAtBit(num, bit) {
    //toString转化为二进制,split将二进制转化为数组,reverse()将数组颠倒顺序
    var arr = num.toString(2).split("").reverse();
    return arr[bit-1];
}
//解法3:
//用第bit位与的方法:
function valueAtBit(num, bit) {
    var result = num & Math.pow(2, bit-1);
    return result? 1 : 0;
}
View Code

40、二进制转换十进制

  输入:'11000000'

  输出:192

//解法1:
function base10(str) {
    /**
        其它进制转十进制
        parseInt(str,2)
        parseInt(str,8)
        parseInt(str,16)
    */
    return parseInt(str,2);
}
//解法2:
function base10(str) {
    return str.split('').reduce(function(total,value,index){
        return total + (value << (str.length - 1 - index));
    },0);
}
//解法3:
function base10(str) {
     return Number('0b'+str);
}
View Code

41、二进制转换,将给定数字转换成二进制字符串。如果字符串长度不足 8 位,则在前面补 0 到满8位。

  输入:65

  输出:01000001

//解法1:
function convertToBinary(num) {
    var str = num.toString(2);
    while(str.length < 8) {
        str = "0" + str;
    }
     
    return str;
}
//解法2:
function convertToBinary(num) {
    var toBit = num.toString(2); 
    return  ( toBit / Math.pow(10, 8) ).toFixed(8).substr(2);
}
//解法3:
function convertToBinary(num) {
    return ("00000000" + num.toString(2)).slice(-8)
}
View Code

 42、乘法,求 a 和 b 相乘的值,a 和 b 可能是小数,需要注意结果的精度问题

  输入:3, 0.0001

  输出:0.0003

//解法1:
function multiply(a, b) {
   return parseFloat((a*b).toFixed(10));
}
//解法2:
function multiply(a, b) {
    return Number((a*b).toFixed(4));
}
View Code

43、改变上下文,将函数 fn 的执行上下文改为 obj,返回 fn 执行后的值

  输入:alterContext(function() {return this.greeting + ', ' + this.name + '!'; }, {name: 'Rebecca', greeting: 'Yo' })

  输出:Yo, Rebecca!

//解法1:bind
function alterContext(fn, obj) {
  return fn.bind(obj)(); }
//解法2:call
function alterContext(fn, obj) {
  return fn.call(obj);
}
//解法3:apply
function alterContext(fn, obj) {
  return fn.apply(obj);
}
View Code

44、批量改变对象的属性,给定一个构造函数 constructor,请完成 alterObjects 方法,将 constructor 的所有实例的 greeting 属性指向给定的 greeting 变量。

  输入:var C = function(name) {this.name = name; return this;}; var obj1 = new C('Rebecca');alterObjects(C, 'What\'s up'); obj1.greeting;

  输出:What's up

//解法1:
function alterObjects(constructor, greeting) {
    constructor.prototype.greeting = greeting;
}
//解法2:
function alterObjects(constructor, greeting) {
        // 防止属性屏蔽失败
    Object.defineProperty(constructor.prototype, "greeting", {
        value: greeting
    });
}
View Code

45、属性遍历,找出对象 obj 不在原型链上的属性(注意这题测试例子的冒号后面也有一个空格~)
  1、返回数组,格式为 key: value
  2、结果数组不要求顺序

  输入:var C = function() {this.foo = 'bar'; this.baz = 'bim';}; C.prototype.bop = 'bip'; iterate(new C());

  输出:["foo: bar", "baz: bim"]

//解法1:
function iterate(obj) {
     return Object.getOwnPropertyNames(obj).map(function(key){
        return key+": "+obj[key];
    });
}
//解法2:
function iterate(obj) {
    return Object.keys(obj).map(function(key) {
        return key + ": " + obj[key];
    });
}
View Code

 46、一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

//解法1
function jumpFloor(number)
{ 
    let a = 1
    let b = 2
    let i = 1
    while(i++ < number){
        [a,b] = [b,a+b]
    }
    return a
}
module.exports = {
    jumpFloor : jumpFloor
};
//解法2
function jumpFloor(number)
{
    // write code here
    let st1 = 1
    let st2 = 2
    if (number==1 || number==2) {
        return number
    }
    for (let i=2;i<number;i++) {
        let temp = st2
        st2 +=st1
        st1 = temp
    }
    return st2
}
module.exports = {
    jumpFloor : jumpFloor
};
View Code

47、链表中的节点每K个一组翻转,将给出的链表中的节点每\ k k 个一组翻转,返回翻转后的链表,如果链表中的节点数不是\ k k 的倍数,将最后剩下的节点保持原样,你不能更改节点中的值,只能更改节点本身。要求空间复杂度  O(1)

  输入:{1,2,3,4,5},2

  输出:{2,1,4,3,5}

//解法1:
function reverseKGroup( head ,  k ) {
    let pre = null,cur = head;
    let p = head;
    //查找长度是否满足反转的数量
    for(let i = 0;i<k;i++){
        if(p == null) return head;
        p = p.next;
    }
    //对该k个链表元素进行反转
    for(let j = 0;j<k;j++){
        let temp = cur.next;
        cur.next = pre;
        pre = cur;
        cur = temp;
    }
    //反转后。head.next已经成为当前反转后链表的最后一个元素,它的指向将是下一个递归的开始点
    //而此时pre已经是最后一个元素,cur是下一个范围的第一元素
    head.next = reverseKGroup(cur,k);
    return pre;
}
module.exports = {
    reverseKGroup : reverseKGroup
};
View Code

48、子数组的最大累加和问题,给定一个数组arr,返回子数组的最大累加和,例如,arr = [1, -2, 3, 5, -2, 6, -1],所有子数组中,[3, 5, -2, 6]可以累加出最大的和12,所以返回12,题目保证没有全为负数的数据,[要求]时间复杂度为O(n),空间复杂度为O(1)

  输入:[1,-2,3,5,-2,6,-1]

  输出:12

//解法1:
function maxsumofSubarray( arr ) {
    // write code here
    var max=0;
    var value=0;
    for(var i=0;i<arr.length;i++){
        if(value<0)value=0
        value+=arr[i];
        if(value>max)
            max=value;
    }
    return max;
}
View Code

49、最长无重复子数组,给定一个数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组

  输入:[2,3,4,5]                    [2,2,3,4,3]

  输出:4          3 

//解法1
function maxLength( arr ) {
    var map = new Map(), max = 0, start = 0
    for(let i = 0; i < arr.length; i++) {
        if(map.has(arr[i])) {
            start = Math.max(map.get(arr[i]) + 1 , start)
        }
        map.set(arr[i], i)
        max = Math.max(max, i - start + 1)
    }
    return max
}
View Code

50、判断链表中是否有环,判断给定的链表中是否有环。如果有环则返回true,否则返回false。你能给出空间复杂度的解法么?

//解法1:
function hasCycle( head ) {
   if (head == null) return false; 
    let slow = head;
    let fast = head;
    while (fast && fast.next) {
        slow = slow.next;
        fast = fast.next.next;
        if (slow == fast) return true;
    }
    return false;
}
//解法2:
function hasCycle( head ) {
    if (!head || !head.next) return false;
    let slow = head,
        fast = head.next.next;
    while (fast && fast.next){
        if(slow === fast) return true;
        slow = slow.next;
        fast = fast.next.next;
    }
    return false;
}
View Code

 51、合并两个有序数组,给出两个有序的整数数组 和 ,请将数组 合并到数组 中,变成一个有序的数组,注意: 可以假设 数组有足够的空间存放 数组的元素, 和 中初始的元素数目分别为 和 

function merge( A, m, B, n ) { 
    if (n === 0) return A
    A.push(...B)
    return A.sort((a, b) => (a - b))
}
View Code

52、链表中环的入口节点,对于一个给定的链表,返回环的入口节点,如果没有环,返回null,你能给出不利用额外空间的解法么?

function detectCycle( head ) {
  while(head){
        if(head.flag){
            return head;
        }
        head.flag = true;
        head = head.next
    }
}
View Code

53、括号序列,给出一个仅包含字符'(',')','{','}','['和']',的字符串,判断给出的字符串是否是合法的括号序列,括号必须以正确的顺序关闭,"()"和"()[]{}"都是合法的括号序列,但"(]"和"([)]"不合法。

  输入:"["                        "[ ]"

  输出:false                    true

//解法1
function isValid( s ) {
    if (s.length % 2) return false; 
    const queue = [];
    const map = {
        ']': '[',
        ')': '(',
        '}': '{',
    };
    const left = Object.values(map);
    for (let i = 0; i < s.length; i++) {
        if (left.includes(s[i])) {
            queue.push(s[i]);
        } else {
            if (map[s[i]] !== queue.pop()) return false;
        }
    }
    return queue.length === 0;
}
//解法2
function isValid( s ) { 
     var result = []
    for(var i = 0 ; i < s.length ; i++){
        //其实是对数组进步性判断
         
        result.push(s[i])
        if(result.slice(result.length -2).join("")=="()" || result.slice(result.length -2).join("")=="[]" ||result.slice(result.length -2).join("")=="{}"){
            result.pop()
            result.pop()
        }
    }
    return result.length==0
}
View Code

54、删除链表的倒数第n个节点,给定一个链表,删除链表的倒数第 nn 个节点并返回链表的头指针,给出的链表为: 1\to 2\to 3\to 4\to 512345, n= 2n=2,删除了链表的倒数第 nn 个节点之后,链表变为1\to 2\to 3\to 51235.

  输入:{1,2},2

  输出:{2}

function removeNthFromEnd( head ,  n ) {
     let fast = head, slow = head;
    while(n--) {
        fast = fast.next;
    }
    if(fast == null)
        return head.next;
    while(fast.next) {
        fast = fast.next;
        slow = slow.next;
    }
    slow.next = slow.next.next;
    return head;
}
View Code

 

posted @ 2021-04-07 10:52  ৢ清欢ꦿ✿  阅读(367)  评论(0编辑  收藏  举报