js解leetcode(28)-中等

本文探讨了多种高效算法解决方案,包括有序矩阵中查找第K小元素的方法、实现常数时间复杂度的数据结构操作、链表随机节点选取策略、数组打乱算法及字典序排序技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.有序矩阵中第K小的元素

题目:给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
请注意,它是排序后的第 k 小元素,而不是第 k 个不同的元素。

思路:先来个最简单的,展开成一维数组,然后sort排序

时间复杂度O(n2logn2),空间复杂度O(n2)

/**
 * @param {number[][]} matrix
 * @param {number} k
 * @return {number}
 */
var kthSmallest = function(matrix, k) {
  const n = matrix.length;
  const list = new Array(n * n);
  let v = 0;
  for (let i = 0; i < n; i++) {
    for (let j = 0; j < n; j++) {
      list[v++] = matrix[i][j];
    }
  }
  list.sort((a, b) => a - b);
  return list[k - 1];
};

注意到,矩阵的每一行是有序数组,我们可以记录从0开始每一行对应的下标,先比较出当前最小的那一行,该行对应的下标+1,直到第K个。这个和之前前K对最小数是一样的

时间复杂度O(kn),空间复杂度O(n)

/**
 * @param {number[][]} matrix
 * @param {number} k
 * @return {number}
 */
var kthSmallest = function(matrix, k) {
  const n = matrix.length;
  let c = 1;
  const list = new Array(n).fill(0);
  let res = matrix[0][0];
  list[0] = 1;
  while (c < k) {
    let cur = matrix[0][list[0]] ?? Infinity;
    let index = 0;
    for (let i = 1; i < n; i++) {
      if ((matrix[i][list[i]] ?? Infinity) < cur) {
        cur = matrix[i][list[i]];
        index = i;
      }
    }
    res = cur;
    list[index]++;
    c++
  }
  return res;
};

2.常数时间插入、删除和随机获取元素

题目:

设计一个支持在平均 时间复杂度 O(1) 下,执行以下操作的数据结构。

insert(val):当元素 val 不存在时,向集合中插入该项。
remove(val):元素 val 存在时,从集合中移除该项。
getRandom:随机返回现有集合中的一项。每个元素应该有相同的概率被返回

思路:用数组或者set记录数据,随机获取下标即可

每次操作时间复杂度:O(n),空间复杂度O(n)

/**
 * Initialize your data structure here.
 */
var RandomizedSet = function () {
  this.data = [];
};

/**
 * Inserts a value to the set. Returns true if the set did not already contain the specified element.
 * @param {number} val
 * @return {boolean}
 */
RandomizedSet.prototype.insert = function (val) {
  if (this.data.includes(val)) return false;
  this.data.push(val);
  return true;
};

/**
 * Removes a value from the set. Returns true if the set contained the specified element.
 * @param {number} val
 * @return {boolean}
 */
RandomizedSet.prototype.remove = function (val) {
  if (!this.data.includes(val)) return false;
  const index=this.data.findIndex(i=>i==val)
  this.data.splice(index,1);
  return true;
};

/**
 * Get a random element from the set.
 * @return {number}
 */
RandomizedSet.prototype.getRandom = function () {
  const index = ~~(Math.random() * this.data.length);
  return this.data[index];
};

3.链表随机节点

题目:

给定一个单链表,随机选择链表的一个节点,并返回相应的节点值。保证每个节点被选的概率一样

进阶:
如果链表十分大且长度未知,如何解决这个问题?你能否使用常数级空间复杂度实现?

思路:先获取链表长度,然后随机获取下标,然后从头部开始得到模板节点

每次操作时间复杂度:o(n),空间复杂度O(1)

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param head The linked list's head.
        Note that the head is guaranteed to be not null, so it contains at least one node.
 * @param {ListNode} head
 */
var Solution = function (head) {
  this.head = head;
  let l = 0;
  while (head) {
    head = head.next;
    l++;
  }
  this.length = l;
};

/**
 * Returns a random node's value.
 * @return {number}
 */
Solution.prototype.getRandom = function () {
  if (!this.length) return null;
  let node = this.head;
  let index = ~~(Math.random() * this.length) + 1;
  while (--index) {
      node=node.next;
  }
  return node.val;
};

也可以单次遍历链表。对于第i个节点,有1/i的概率将该节点值作为结果。


/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param head The linked list's head.
        Note that the head is guaranteed to be not null, so it contains at least one node.
 * @param {ListNode} head
 */
var Solution = function (head) {
  this.head = head;
};

/**
 * Returns a random node's value.
 * @return {number}
 */
Solution.prototype.getRandom = function () {
  if (!this.head) return null;
  let v = this.head.val;
  let index = 1;
  let node = this.head.next;
  while (node) {
    index++;
    if (!~~(Math.random() * index)) {
      v = node.val;
    }
    node = node.next;
  }
  return v;
};

/**
 * Your Solution object will be instantiated and called as such:
 * var obj = new Solution(head)
 * var param_1 = obj.getRandom()
 */

 

4.打乱数组

题目:

给你一个整数数组 nums ,设计算法来打乱一个没有重复元素的数组。

实现 Solution class:

  • Solution(int[] nums) 使用整数数组 nums 初始化对象
  • int[] reset() 重设数组到它的初始状态并返回
  • int[] shuffle() 返回数组随机打乱后的结果

思路:每次根据当前数组长度随机获取一个元素,然后删除当前元素进入下一轮获取

,每次时间复杂度O(n2),空间复杂度O(n)


/**
 * @param {number[]} nums
 */
var Solution = function (nums) {
  this.data = nums;
};

/**
 * Resets the array to its original configuration and return it.
 * @return {number[]}
 */
Solution.prototype.reset = function () {
  return this.data;
};

/**
 * Returns a random shuffling of the array.
 * @return {number[]}
 */
Solution.prototype.shuffle = function () {
  const l = this.data.length;
  const res = new Array(l);
  const list = new Array(l).fill('').map((item, i) => i);
  for (let i = 0; i < l; i++) {
    const index = list.splice(~~(Math.random() * (l - i)), 1)[0];
    res[index] = this.data[i];
  }
  return res;
};

/**
 * Your Solution object will be instantiated and called as such:
 * var obj = new Solution(nums)
 * var param_1 = obj.reset()
 * var param_2 = obj.shuffle()
 */

 5.字典序排序

题目:

给定一个整数 n, 返回从 到 的字典顺序。

例如,

给定 n =1 3,返回 [1,10,11,12,13,2,3,4,5,6,7,8,9] 。

请尽可能的优化算法的时间复杂度和空间复杂度。 输入的数据 小于等于 5,000,000。

思路:先说简单的。用数组的sort排序。因为字符串比较时就是字典序比较

时间复杂度O(nlogn),空间复杂度O(n)

/**
 * @param {number} n
 * @return {number[]}
 */
var lexicalOrder = function(n) {
  const res = new Array(n);
  for (let i = 1; i <= n; i++) {
    res[i - 1] = `${i}`;
  }
  res.sort();
  return res;
};

也可以自定义顺序推入数组。

我们将数字放入一个数组里,每次从头部取出一个数,如果这个数满足条件(小于等于n),那么推入结果。同时将这个数字后面连接0-9的数字形成10个新的数字,推入数组的头部

时间复杂度O(n),空间复杂度O(n)

/**
 * @param {number} n
 * @return {number[]}
 */
var lexicalOrder = function(n) {
  const res = new Array(n);
  const stack = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
  let c = 0;
  while (c < n) {
    const item = stack.shift();
    if (+item > n) continue;
    res[c++] = item;
    const list = new Array(10);
    for (let i = 0; i < 10; i++) {
      list[i] = `${item}${i}`;
    }
    stack.unshift(...list);
  }
  return res;
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值