Description
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.
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?
Example:
// Init a singly linked list [1,2,3].
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
Solution solution = new Solution(head);
// getRandom() should return either 1, 2, or 3 randomly. Each element should have equal probability of returning.
solution.getRandom();
Solution
Cache + nextInt, constructor O(n), getRandom O(1), S(n)
将LinkedList的所有value按顺序添加到cache中,getRandom时只需对cache.size()进行采样,返回对应的值即可。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
private List<Integer> cache;
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) {
cache = new ArrayList<>();
random = new Random();
while (head != null) {
cache.add(head.val);
head = head.next;
}
}
/** Returns a random node's value. */
public int getRandom() {
return cache.get(random.nextInt(cache.size()));
}
}
/**
* Your Solution object will be instantiated and called as such:
* Solution obj = new Solution(head);
* int param_1 = obj.getRandom();
*/
Followup: Reservoir sampling, constructor O(1), getRandom O(n), S(1)
经典的蓄水池抽样算法,从n(非常大)个元素中随机选择k个元素,对应到这道题k = 1。
优点是不需要将LinkedList全部载入内存,可以以stream的形式更新random。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
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 val = head.val;
ListNode curr = head.next;
for (int i = 1; curr != null; ++i, curr = curr.next) {
if (random.nextInt(i + 1) == 0) { // random between [0, i]
val = curr.val;
}
}
return val;
}
}
/**
* Your Solution object will be instantiated and called as such:
* Solution obj = new Solution(head);
* int param_1 = obj.getRandom();
*/