前端面试-常用数据结构和算法

·  阅读 38

大多数人,甚至我之前都觉得算法对于前端事没有什么做勇敢的,所以很多同行包括我对这部分知识都是有所欠缺,甚至抵触,但是,如果我们想要突破更高的天花板或者进入大厂,这部分知识是必不可少的,至少我的亲身经历来看时非常有用的!!!

算法

算法基本定义就是对特定问题求解步骤,过程是指令有限序列,特性有穷性确定性可行性输入输出,要求输入输出正确、清晰可读、非法健壮、效率低存储。

所以一般来说,对于算法首先有对时间复杂度和空间复杂度的敏感性(可估计业务逻辑代码的耗时和内存消耗)一般问完算法都会让你计算一下。

如果面试的公司不是很注重算法,一般会问你一些基本的排序算法的实现原理、应用场景、优缺点,最好可以快速说出时间、空间复杂度

有一点要求的不想刁难你的,比较喜欢问一下递归和循环的优缺点和应用。

想给你加一点难度就是,用回溯算法贪心算法分治算法动态规划等解决复杂问题。

高级一点的,比较少,我也只是见过一两个公司问过,前端怎么去处理海量数据。

时间复杂度和空间复杂度

时间复杂度

对于问题规模n,算法基本操作的原子操作语句重复执行的次数时间(频度)的度量。

举例:

基本操作: x增1

程序段1: { ++x; s=0; } O(1) 常量阶

程序段2: for(i = 1; i <=n; ++i) { ++x; s+=x; } O(n) 线性阶

程序段3: for(j = 1; j <=n; ++j) for(k = 1; k <=n; ++k) { ++x; s+=x; } O(n^2) 平方阶

空间复杂度

一个程序执行时除了需要存储空间和存储本身所使用的指令、常数、变量和输入数据外,对于问题规模n,算法对输入数据进行操作的工作单元或则存储实时计算信息的辅助空间的存储量度。 S(n) = O(f(n))

排序算法

快排

选择一个目标值,比目标小的放左边,比目标大的放右边,一趟排序后目标位置确定,再将左右两侧再递归快排序。 快排,利用了分治的思想。

   // 写法1: 额外开辟left 和 right 两个 数组,存储比target 大小的序列,对于递归返回的left、target、right拼接成最终数组。 
   function quickSort(array) {
       if(array.length < 2) {
          return array;
       }
       const target = array[0];
       const left = [];
       const right = [];
       for(let i = 1; i < array.length; i++) {
           if(array[i] < target) {
               left.push(array[i])
           }
           if(array[i] > target[i]) {
                right.push(arrayp[i])
           }
       }
       return quickSort(left).concat([target], quick(right))
   }
   
   // 写法2: 
   // 记录一个索引l 从数组的最左侧开始, 记录一个索引r 从数组右侧开始
   // 在l < r 的条件下,找到右侧 小于target 的值的array[r], 并将其赋值到array[l]
   // 在l < r 的条件下, 找到左侧大于target 的值array[l], 并将其赋值到array[r]
   // 这样让l=r时, 左侧的值全部小于target, 右侧的值全部大于target。
   // 最后将target 放到该 l=r 处。
   
   function quickSort(array, start, end) {
      if(end - start < 1) return;
      const target = array[start]
      let l = start, r = end;
      while(l < r) {
          while(l < r && array[r] >= target) {
               r--;
          }
          array[l] = array[r];
          while(l < r && array[l] < target) {
              l++;
          }
          array[r] = array[l]
      }
      array[l] = target;
      quickSort(array, start, l - 1);
      quickSort(array, l+1, end);
      return array;
   }

复制代码

时间复杂度: 平均O(nlogn)阶, 最坏O(n^2),多数情况小于O(nlogn) 空间复杂度:O(logn) 递归调用消耗 不稳定排序

归并排序

将大序列分成小序列,小序列排序,小序列二路归并有序成大序列,整体有序。 分治法的典型应用。 归并:创建临时数组temp, 比较左右数组第一个元素,小的先加入临时数组,直到两个数组为空,若左右数组有一个为空了,另一个数组的元素都是大于临时数组的所有元素,直接将其逐个加入temp.

// 写法1: 分割数组为左右数组,空间复杂度高,需要copy多个数组
    function mergeSort(array) {
       const len = array.length;
       if(len < 2) return array;
       // const mid = Math.floor(len / 2);
       const mid = len >> 1;
       const left = array.slice(0, mid);
       const right = array.slice(mid);
       return merge(mergeSort(left), mergeSort(right));
    }
    
    function merge(front, end) {
        const temp = [];
        while(front.length && end.length) {
            if(front[0] < end[0]) {
               temp.push(front.shift());
            } else {
                temp.push(end.shift());
            }
        }
        while(front.length) {
            temp.puhs(front.shift());
        }
        while(end.length) {
            temp.push(end.shift());
        }
        return temp;
    }
// 写法2: 记录数组的索引,left、right 索引限定分割当前数组。
// 空间复杂度低,只需一个temp数组,不copy 数组
function mergeSort(array, left, right, temp) {
   if(left < right) {
     const mid = ((left + right)/2) >> 1;
     mergeSort(array, left, mid, temp);
     mergeSort(array, mid+1, right, temp);
     merge(array, left, right, temp);
   }
   return array;
}

function merge(array, left, right, temp) {
     const mid = ((left + right)/2) >> 1;
     let leftIndex = left;
     let rightIndex = mid + 1;
     let tempIndex = 0;
     while(leftIndex <= mid && rightIndex <= right) {
         if(array[leftIndex] < array[rightIndex]) {
             temp[tempIndex++] = array[leftIndex++]
         } else {
             temp[tempIndex++] = array[rightIndex++]
         }
     }
     while(leftIndex <= mid) {
        temp[tempIndex++] = array[leftIndex++]
     }
     while(rightIndx <= rihgt) {
        temp[tempIndex++] = array[rightIndex]
     }
     tempIndex = 0;
     for(let i = left; i <=right; i++) {
        array[i] = temp[tempIndex++];
     }
     
}
    
复制代码

时间复杂度:O(nlogn) 空间复杂度:O(n) 稳定

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改