跳至主要內容

382. 链表随机节点


382. 链表随机节点

🟠   🔖  水塘抽样 链表 数学 随机化  🔗 力扣open 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 + M),其中 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随机数索引水塘抽样 哈希表 数学 1+🟠🀄️open in new window 🔗open in new window