leetcode 之排序

221 阅读2分钟

详解 sort 方法

215. 数组中的第K个最大元素:TopK 快排问题

TopK 问题出现频率很高.

题目215. 数组中的第K个最大元素

注意升降序和 (k-1)

  1. 求第 K 个最大元素,数组应该降序排列
  2. 算法优化:找个第 K 个元素后,递归就终止。
const divide = (arr, left, right) => { // 和快排的 divide() 一样
    const pivot = arr[right];
    let p = left;
    for (let i = left; i < right; i++) {
        if (arr[i] > pivot) { // 控制升序还是降序
            [arr[i], arr[p]] = [arr[p], arr[i]];
            p++;
        }
    }
    [arr[right], arr[p]] = [arr[p], arr[right]];
    return p;
}

// 不需要全部排完序,找到第K大的元素后终止递归!
const KthLargest = (nums, left = 0, right = nums.length - 1, k) => {
    if (left < right) {
        const mid = divide(nums, left, right);
        if (mid == k - 1) { // 递归终止!
            return; // 注意
        } else if (mid < k - 1) {
            KthLargest(nums, mid + 1, right, k);
        } else {
            KthLargest(nums, left, mid - 1, k);
        }
    }
}

const findKthLargest = (nums, k) => {
    KthLargest(nums, 0, nums.length - 1, k);
    return nums[k - 1];
}

拓展:获得前 K 大的数

const topkLargest = (nums, k) => {
  KthLargest(nums, 0, nums.length - 1, k);
  return nums.slice(0, k);
}

如果要求 前K小、第K小 的问题,那么将 divide 函数修改为升序即可!

56.合并区间:左端点 sort 排序

题目56. 合并区间

题解

  1. 首先将区间按照左端点的大小升序排序;
  2. 然后遍历区间,根据上一个区间 prev 右端点下一个区间左端点的大小关系,判断区间是否有重叠:
    • 不重叠时,将上一个区间 push 进 res 中,并更新 prev;
    • 重叠时,我们取两个区间右端点中的较大值来更新数值。
  3. 在遍历完成后,将最后一个区间 push 进 res 中。
const merge = function(nums) {
  nums.sort((a, b) => a[0] - b[0]); // 按区间的左端点大小升序排列
  
  const res = [];
  let prev = nums[0];
  
  for (let i = 1; i < nums.length; i++) {
    if (prev[1] < nums[i][0]) {  // 不重叠
      res.push(prev);
      prev = nums[i];  // 更新 prev
    } else {
        prev[1] = Math.max(prev[1], nums[i][1]);
    }
  }
  res.push(prev);  // 注意!!
  return res;
};

时间复杂度:O(nlogn)。主要是 sort 的时间开销。

空间复杂度:O(logn)。sort 排序所需要的空间复杂度。

179. 最大数:拼接字典序sort + 贪心

题目179. 最大数

sort 排序后得到的依然是整数数组;返回值要求是字符串!

  • 对于 nums 中的任意两个值 a 和 b,我们无法直接从常规角度确定它们拼接之后的大小关系,但我们可以根据 结果 来决定 a 和 b 的排序关系。
  • 如果拼接结果 ab 要比 ba 好,那么我们会认为 a 应该在 b 的前面。所以 我们要按照 「拼接结果的字典序大小」 排序。
  • 另外,注意我们需要处理 前导0 (最多保留一位)。
const largestNumber = function(nums) {
  nums.sort((a, b) => {  // 按拼接结果的字典序大小排列
    let s1 = `${a}${b}`;
    let s2 = `${b}${a}`;
    return s2 - s1;  // 降序
  });
  // 要返回的是字符串,因此将数组转化为字符串
  // 如果返回是 '00',那么直接返回一个 '0'即可。
  return nums[0] ? '0' : nums.join('');
};

时间复杂度:O(nlogn)。主要来自于 sort 排序。