前端算法面试必刷题系列[29]

267 阅读4分钟

这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。

50. 搜索二维矩阵 (search-a-2d-matrix)

标签

  • 二分查找
  • 中等

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:

  • 每行中的整数从左到右按升序排列。
  • 每行的第一个整数大于前一行的最后一个整数。

屏幕快照 2021-03-28 上午11.13.01.png

输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
输出:true

相关知识

数组拍平

Array.prototype.flat()

flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。

语法

var newArray = arr.flat([depth])

参数

depth (可选)

指定要提取嵌套数组的结构深度,默认值为 1。

例子

var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]

var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]

var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]

//使用 Infinity,可展开任意深度的嵌套数组
var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

注意 flat() 方法会移除数组中的空项:

var arr4 = [1, 2, , 4, 5];
arr4.flat();
// [1, 2, 4, 5]

手动实现一层flat

var arr = [1, 2, [3, 4]];
// 展开一层数组

// 方法一: reduce + concat
arr.reduce((acc, val) => acc.concat(val), []);
// [1, 2, 3, 4]

// 方法儿: 使用扩展运算符 ...
const flattened = arr => [].concat(...arr);

手动实现无限层flat

// reduce + concat + 递归
var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]];

function flatDeep(arr, d = 1) {
  if (d > 0) {
    return arr.reduce((acc, cur) => acc.concat(
      Array.isArray(cur) ? 
      flatDeep(cur, d - 1) :
      cur
    ), [])
  } else {
    return arr.slice();
  }
};

console.log(flatDeep(arr1, Infinity));
// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]

基本思路

我们看到有序序列查找问题,就想到可用二分查找。

不熟同学请移步 二分查找这篇先

基本步骤

  1. 先拍平成一维数组。
  2. 再二分查找就行了。

写法实现

var searchMatrix = function(matrix, target) {
  // 先拍平,根据题意,拍平后是个有序一维数组
  let matrixFlat = matrix.flat(Infinity);
  // 有序数组查找,直接二分
  let [left, right, mid] = [0, matrixFlat.length - 1, 0]
  while (left <= right) {
    mid = left + Math.floor((right - left) / 2)
    console.log(mid, 'mid')
    console.log(matrixFlat[mid])
    if (matrixFlat[mid] === target) {
      return true
    } else if (matrixFlat[mid] > target) {
      right = mid - 1
    } else {
      left = mid + 1
    }
  }
  return false
};

let matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3

console.log(searchMatrix(matrix, target))

51. 颜色分类 (sort-colors)

标签

  • 计数排序
  • 中等

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

基本思路

这道题可以用计数排序,适合待排序数字很少的题目。 用一个 3 个容量的数组分别计数,记录 0,1,2 出现的次数。然后再根据个数排列 0,1,2 即可。

详细关于计数排序、桶排序和基数排序的原理请移步这篇文章:

[算法拆解] 一文说透排序算法的特点(中)

基本步骤

请根据上面文章先了解计数排序的思想。

  1. 建立1个桶,里面就是放 0, 1, 2三个元素。
统计数   [0, 0, 0]
index   [0, 1, 2]
  1. 遍历 nums 把这些元素分别装到桶里,其实就是用桶的index位置来对应这三个数值,然后记录出现次数
  2. 桶已经装完了,根据统计次数放回原数组即可。

写法实现

var sortColors = function(nums) {
  // 这题桶是一定的就三数,桶里元素表示这3数出现的次数
  let [len, cur] = [nums.length, 0]
  // 核心就是用index来对应这三个数
  let bucket = [0, 0, 0]
  nums.map(item => {
    bucket[item]++
  })
  // 放回原数组
  for (let i = 0; i < Math.max(len, 3); i++) {
    while (bucket[i] > 0) {
      nums[cur++] = i
      // 用掉一次减一次
      bucket[i]--;
    }
  }
  return nums
};

let nums = [2,0,2,1,1,0]
console.log(sortColors(nums))

另外向大家着重推荐下这位大哥的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列

今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 搜索我的微信号infinity_9368,可以聊天说地 加我暗号 "天王盖地虎" 下一句的英文,验证消息请发给我 presious tower shock the rever monster,我看到就通过,暗号对不上不加哈,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧

参考