跳至主要內容

382. Linked List Random Node


382. Linked List Random Nodeopen in new window

🟠   🔖  水塘抽样 链表 数学 随机化  🔗 LeetCodeopen in new window

题目

Given a singly linked list, return a random node's value from the linked list. Each node must have the same probability of being chosen.

Implement the Solution class:

  • Solution(ListNode head) Initializes the object with the head of the singly-linked list head.
  • int getRandom() Chooses a node randomly from the list and returns its value. All the nodes of the list should be equally likely to be chosen.

Example 1:

Input

["Solution", "getRandom", "getRandom", "getRandom", "getRandom", "getRandom"]

[[[1, 2, 3]], [], [], [], [], []]

Output

[null, 1, 3, 2, 2, 3]

Explanation

Solution solution = new Solution([1, 2, 3]);

solution.getRandom(); // return 1

solution.getRandom(); // return 3

solution.getRandom(); // return 2

solution.getRandom(); // return 2

solution.getRandom(); // return 3

// getRandom() should return either 1, 2, or 3 randomly. Each element should have equal probability of returning.

Constraints:

  • The number of nodes in the linked list will be in the range [1, 10^4].
  • -10^4 <= Node.val <= 10^4
  • At most 10^4 calls will be made to getRandom.

Follow up:

  • What if the linked list is extremely large and its length is unknown to you?
  • Could you solve this efficiently without using extra space?

题目大意

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

实现 Solution 类:

  • Solution(ListNode head) 使用整数数组初始化对象。
  • int getRandom() 从链表中随机选择一个节点并返回该节点的值。链表中所有节点被选中的概率相等。

解题思路

这个问题涉及到水塘抽样算法,目标是从未知长度的链表中随机选择一个节点。水塘抽样算法允许在遍历数据流的过程中,以等概率抽样其中的一个元素。

  1. 初始化水塘 result ,while 循环遍历链表。
  2. 从第一个节点开始,以递增的概率选择节点的值:
    • 对于第一个节点,以 1/1 的概率选择该节点的值,即 Math.floor(Math.random() * 1) === 0
    • 对于第二个节点,以 1/2 的概率选择该节点的值,即 Math.floor(Math.random() * 2) === 0
    • 对于第三个节点,以 1/3 的概率选择该节点的值,即 Math.floor(Math.random() * 3) === 0
    • 以此类推,对于第 k 个节点,以 1/k 的概率选择该节点的值。
  3. 最终返回水塘中随机选择的节点的值。

这个算法的核心思想是保持水塘 result 中的元素,以相同的概率来替换为新遇到的节点值。这样可以保证每个节点被选中的概率都是 1/n,其中 n 是节点的序号。最终在整个遍历过程中,所有节点都有相同的被选中的概率。这样实现了在未知长度链表中随机选择节点的目标。

时间复杂度 O(n),其中 n 是链表的节点数,空间复杂度 O(1)

代码

/**
 * @param {ListNode} head
 */
var Solution = function (head) {
  this.head = head;
};

/**
 * @return {number}
 */
Solution.prototype.getRandom = function () {
  let result;
  let node = this.head;
  let count = 0;
  // while 循环遍历链表
  while (node) {
    count++;
    // 生成一个 [0, count) 之间的整数
    // 这个整数等于 0 的概率就是 1/count
    if (Math.floor(Math.random() * count) == 0) {
      result = node.val;
    }
    node = node.next;
  }
  return result;
};

相关题目

相关题目
- [398. 随机数索引](https://leetcode.com/problems/random-pick-index)