题目地址:
https://leetcode.com/problems/linked-list-random-node/
给定一个单链表,要求等概率随机返回其中一个节点。
蓄水池抽样算法。具体做法是,设一个变量 t t t,并遍历链表,当遍历到第 k k k个节点的时候,就以 1 k \frac{1}{k} k1的概率将当前节点的值赋值给 t t t。遍历完链表后返回 t t t即可。
算法正确性证明:
数学归纳法。当链表长度为
1
1
1的时候显然。设当链表长度为
n
n
n的时候,每个节点以
1
n
\frac{1}{n}
n1的概率返回。当链表长度为
n
+
1
n+1
n+1的时候,第
k
k
k个节点在遍历到第
n
n
n个节点存在
t
t
t里的概率是
1
n
\frac{1}{n}
n1,而最后一个节点“不上位”的概率是
n
n
+
1
\frac{n}{n+1}
n+1n,所以第
k
k
k个节点作为最后结果返回的概率是
1
n
n
n
+
1
=
1
n
+
1
\frac{1}{n}\frac{n}{n+1}=\frac{1}{n+1}
n1n+1n=n+11。算法正确。
代码如下:
import java.util.Random;
public class Solution {
private ListNode head;
private Random random;
/**
* @param head The linked list's head.
* Note that the head is guaranteed to be not null, so it contains at least one node.
*/
public Solution(ListNode head) {
this.head = head;
random = new Random();
}
/**
* Returns a random node's value.
*/
public int getRandom() {
int res = -1, n = 0;
for (ListNode cur = head; cur != null; cur = cur.next) {
n++;
// 以1/n的概率让cur上位
if (random.nextInt(n) == 0) {
res = cur.val;
}
}
return res;
}
}
class ListNode {
int val;
ListNode next;
public ListNode(int val) {
this.val = val;
}
}
时间复杂度 O ( n ) O(n) O(n),空间 O ( 1 ) O(1) O(1)。