2022年1月16日
382. 链表随机节点
🌔题目描述
给你一个单链表,随机选择链表的一个节点,并返回相应的节点值。每个节点 被选中的概率一样 。
实现 Solution
类:
Solution(ListNode head)
使用整数数组初始化对象。int getRandom()
从链表中随机选择一个节点并返回该节点的值。链表中所有节点被选中的概率相等。
示例:
输入
["Solution", "getRandom", "getRandom", "getRandom", "getRandom", "getRandom"]
[[[1, 2, 3]], [], [], [], [], []]
输出
[null, 1, 3, 2, 2, 3]
解释
Solution solution = new Solution([1, 2, 3]);
solution.getRandom(); // 返回 1
solution.getRandom(); // 返回 3
solution.getRandom(); // 返回 2
solution.getRandom(); // 返回 2
solution.getRandom(); // 返回 3
// getRandom() 方法应随机返回 1、2、3中的一个,每个元素被返回的概率相等。
提示:
- 链表中的节点数在范围
[1, 104]
内 -104 <= Node.val <= 104
- 至多调用
getRandom
方法104
次
进阶:
- 如果链表非常大且长度未知,该怎么处理?
- 你能否在不使用额外空间的情况下解决此问题?
🎯题解
记录所有链表元素
我们可以在初始化时,用一个数组记录链表中的所有元素,这样随机选择链表的一个节点,就变成在数组中随机选择一个元素。
代码实现
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
List<Integer> list;
Random random;
public Solution(ListNode head) {
list=new ArrayList<Integer>();
while(head!=null){
list.add(head.val);
head=head.next;
}
random=new Random();
}
public int getRandom() {
return list.get(random.nextInt(list.size()));
}
}
/**
* Your Solution object will be instantiated and called as such:
* Solution obj = new Solution(head);
* int param_1 = obj.getRandom();
*/
//时间复杂度o(n)
//空间复杂度o(1)
复杂度分析
-
时间复杂度:初始化为 O(n) ,随机选择为 O(1) ,其中 n 是链表的元素个数。
-
空间复杂度:O(n) 。我们需要 O(n) 的空间存储链表中的所有元素。
蓄水池算法
使用蓄水池算法,用通俗的语言说一下:
- 如果我们池子中只有一个数字,那么拿到第一个数字的概率就是100%毋庸置疑。
- 两个数字50% 三个数字每个数字的几率都是33% 以此类推。。。。
当我们不知道池子里有多少个数字的时候,就需要用蓄水池的算法思想去计算。
- 当链表前行到第一个数字,此时取第一个数字的几率为100%,那result自然等于这个数字。
- 前进到第二个数字,那么此时取这个数字的几率自然就为50%(池子里只有两个数字),那么就是50%的几率取新数字,50%的几率保留原本的数字。
- 第三个数字的时候,33%的几率取当前最新的这个数字,66%的几率保留原本的数字。这66%中:原本的数字有50%的几率是1,有50%的几率是2。也就是此时三个数字的概率都为33%。 通过这个算法,就能达到取数的概率均摊,从而实现随机。
代码实现
class Solution {
ListNode head;
Random random;
public Solution(ListNode head) {
this.head=head;
this.random=new Random();
}
public int getRandom() {
// 蓄水池算法
// 第一次拿第一个数 第一个数的概率是100%
// 第二次 拿第二个数 取第二个数的概率是50%
// 第三次 拿第三个数是 33% 则保留原本数的概率是66%
ListNode p=this.head;
int count=0;
int res=0;
while(p!=null){
count++;
int randomint=random.nextInt(count)+1;//因为生成的是[0,count)的值 而不包含count 所以要加1
if(randomint==count){
res=p.val;
}
p=p.next;
}
return res;
}
}
//时间复杂度o(1)
//空间复杂度o(1)
复杂度分析
-
时间复杂度:初始化为 O(1) ,随机选择为 O(n) ,其中 n 是链表的元素个数。
-
空间复杂度:O(1) 。我们只需要常数的空间保存若干变量。
🐄我的看法
今天的题目是关于数据结构的一道题目,我并没有看的太懂,只是知道了大概的思路,Java数据结构我不是太了解,就不过多的解释了,我把官方的题解整理了一下,仅供参考。
加油,每天进步一点点!🎃