美文网首页
收集整理一些JS算法以及解题思路

收集整理一些JS算法以及解题思路

作者: 杭州朱亚文 | 来源:发表于2019-07-19 15:41 被阅读0次

    脑袋不用就会变得愚钝,所以我觉得还是有必要偶尔动动自己的脑子。增强自己的逻辑性,对业务上也是有一定帮助的。持续更新,希望大家能够喜欢,然后关注!各个题目大家可以自己先去尝试做一下,然后在对比我的解题思路,如果有好的,欢迎分享!可能有些解题思路感觉很傻很蠢很吃力,但是对于有些人可能会碰撞出不同的火花;有不正确的地方欢迎指正;

    问题一:

    写一个 function,它遍历一个对象数组(第一个参数)并返回一个包含相匹配的属性-值对(第二个参数)的所有对象的数组。如果返回的数组中包含 source 对象的属性-值对,那么此对象的每一个属性-值对都必须存在于 collection 的对象中。例如,如果第一个参数是 [{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }],第二个参数是 { last: "Capulet" },那么你必须从数组(第一个参数)返回其中的第三个对象,因为它包含了作为第二个参数传递的属性-值对。

    测试数据:

    where([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" })
    应该返回[{ first: "Tybalt", last: "Capulet" }]。
    where([{ "a": 1 }, { "a": 1 }, { "a": 1, "b": 2 }], { "a": 1 }) 应该返回 [{ "a": 1 }, { "a": 1 }, { "a": 1, "b": 2 }]。
    
    where([{ "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 2 }], { "a": 1, "b": 2 }) 应该返回 [{ "a": 1, "b": 2 }, { "a": 1, "b": 2, "c": 2 }]。
    
    where([{ "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 2 }], { "a": 1, "c": 2 }) 应该返回 [{ "a": 1, "b": 2, "c": 2 }]。
    

    解题一

    function where(collection, source) {
      var arr = [];
      var keyArrNum = [];
      var sourceLength = 0;
      for (var i in source) {
        sourceLength++;
        collection.forEach(function(e, j) {
            if (e.hasOwnProperty(i) && e[i] === source[i]) {
                keyArrNum.push(j)
            }
        });
      }
      for (var z = 0; z < keyArrNum.length; z++) {
        var count = 0;
        for (var x = z; x < keyArrNum.length; x++) {
            if (keyArrNum[z] == keyArrNum[x]) {
                count++
            }
        }
        if (count == sourceLength) {
            arr.push(collection[keyArrNum[z]]);
        }
      }
      return arr;
    }
    where([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" });
    

    解题思路:

    记录source里面有多少key,然后把每个source的key在collection中出现的位置(下标)放入一个数组里keyArrNum;然后循环这个数组里面的值出现的次数和source的key数量是否一致,如果一致就放入arr里!简单粗暴;

    解题二:

    function where1(collection, source) {
      var arr = [];
      var keys = Object.keys(source);
      arr = collection.filter(function(item){
       for (var i = 0; i < keys.length; i++) {
          if ( !item.hasOwnProperty(keys[i]) || item[keys[i]] !== source[keys[i]]) {
            return false;
          }
        }
        return true;
      });
      return arr;
    }
    

    解题思路:

    比解题一更简单直观,但是要大家对数组和对象的方法有所了解;思路大同小异,只是方法不同而已;获取soure的健值数组,然后利用array.filter()方法去检查指定数组中符合条件的所有元素;

    解题三:

    function where1(collection, source) {
      var arr = [];
      var keys = Object.keys(source);
      arr = collection.filter(function(item){
        return keys.every(function(key){
          return item.hasOwnProperty(key) && item[key] === source[key];
        })
      });
      return arr;
    }
    

    解题思路:

    思路和解题二差不多,只是把for循环改成了every()方法,但是从效率上说的话,还是for 循环来的更快些;

    问题二

    我们会传递给你一个包含两个数字的数组。返回这两个数字和它们之间所有数字的和。

    测试数据:

    sumAll([1, 4]) 应该返回一个数字。
    sumAll([1, 4]) 应该返回 10。
    sumAll([4, 1]) 应该返回 10。
    sumAll([5, 10]) 应该返回 45。
    sumAll([10, 5]) 应该返回 45。
    

    解题一:

    function sumAll(arr) {
      var maxNum = Math.max.apply(null, arr);
      var minNum = Math.min.apply(null, arr);
      if (maxNum == minNum) {
        return maxNum + minNum;
      } else {
        var len = maxNum - minNum + 2;
        var num = [];
        for (var i = minNum; num.length < len -1; i++) {
          num.push(i);
        }
        return num.reduce(function(res, index) {
          return res + index;
        }, 0);
      }
    }
    sumAll([1, 4]);
    

    解题思路:

    获取最大值最小值,然后循环得到最大值最小值之间的数组,然后加起来;

    解题二:

    function sumAll(arr) {
      var maxNum = Math.max.apply(null, arr);
      var minNum = Math.min.apply(null, arr);
      if (maxNum == minNum) {
        return maxNum + minNum;
      } else {
        var allNum = 0;
        for (var i = minNum; i <= maxNum; i++) {
         allNum += i;
        }
        return allNum;
      }
    }
    sumAll([1, 4]);
    

    解题思路:

    获取最大值最小值,然后直接循环加起来;
    解题三:

    function sumAll(arr) {
       var max = Math.max.apply(null, arr);
       var min = Math.min.apply(null, arr);
       return (max + min) * (max - min + 1)/2;
    }
    sumAll([1, 4]);
    

    解题思路:
    这个就考到小学算数了。

    问题三

    比较两个数组,然后返回一个新数组,该数组的元素为两个给定数组中所有独有的数组元素。换言之,返回两个数组的差异。

    测试数据

    diff([1, 2, 3, 5], [1, 2, 3, 4, 5]) 应该返回一个数组。
    ["diorite", "andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"] 应该返回 ["pink wool"]。
    ["andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"] 应该返回 ["diorite", "pink wool"]。
    ["andesite", "grass", "dirt", "dead shrub"], ["andesite", "grass", "dirt", "dead shrub"] 应该返回 []。
    [1, 2, 3, 5], [1, 2, 3, 4, 5] 应该返回 [4]。
    [1, "calf", 3, "piglet"], [1, "calf", 3, 4] 应该返回 ["piglet", 4]。
    [], ["snuffleupagus", "cookie monster", "elmo"] 应该返回 ["snuffleupagus", "cookie monster", "elmo"]。
    [1, "calf", 3, "piglet"], [7, "filly"] 应该返回 [1, "calf", 3, "piglet", 7, "filly"]。
    

    解题一:

    
    function diff(arr1, arr2) {
        var newArr = [];
        var arr = arr1.concat(arr2);
        for (var i = 0; i < arr.length; i++) {
            var count = 0;
            for (var j = 0; j < arr.length; j++) {
                if (arr[i] !== arr[j]) {
                    count++;
                }
                
            }
            if (count == arr.length -1) {
                newArr.push(arr[i]);
            }
         }
        return newArr;
    }
    
    diff([1, 2, 3, 5], [1, 2, 3, 4, 5]);
    

    解题思路:

    合并2个数组为arr,然后计算每个值在这个arr里未出现次数。

    解题二:

    function diff1(arr1, arr2) {
        var newArr = [];
        var diffArr1 = [];
        var diffArr2 = [];
        diffArr1 = arr1.filter(function (item) {
            return arr2.indexOf(item) == -1;
        })
        diffArr2 = arr2.filter(function (item) {
            return arr1.indexOf(item) == -1;
        })
        newArr = diffArr1.concat(diffArr2)
        return newArr;
    }
    

    解题思路:

    塞选出另一个数组的元素不存在这个数组里,然后合并返回;

    问题四:

    将给定的数字转换成罗马数字。
    所有返回的 罗马数字 都应该是大写形式。可参考Roman Numerals;

    测试数据:

    convert(2) 应该返回 "II"。
    convert(3) 应该返回 "III"。
    convert(4) 应该返回 "IV"。
    convert(5) 应该返回 "V"。
    convert(9) 应该返回 "IX"。
    convert(12) 应该返回 "XII"。
    convert(16) 应该返回 "XVI"。
    convert(29) 应该返回 "XXIX"。
    convert(44) 应该返回 "XLIV"。
    convert(45) 应该返回 "XLV"。
    convert(68) 应该返回 "LXVIII"。
    convert(83) 应该返回 "LXXXIII"。
    convert(97) 应该返回 "XCVII"。
    convert(99) 应该返回 "XCIX"。
    convert(500) 应该返回 "D"。
    convert(501) 应该返回 "DI"。
    convert(649) 应该返回 "DCXLIX"。
    convert(798) 应该返回 "DCCXCVIII"。
    convert(891) 应该返回 "DCCCXCI"。
    convert(1000) 应该返回 "M"。
    convert(1004) 应该返回 "MIV"。
    convert(1006) 应该返回 "MVI"。
    convert(1023) 应该返回 "MXXIII"。
    convert(2014) 应该返回 "MMXIV"。
    convert(3999) 应该返回 "MMMCMXCIX"。
    

    解题思路一:

    为什么没有写解题一呢?主要是解题一特别繁杂,代码量大,属于那种实在想不出解题办法,然后用最笨的办法一个一个换算的,大体解题思路就是:把各个情况都判断一遍,算出个位、十位、百位、千位,然后组合起来返回;这种办法吃力不讨好,但是不乏有很多人这么解题的,主要是没思路;

    解题二:

    function convent(num) {
        var arr = [
            ["","I","II","III","IV","V","VI","VII","VIII","IX"], //个位
            ["","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"], //十位
            ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"], //百位
            ["", "M", "MM", "MMM"],//千位
        ]
        return num.toString().split('').reverse().map((value, i) => {
            return arr[i][value]
        }).reverse().join('')
    };
    

    解题思路:

    这个很清晰明了,它是直接列出了所有情况,然后匹配;
    当然还有其他类似的思路

    function convert(num) {
        var a = [["","I","II","III","IV","V","VI","VII","VIII","IX"],
            ["","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"],
            ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"],
            ["","M","MM","MMM"]
        ];
        var i = a[3][Math.floor(num/1000)];
        var j = a[2][Math.floor(num%1000/100)];
        var k = a[1][Math.floor(num%100/10)];
        var l = a[0][num%10];
        return i + j + k + l;
    
    }
    

    其实思路都是差不多,只是有的人能举一反三,有的人困死在一个逻辑误区里,脑袋要多动,才不会生锈。

    问题五:

    第一个参数是将要对其执行查找和替换的句子。

    第二个参数是将被替换掉的单词(替换前的单词)。

    第三个参数用于替换第二个参数(替换后的单词)。

    注意:替换时保持原单词的大小写。例如,如果你想用单词 "dog" 替换单词 "Book" ,你应该替换成 "Dog"。

    测试数据:

    myReplace("Let us go to the store", "store", "mall") 应该返回 "Let us go to the mall"。
    myReplace("He is Sleeping on the couch", "Sleeping", "sitting") 应该返回 "He is Sitting on the couch"。
    myReplace("This has a spellngi error", "spellngi", "spelling") 应该返回 "This has a spelling error"。
    myReplace("His name is Tom", "Tom", "john") 应该返回 "His name is John"。
    myReplace("Let us get back to more Coding", "Coding", "algorithms") 应该返回 "Let us get back to more Algorithms"。
    

    解题一:

    function myReplace(str, before, after) {
        if ((/^[A-Z]/).test(before.charAt(0))) {
            after = after.replace(after.charAt(0), after.charAt(0).toUpperCase())
        } else {
            after = after.replace(after.charAt(0), after.charAt(0).toLowerCase())
        }
        str = str.replace(before, after)
        return str;
    }
    
    myReplace("A quick brown fox jumped over the lazy dog", "jumped", "leaped");
    

    解题思路:

    首先验证要替换的首字母是大小写,然后替换;

    解题二:

    
    function myReplace1(str, before, after) {
        var strArr = str.split(' ')
        var replaceStr = '';
        var afterArr = after.split('');
        if ((/^[A-Z]/).test(before.charAt(0))) {
            replaceStr = afterArr[0].toUpperCase();
        } else {
            replaceStr = afterArr[0].toLowerCase();
        }
        replaceStr += afterArr.slice(1, afterArr.length).join('');
        for (var i = 0; i < strArr.length; i++) {
            if (strArr[i] === before) {
                strArr[i] = replaceStr;
                return strArr.join(" ");
            }
        }
    }
    console.log(myReplace1("A quick brown fox Jumped over the lazy dog", "Jumped", "leaped"))
    

    解题思路:

    把要替换的str变成数组,然后循环替换,不过还是要对比首字母是否大写,只是把直接替换变成了循环替换;当然方法还有很多,但是大致方向是这样的;

    问题四:

    从传递进来的字母序列中找到缺失的字母并返回它。
    如果所有字母都在序列中,返回 undefined。

    测试数据:

    fearNotLetter("abce") 应该返回 "d"。
    fearNotLetter("abcdefghjklmno") 应该返回 "i"。
    fearNotLetter("bcd") 应该返回 undefined。
    fearNotLetter("yz") 应该返回 undefined。
    

    解题一:

    var a = "abcdefghijklmnopqrstuvwxyz";
      var len = str.length;
      var start = a.indexOf(str.charAt(0));
      var end = a.indexOf(str.charAt(len - 1));
      var num = end - start + 1;
      if (len == num) {
            return undefined
      } else {
        var selectArr = a.substr(start, end)
        for (var i = 0; i < selectArr.length; i++) {
            if (str.indexOf(selectArr[i]) == -1) {
                return selectArr[i];
            }
          }
      }
    fearNotLetter("bcdfg")
    

    解题思路:

    找到字符串在全部字母表里的位置,然后一一匹配就好了;
    解题二:

    function fearNotLetter(str) {
     for(var i = 0, len = str.length; i < len; i++){
       var cha = str.charCodeAt(i + 1) - str.charCodeAt(i);
       if(cha > 1){
         return String.fromCharCode(str.charCodeAt(i) + 1);
       }
     }
      return undefined;
    }
    fearNotLetter("abce");
    

    解题思路:

    对字符串进行遍历,连续两个字母的charCode进行相减,如果大于1,则说明这两个字母不是相邻的,返回较小字母的下一个字母即可,如果所有字母都在序列中,返回 undefined。主要用到的方法有:String.charCodeAt()---返回值是一表示给定索引处字符的 UTF-16 代码单元值的数字,静态 String.fromCharCode() 方法返回使用指定的Unicode值序列创建的字符串。

    问题五:

    斐波纳契数列中的前几个数字是 1、1、2、3、5 和 8,随后的每一个数字都是前两个数字之和。

    例如,sumFibs(4)应该返回 5,因为斐波纳契数列中所有小于4的奇数是 1、1、3。

    测试数据:

    sumFibs(1) 应该返回一个数字。
    sumFibs(1000) 应该返回 1785。
    sumFibs(4000000) 应该返回 4613732。
    sumFibs(4) 应该返回 5。
    sumFibs(75024) 应该返回 60696。
    sumFibs(75025) 应该返回 135721。
    

    解题一:

    function sumFibs(num) {
        var arr = [],
        maxNum = 1,
        acount = 0;
        while (maxNum <= num) {
            if (maxNum % 2 != 0) {
                acount += maxNum;
            }
            arr.push(maxNum);
            if (arr.length < 2) {
                maxNum = 1;
            } else {
                maxNum = arr[arr.length -1] + arr[arr.length -2];
            }
        }
      return acount;
    }
    

    解题思路:

    本来想递归的,但是如果数据过多会溢出,所以用这种形式;

    问题六:

    求小于等于给定数值的质数之和。

    只有 1 和它本身两个约数的数叫质数。例如,2 是质数,因为它只能被 1 和 2 整除。1 不是质数,因为它只能被自身整除。

    给定的数不一定是质数。

    测试数据:

    sumPrimes(10) 应该返回一个数字。
    sumPrimes(10) 应该返回 17。
    sumPrimes(977) 应该返回 73156。
    

    解题一:

    
    function sumPrimes(num) {
        var isPrimeArr = []; 
        var isPrimeAcount = 0;
        for (var i = 2; i <= num; i++) {
            var isPrimeNum = true;
            for (var j = 2; j < i; j++) {
                if (i % j ==0) {
                    isPrimeNum = false;
                }
            }
            if (isPrimeNum) {
                isPrimeAcount += i;
            }
        }
      return isPrimeAcount;
    }
    

    解题思路:

    一般的判断条件写作循环2到他本身,而求小于等于给定数值的质数之和只需要从2循环到他本身即可

    问题七:

    找出能被两个给定参数和它们之间的连续数字整除的最小公倍数。

    范围是两个数字构成的数组,两个数字不一定按数字顺序排序。

    例如对 1 和 3 —— 找出能被 1 和 3 和它们之间所有数字整除的最小公倍数。

    测试数据:

    smallestCommons([1, 5]) 应该返回一个数字。
    smallestCommons([1, 5]) 应该返回 60。
    smallestCommons([5, 1]) 应该返回 60。
    smallestCommons([1, 13]) 应该返回 360360。
    

    解题:

    function smallestCommons(arr) {
        var numArr = [];
        var isArr = [];
        var obj = [], count = 0;
        var maxNum = Math.max.apply(null, arr);
        var minNum = Math.min.apply(null, arr) > 1 ? Math.min.apply(null, arr) : 2;
        for (var i = minNum; i <= maxNum; i++) {
            numArr.push(i)
        }
        function fu (nums) {
            if (nums ==1 ){
                count++;
                return
            }
            for (var j = 2; j <= nums; j++) {
                if (nums % j == 0) {
                    if (!obj[count]) {
                        obj[count] = [];
                    }
                        obj[count].push(j)
                        fu(nums / j);
                        break;
                }
            }
        }
    
        for (var j = 0; j < numArr.length; j++) {
            fu(numArr[j]);
        }
        var allArr = [];
        for (var k = 0; k < obj.length; k++) {
            for (var z = 0; z < obj[k].length; z++) {
                allArr.push(obj[k][z]);
                for(var x = k + 1; x < obj.length; x++) {
                    if (obj[x].indexOf(obj[k][z]) !== -1) {
                        obj[x].splice(obj[x].indexOf(obj[k][z]), 1)
                    }
                }
            }
        }
        var result = 1;
      for(i = 0; i < allArr.length; i++){
        result *= allArr[i];
      }
      return result;
    }
    

    解题思路:

    先获取2个数之间的所有数的数组,然后递归获取每个元素的质因数,最后找出公共质因数相乘;

    问题八

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

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

    测试数据:

    permAlone("aab") 应该返回一个数字.
    permAlone("aab") 应该返回 2.
    permAlone("aaa") 应该返回 0.
    permAlone("aabb") 应该返回 8.
    permAlone("abcdefa") 应该返回 3600.
    permAlone("abfdefa") 应该返回 2640.
    permAlone("zzzzzzzz") 应该返回 0.
    

    解题:

    function permAlone(str){
      var reg = str.match(/(.)\1+/g);
      if (reg !== null && reg[0] == str) {
        return 0;
      }
      var arr = str.split('');
      var arrys = [];
      digui(arr, 0, arr.length);
      function digui(arr, start, end){
        if (start == end) {
          retrun arrys.push(arr.join(''));
        }
        for (var i = start; i < end; i++) {
          again(arr, start, i);
          digui(arr, start + 1, end);
          again(arr, start, i);
        }
      }
      function again(arr, start, end) {
        var temp  = arr[start];
        arr[start] = arr[end];
        arr[end] = temp;
      }
      return arrys.filter(function(item){
        return !item.match(/(.)\1+/g);
      }).length;
    }
    

    解题思路:

    先正则匹配,然后递归全排列,最后塞选出需要的;如果大家看不懂可以去了解下递归;这题是有点难度的;接下来,难度在升级一下,就是在这个基础上去重;大家想想在加入一些什么条件才能满足;不知道的看下我下面的代码;

    解题:

    function permAlone(str){
      var reg = str.match(/(.)\1+/g);
      if (reg !== null && reg[0] == str) {
        return 0;
      }
      var arr = str.split('');
      var arrys = [];
      digui(arr, 0, arr.length);
      function digui(arr, start, end){
        if (start == end) {
          retrun arrys.push(arr.join(''));
        }
        for (var i = start; i < end; i++) {
          if(!same(arr, start, i)) {
            continue;
          }
          again(arr, start, i);
          digui(arr, start + 1, end);
          again(arr, start, i);
        }
      }
      function again(arr, start, end) {
        var temp  = arr[start];
        arr[start] = arr[end];
        arr[end] = temp;
      }
      function same(arr, start, end) {
        for (var k = start; k < end; k++) {
            if (arr[k] === arr[end]) {
              return false;
            }
         }
        return true;
      }
      return arrys.filter(function(item){
        return !item.match(/(.)\1+/g);
      }).length;
    }
    

    `

    相关文章

      网友评论

          本文标题:收集整理一些JS算法以及解题思路

          本文链接:https://www.haomeiwen.com/subject/jiqslctx.html