资讯专栏INFORMATION COLUMN

前端面试中常遇到的算法题及考察点

Jochen / 1906人阅读

摘要:重点是检测到空格时进行处理。使用实现二叉查找树一般叫全部写完的概率比较少,但是重点考察你对它的理解和一些基本特点的实现。二叉查找树相比于其他数据结构的优势在于查找插入的时间复杂度较低。统计数组中每个元素及出现的次数,并输出到页面

【灵活应对前端面试中的JS算法题】

实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制

    function clone(obj){
        var result;
        switch(typeof obj){
            case "undefined":
            break;
            case "string":
            result = obj+"";
            break;
            case "number":
            result = obj-0;
            break;
            case "boolean":
            result =obj;
            break;
            case "object":
                if(obj ===null){
                    result = null;
                } else {
                    if(Object.prototype.toString.call(obj).slice(8,-1)==="Array"){
                        result=[];
                        for(var i=0;i

判断一个单词是否是回文

回文是指把相同的词汇或句子,在下文中调换位置或颠倒过来,产生首尾回环的情趣,叫做回文,也叫回环。

很多人拿到这样的题目非常容易想到用for将字符串颠倒字母顺序然后匹配就行了。其实重要的考察的是对于reverse的实现。其实我们可以利用现成的函数,将字符串转换成数组,这个思路很重要,我们可以拥有更多的自由度去进行字符串的一些操作。
let reverseStr = function(str) {  
    return str = str.split("").reverse().join("");
}
reverseStr("abcdefg");
//gfedcba

在句子中反转词

如fix this one 变为 one this fix。重点是检测到空格时进行处理。

    function reverseWord(str){
        return str.split(" ").reverse().join(" ")
    }

反转每个单词中字符的顺序

“I am the good boy” 反转成这样 “I ma eht doog yob”

    function reverse(str){
        return str.split(" ").reverse().join(" ").split("").reverse().join("");
    }

去掉一组整型数组重复的值

题目如下输入: [3,13,24,11,11,14,1,2]
输出: [3,13,24,11,14,2]
需要去掉重复的11 和 1 这两个元素。

这道题有多重方法,我理解的主要是考察个人对Object的使用,利用key来进行筛选。
    function unique(arr) {  
        let hashTable = {};
        let data = [];
        for(let i=0,l=arr.length;i

再来一个其他实现方式,这个方法常在我的项目中出现,用的时候确实觉得代码少了那么几行

     function unique(arr) {  
        let data = [];
        for(let i=0,l=arr.length;i

统计一个字符串出现最多的字母

输入一段英文连续的英文字符串 afjghdfraaaasdenas,找出重复出现次数最多的字母

    function findMaxChar(str) {  
          if(str.length == 1) {
            return str;
          }
          let charObj = {};
          for(let i=0;i= maxValue) {
              maxChar = k;
              maxValue = charObj[k];
            }
         }
         return maxChar;
     }
     findMaxChar("afjghdfraaaasdenas")
    //a

找到字符串中的第一个非重复的字符

遍历字符串,用一个对象当做hash表来存储重复字符。

    function firstNonRepeatChar(str){
        var count = {};
        for(var i=0;i

删除字符串中重复的字符

其实是在上一个问题的基础上再进行操作:

    function firstNonRepeatChar(str){
        var count = {};
        var result = [];
        for(var i=0;i

在n和m之间生成随机整数

    Math.floor(Math.random()*(m-n))+n

排序算法(冒泡排序)

冒泡排序JavaScript代码实现:

    function bubbleSort(arr) {
        var len = arr.length;
        for (var i = 0; i < len; i++) {
            for (var j = 0; j < len - 1 - i; j++) {
                if (arr[j] > arr[j+1]) {        //相邻元素两两对比
                    var temp = arr[j+1];        //元素交换
                    arr[j+1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        return arr;
    }
    bubbleSort([3,5,2,8,9,7,6])
    //[2, 3, 5, 6, 7, 8, 9]

排序算法(选择排序)

在时间复杂度上表现最稳定的排序算法之一,因为无论什么数据进去都是O(n²)的时间复杂度。。。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。
    function selectionSort(arr) {
        var len = arr.length;
        var minIndex, temp;
        for (var i = 0; i < len - 1; i++) {
            minIndex = i;
            for (var j = i + 1; j < len; j++) {
                if (arr[j] < arr[minIndex]) {     //寻找最小的数
                    minIndex = j;                 //将最小数的索引保存
                }
            }
            temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
        return arr;
    }
     selectionSort([3,5,2,8,9,7,6])
    //[2, 3, 5, 6, 7, 8, 9]

从未排序的整数数组中找出缺失的数字

比如你有1到100的整数,而其中缺了一个,怎么找出这个数字?利用等差数列公式计算这些数应得的和,再计算当前数组所有数字的和,二者的差即为缺少的数。

    function missingNumber(arr){
        var n = arr.length+1;
        var expectedSum = (1+n)*n/2;
        var sum = 0;
        for(var i=0;i

检查是否有任何两个数字的和是给定的数字

最暴力的方法就是两层循环,是O(n2).改进方法使用一个对象作为哈希表,用于存储数,这样在每次搜寻是否有另一个数与当前数的和为sum时就可以在O(1)的时间内找到。

    function twoSum(arr,sum){
        var obj = {};
        var num;
        for(var i=0;i

检查是否有任何两个数字的和是给定的数字,有的话将数字和位置以对象的方式返回值,否则返回false

最暴力的方法就是两层循环,是O(n2).改进方法使用一个对象作为哈希表,用于存储数,这样在每次搜寻是否有另一个数与当前数的和为sum时就可以在O(1)的时间内找到。

    function twoSum(arr,sum){
        var obj = {};
        var num;
        for(var i=0;i

找到任意两个数字的最大和

找到两个最大的数并返回它们的和。

    function topSum(arr){
        if(arr.length<2) return null;
        var first,second;
        if(arr[0]>arr[1]){
            first = arr[0];
            second=arr[1];
        }else{
            first = arr[1];
            second=arr[0];
        }
    
        for(var i=2;ifirst){
                second = first;
                first = arr[i];
            }else if(arr[i]>second){
                second = arr[i];
            }
        }
    
        return first+second;
    }

从1到n中0的总个数

n=50的话,有5个0,分别是10,20,30,40,50。 
n = 120的话,分别是10到90,共九个,110到120,共2个,以及100的两个,一共13个。
也就是说10的整数次方会有多个零,如100,1000,那么就要利用现有的数计算包含了多少个10的平方数。
如2014,2014/10=201; 201/10 = 20; 20/10 = 2; 最后表明出现了两次10的三次方,即1000和2000。
    function countZero(n){
        var count = 0;
        while(n>0){
            count+=Math.floor(n/10);
            n/=10;
        }
        return count;
    }

匹配字符串的子字符串

    function substr(str,subStr){
        for(var i=0;i

字符串的全排列

    var result = [];
    function permutations(str){
        var arr= str.split("");
    
        helper(arr,0,[]);
        return result;
    }
    function helper(arr,index,list){
        if(index === arr.length){
            result.push(list.join(""));
            return;
        }
        for(var i = 0;i

不借助临时变量,进行两个整数的交换

把 a = 2, b = 4 变成 a = 4, b =2
这种问题非常巧妙,需要大家跳出惯有的思维,利用 a , b进行置换
主要是利用 + – 去进行运算,类似 a = a + ( b – a) 实际上等同于最后 的 a = b;
    function swap(a , b) {  
      b = b - a;
      a = a + b;
      b = a - b;
      console.log("a="+a);
      console.log("b="+b)
    }
    var a=2,b=4;
    swap(a,b)
    //a=4;b=2

斐波那契数列(黄金分割数列)不说换金分割我也不知道是啥玩意儿啦

斐波那契数列,又称黄金分割数列,指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列主要考察递归的调用。

    function getFibonacci(n) {  
      var fibarr = [];
      var i = 0;
      while(i

获得第n个斐波那契数字

解法一:迭代

var fibonacci = function(n){
    var fibo = [0,1];
    for(var i=2;i<=n;i++){
        fibo[i] = fibo[i-1]+fibo[i-2];
    }
    return fibo[n];
}

解法二:递归

    var fibonacci = function(n){
        if(n>=2){
            return fibonacci(n-1)+fibonacci(n-2);
        }else{
            return n;
        }
    }

找到两个数的最大公约数

解法一:遍历

    var greatestCommonDivisor= function(a,b){
        if(a<2 || b<2) return 1;
        var divider = 2;
        var greatestDivisor = 1;
        while(divider<=a && divider<=b){
            if(a%divider == 0 && b%divider == 0){
                greatestDivisor = divider;
            }
            divider++;
        }
        return greatestDivisor;
    }

解法二:辗转相除法
又名欧几里德算法(Euclidean algorithm)乃求两个正整数之最大公因子的算法。它是已知最古老的算法……
有解释的,但我选择不去理解……

    function greatestCommonDivisor(a, b){
       if(b == 0)
         return a;
       else 
         return greatestCommonDivisor(b, a%b);
    }

合并两个排序数组

var mergeSortedArray = function(a,b){
    var merge = [];
    var i = 0,j = 0;
    var k = 0;
    while(ib[j])){
            merge[k++] = b[j++];
        }else{
            merge[k++] = a[i++];
        }
    }
    return merge; 
}

验证一个数是否是质数

质数只能被1和它自己整除,因此令被除数从2开始,若能整除则不是质数,若不能整除则加一,直到被除数到达根号n,此时n则是质数。

    function isPrime(n){
        var divider = 2;
        var limit = Math.sqrt(n);
        while(divider<=limit){
            if(n%divider == 0){
                return false;
            }
            divider++;
        }
        return true;
    }
    isPrime(3);
    //true

查找数字的所有质数因子

divider从2开始,如果n能整除divider,则将divider加入到结果中,n为此次计算后的商,如果n不能整除divider,则divider++

var primeFactors = function(n){
    var factors = [];
    var divider = 2;
    while(n>2){
        if(n%divider == 0){
            factors.push(divider);
            n /= divider;
        }else{
            divider++;
        }
    }
    return factors;
}

找出正数组的最大差值比

这是通过一道题目去测试对于基本的数组的最大值和最小值的查找

     function getMaxProfit(arr) {
        var minPrice = arr[0];
        var maxProfit = 0;
        for (var i = 0; i < arr.length; i++) {
            var currentPrice = arr[i];
            minPrice = Math.min(minPrice, currentPrice);
            var potentialProfit = currentPrice - minPrice;
            maxProfit = Math.max(maxProfit, potentialProfit);
        }
        return maxProfit;
    }
    getMaxProfit([10,5,11,7,8,9])
    //6

随机生成指定长度的字符串

    function randomString(n) {  
      let str = "abcdefghijklmnopqrstuvwxyz9876543210";
      let tmp = "",
          i = 0,
          l = str.length;
      for (i = 0; i < n; i++) {
        tmp += str.charAt(Math.floor(Math.random() * l));
      }
      return tmp;
    }
    randomString(9);  //指定长度为9
    //4ldkfg9j7

实现类似getElementsByClassName 的功能

自己实现一个函数,查找某个DOM节点下面的包含某个class的所有DOM节点?不允许使用原生提供的 getElementsByClassName querySelectorAll 等原生提供DOM查找函数。

    function queryClassName(node, name) {  
      var starts = "(^|[ 

	f])",
           ends = "([ 

	f]|$)";
      var array = [],
            regex = new RegExp(starts + name + ends),
            elements = node.getElementsByTagName("*"),
            length = elements.length,
            i = 0,
            element;
     
        while (i < length) {
            element = elements[i];
            if (regex.test(element.className)) {
                array.push(element);
            }
     
            i += 1;
        }
     
        return array;
    }
    queryClassName()

使用JS 实现二叉查找树

一般叫全部写完的概率比较少,但是重点考察你对它的理解和一些基本特点的实现。 二叉查找树,也称二叉搜索树、有序二叉树(英语:ordered binary tree)是指一棵空树或者具有下列性质的二叉树:

任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 任意节点的左、右子树也分别为二叉查找树;
没有键值相等的节点。二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低。为O(log
n)。二叉查找树是基础性数据结构,用于构建更为抽象的数据结构,如集合、multiset、关联数组等。
    class Node {  
      constructor(data, left, right) {
        this.data = data;
        this.left = left;
        this.right = right;
      }
    }
    
    class BinarySearchTree {
      constructor() {
        this.root = null;
      }
      insert(data) {
        let n = new Node(data, null, null);
        if (!this.root) {
          return this.root = n;
        }
        let currentNode = this.root;
        let parent = null;
        while (1) {
          parent = currentNode;
          if (data < currentNode.data) {
            currentNode = currentNode.left;
            if (currentNode === null) {
              parent.left = n;
              break;
            }
          } else {
            currentNode = currentNode.right;
            if (currentNode === null) {
              parent.right = n;
              break;
            }
          }
        }
      }
     
      remove(data) {
        this.root = this.removeNode(this.root, data)
      }
     
      removeNode(node, data) {
        if (node == null) {
          return null;
        }
        if (data == node.data) {
          // no children node
          if (node.left == null && node.right == null) {
            return null;
          }
          if (node.left == null) {
            return node.right;
          }
          if (node.right == null) {
            return node.left;
          }
          let getSmallest = function(node) {
            if(node.left === null && node.right == null) {
              return node;
            }
            if(node.left != null) {
              return node.left;
            }
            if(node.right !== null) {
              return getSmallest(node.right);
            }
          }
          let temNode = getSmallest(node.right);
          node.data = temNode.data;
          node.right = this.removeNode(temNode.right,temNode.data);
          return node;
        } else if (data < node.data) {
          node.left = this.removeNode(node.left,data);
          return node;
        } else {
          node.right = this.removeNode(node.right,data);
          return node;
        }
      }
     
      find(data) {
        var current = this.root;
        while (current != null) {
          if (data == current.data) {
            break;
          }
          if (data < current.data) {
            current = current.left;
          } else {
            current = current.right
          }
        }
        return current.data;
      }
     
    }
     
    module.exports = BinarySearchTree;

统计数组中每个元素及出现的次数,并输出到页面

  function getArrayMess(arr) {  
          if(arr.length == 1) {
            console.log("{"+arr[0]+":1")
          }
          let charObj = {};
          for(let i=0;i           
               
                                           
                       
                 

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89215.html

相关文章

  • 前端周报:前端面试题及答案总结;JavaScript参数传递深入理解

    摘要:前端面试题及答案总结掘金技术征文金三银四,金九银十,用来形容求职最好的几个月。因为的存在,至少在被标准化的那一刻起,就支持异步编程了。然而异步编程真正发展壮大,的流行功不可没。 showImg(https://segmentfault.com/img/bVVQOH?w=640&h=319); 1、2017前端面试题及答案总结 |掘金技术征文 金三银四,金九银十,用来形容求职最好的几个月...

    ermaoL 评论0 收藏0
  • 求职攻略 | Datawhale助力秋招最强战甲

    摘要:秋招变夏招,还没准备好团队成员收割机牵头,带领名成员历时个月,整理了一份机器学习算法工程师求职面经。但如果之前并没有意识到这一问题也没关系,为你呈现一份小而美的面经。这部分内容包含了逻辑题目及概率题目两方面的内容。 秋招变夏招,还没准备好?Datawhale团队成员offer收割机牵头,带领14名成员历时2个月,整理了一份机器学习算法工程师求职面经:Daily-interview。一份...

    CKJOKER 评论0 收藏0
  • 求职准备 - 收藏集 - 掘金

    摘要:一基础接口的意义百度规范扩展回调抽象类的意义想不想通过一线互联网公司面试文档整理为电子书掘金简介谷歌求职记我花了八个月准备谷歌面试掘金原文链接翻译者 【面试宝典】从对象深入分析 Java 中实例变量和类变量的区别 - 掘金原创文章,转载请务必保留原出处为:http://www.54tianzhisheng.cn/... , 欢迎访问我的站点,阅读更多有深度的文章。 实例变量 和 类变量...

    cuieney 评论0 收藏0

发表评论

0条评论

Jochen

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<