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

151 阅读6分钟

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

65. 分隔链表 (partition-list)

标签

  • 链表
  • 中等

题目

leetcode 传送门

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

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前

你应当 保留 两个分区中每个节点的初始相对位置。

image.png

输入:head = [1,4,3,2,5,2], x = 3
输出:[1,2,2,4,3,5]

基本思路

  1. 新构造 2 个链表,一个链表专门存储比 x 小的结点,另一个专门存储比 x 大的结点。
  2. 在原链表头部开始扫描一遍,依次把这两类点归类到 2 个新建链表中。
  3. 由于是从头开始扫描的原链表,所以原链表中的原有顺序会依旧被保存下来。
  4. 最后 2 个新链表里面会存储好各自的结果,把这两个链表,比 x 小的链表拼接到 比 x 大的链表的前面,就能得到最后的答案了。

基本步骤

  1. 建立两个链表,big && small
  2. 建立两个列表的虚拟头结点,处理空的边界条件
  3. 开始遍历,分类大小
  4. 大小数组拼接,尾部置空,返回小数组头结点。

写法实现

var partition = function(head, x) {
  // 建立两个链表,分别为大于 x 的和小于 x 的链表
  let [small, big] = [new ListNode(0), new ListNode(0)]
  // 建立两个链表的虚拟头结点,处理头节点为空的边界条件更方便
  let [smallPreHead, bigPreHead] = [small, big]
  // 开始区分,形成 small , big 链表
  while (head !== null) {
    if (head.val < x) {
      small.next = head;
      small = small.next;
    } else {
      big.next = head;
      big = big.next;
    }
    head = head.next;
  }
  // big 数组尾部置空
  big.next = null;
  // 数组链接
  small.next = bigPreHead.next;
  return smallPreHead.next;
}

66. 合并两个有序数组 (merge-sorted-array)

标签

  • 数组
  • 简单

题目

leetcode 传送门

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

给你两个有序整数数组 nums1nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。

初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。你可以假设 nums1 的空间大小等于 m + n,这样它就有足够的空间保存来自 nums2 的元素。

示例:

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]

相关知识

Array.prototype.splice()

splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组

// 删除 0 个 并在 index === 1 的位置添加 'Feb'
const months = ['Jan', 'March', 'April', 'June'];
months.splice(1, 0, 'Feb');
// inserts at index 1
console.log(months);
// expected output: Array ["Jan", "Feb", "March", "April", "June"]

// 在 index === 4 的位置 删除 1 个元素("June") 并添加 'May'
months.splice(4, 1, 'May');
// replaces 1 element at index 4
console.log(months);
// expected output: Array ["Jan", "Feb", "March", "April", "May"]

语法

array.splice(start[, deleteCount[, item1[, item2[, ...]]]])

参数

  • start

    • 指定修改的开始位置(从0计数)。
    • 如果超出了数组的长度,则从数组末尾开始添加内容;
    • 如果是负值,则表示从数组末位开始的第几位(从-1计数,这意味着-n是倒数第n个元素并且等价于array.length-n);
    • 如果负数的绝对值大于数组的长度,则表示开始位置为第0位。
  • deleteCount 可选

    • 整数,表示要移除的数组元素的个数
    • 如果 deleteCount 大于 start 之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。
    • 如果 deleteCount 被省略了,或者它的值大于等于array.length - start(也就是说,如果它大于或者等于start之后的所有元素的数量),那么start之后数组的所有元素都会被删除。
    • 如果 deleteCount 是 0 或者负数,则不移除元素。这种情况下,至少应添加一个新元素。
  • item1, item2, ... 可选

    • 添加进数组的元素
    • start 位置开始。如果不指定,则 splice() 将只删除数组元素。

返回值

  • 被删除的元素组成的一个数组
  • 如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。

注意 如果添加进数组的元素个数不等于被删除的元素个数,数组的长度会发生相应的改变。

Array.prototype.sort()

sort() 方法用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的。

const months = ['March', 'Jan', 'Feb', 'Dec'];
months.sort();
console.log(months);
// expected output: Array ["Dec", "Feb", "Jan", "March"]

// 注意 1 ,100000 的顺序,并不是我们想的那样
const array1 = [1, 30, 4, 21, 100000];
array1.sort();
console.log(array1);
// expected output: Array [1, 100000, 21, 30, 4]

语法

arr.sort([compareFunction])

参数

  • compareFunction 可选
    • 用来指定按某种顺序进行排列的函数
    • 如果省略,元素按照转换为的字符串的各个字符的Unicode位点进行排序。

返回值

排序后的数组。 请注意,数组已原地排序,并且不进行复制。

注意

  • 如果没有指明 compareFunction ,那么元素会按照转换为的字符串的诸个字符的Unicode位点进行排序。

    • 例如 "Banana" 会被排列到 "cherry" 之前。
    • 当数字按由小到大排序时,9 出现在 80 之前,但因为(没有指明 compareFunction),比较的数字会先被转换为字符串,所以在Unicode顺序上 "80" 要比 "9" 要靠前。
  • 如果指明了 compareFunction ,那么数组会按照调用该函数的返回值排序。即 a 和 b 是两个将要被比较的元素:

    • 如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
    • 如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。备注: ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守(例如 Mozilla 在 2003 年之前的版本);
    • 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。
    • compareFunction(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。 所以,比较函数格式如下:
function compare(a, b) {
  if (a < b ) {           // 按某种排序标准进行比较, a 小于 b
    return -1;
  }
  if (a > b ) {
    return 1;
  }
  // a must be equal to b
  return 0;
}

要比较数字而非字符串,比较函数可以简单的以 a 减 b,如下的函数将会将数组升序排列

function compareNumbers(a, b) {
  return a - b;
}

sort 方法可以使用 函数表达式 方便地书写:

var numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
  return a - b;
});
console.log(numbers);

也可以写成:
var numbers = [4, 2, 5, 1, 3];
numbers.sort((a, b) => a - b);
console.log(numbers);

// [1, 2, 3, 4, 5]

对象可以按照某个属性排序:

var items = [
  { name: 'Edward', value: 21 },
  { name: 'Sharpe', value: 37 },
  { name: 'And', value: 45 },
  { name: 'The', value: -12 },
  { name: 'Magnetic' },
  { name: 'Zeros', value: 37 }
];

// sort by value
items.sort(function (a, b) {
  return (a.value - b.value)
});

// sort by name
items.sort(function(a, b) {
  var nameA = a.name.toUpperCase(); // ignore upper and lowercase
  var nameB = b.name.toUpperCase(); // ignore upper and lowercase
  if (nameA < nameB) {
    return -1;
  }
  if (nameA > nameB) {
    return 1;
  }

  // names must be equal
  return 0;
});

由此我们可以各种组合使用排序。

基本思路

  1. 改写数组nums1,相当于合并
  2. 然后排序就行

写法实现

// 注意它是原地修改 nums1
var merge = function(nums1, m, nums2, n) {
  nums1.splice(m, nums1.length - m, ...nums2);
  nums1.sort((a, b) => a - b);
};

当然本题也可以用双指针,但我们这种简单题不浪费时间,过!

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

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

参考