题目概述:
链接:点我做题
题解
一、数组接收暴力算法
由于链表不支持随机访问,单链表只支持顺序访问,我们要用rand()
等概率的随机取一个0~length - 1的随机值然后直接访问是不可以的,为了随机访问我们可以先拷到一个数组里。
class Solution {
public:
Solution(ListNode* head)
{
ListNode* cur = head;
while (cur != nullptr)
{
_vec.push_back(cur->val);
cur = cur->next;
}
}
int getRandom()
{
return _vec[rand() % _vec.size()];
}
private:
vector<int> _vec;
};
时间复杂度:
O
(
n
)
、
O
(
1
)
O(n)、O(1)
O(n)、O(1)
空间复杂度:
O
(
n
)
O(n)
O(n)
二、随机生成步长直接往前走
我们在初始化的时候,顺便记录一下链表的长度_sz
,然后用rand()%_sz
等概率的取得一个
[
0
,
_
s
z
−
1
]
[0,\_sz - 1]
[0,_sz−1]随机数,然后从头往前走随机数步,返回对应位置的值。
class Solution {
public:
Solution(ListNode* head)
{
_head = head;
while (head != nullptr)
{
_sz++;
head = head->next;
}
}
int getRandom()
{
ListNode* cur = _head;
int walks = rand() % _sz;
while (walks--)
{
cur = cur->next;
}
return cur->val;
}
private:
ListNode* _head;
int _sz = 0;
};
时间复杂度:
O
(
n
)
、
O
(
n
)
O(n)、O(n)
O(n)、O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
三、蓄水池抽样算法
每次要返回随机结点的值时,就遍历一遍链表。
对遍历到第i个结点,利用rand()%i
随机等可能的取一个
[
0
,
i
)
[0,i)
[0,i)的整数
如果取到0,就让返回值变成当前结点的值
然后接着遍历下一个结点,重复上述过程
由概率论的知识,第i个结点的值成为返回值的概率等于
P
(
第
i
个
结
点
成
为
返
回
值
的
概
率
)
=
P
(
遍
历
到
i
时
从
[
0
,
i
)
选
中
了
0
且
第
i
+
1
个
结
点
没
有
被
选
中
且
.
.
.
且
第
n
个
结
点
没
被
选
中
)
P(第i个结点成为返回值的概率) \\= P(遍历到i时从[0,i)选中了0 且 第i+1个结点没有被选中 且 ... 且 第n个结点没被选中)
P(第i个结点成为返回值的概率)=P(遍历到i时从[0,i)选中了0且第i+1个结点没有被选中且...且第n个结点没被选中),
由于这些事件独立,所以有:
上式=1/i * (1 - 1/(i + 1)) * … *(1 - 1/n)
=1/i * i/(i + 1) *… * (n - 1)/n
=1/n
显然任意一个结点成为返回值的概率是相等的。
class Solution {
public:
Solution(ListNode* head)
{
this->_head = head;
}
int getRandom()
{
ListNode* cur = _head;
int ret = 0;
int i = 1;
//对遍历到第i个结点,随机等可能的取一个[0,i)的整数
//如果取到0,就让返回值变成当前结点的值
//然后接着遍历下一个结点,重复上述过程
//由概率论的知识,第i个结点的值成为返回值的概率为
//P(第i个结点成为返回值的概率) =
//P(遍历到i时从[0,i)选中了0 && 第i+1个结点没有被选中 && ... && 第n个结点没被选中)
//由于这些事件独立,所以
//上式=1/i * (1 - 1/(i + 1)) * ... *(1 - 1/n)
//=1/i * i/(i + 1) *... * (n - 1)/n
//=1/n
//显然是等概率的
while (cur != nullptr)
{
if (rand() % i == 0)
{
ret = cur->val;
}
cur = cur->next;
i++;
}
return ret;
}
private:
ListNode* _head;
};
时间复杂度:
O
(
1
)
、
O
(
n
)
O(1)、O(n)
O(1)、O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)