LeetCode382-链表随机节点
原题链接:【382. 链表随机节点】:https://leetcode-cn.com/problems/linked-list-random-node/
题目描述:
给定一个单链表,随机选择链表的一个节点,并返回相应的节点值。保证每个节点被选的概率一样。
进阶:
如果链表十分大且长度未知,如何解决这个问题?你能否使用常数级空间复杂度实现?
示例:
// 初始化一个单链表 [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()方法应随机返回1,2,3中的一个,保证每个元素被返回的概率相等。
solution.getRandom();
相关知识点:水塘抽样 链表 数学 随机化
解题思路:
一般的想法就是,我先遍历一遍链表,得到链表的总长度 n,再生成一个 [1,n] 之间的随机数为索引,然后再遍历链表,找到索引对应的节点,不就是一个随机的节点了吗?
但是由题目可知,链表十分大,且长度未知,也就说,我们不知道链表长度n,也就没办法取中间的随机数,那么我们应该怎么去取值呢?
由于是链表,所以我们可以一个节点一个节点遍历加载进入内存。虽然我们无法知道链表总长度,但是我们可以知道我们当前遍历的节点的长度i。
比如我们已经遍历了i个元素,可以从这i个元素中随机取了一个元素a,那如果现在再给你一个新元素b,你是继续留着a呢?还是抽取b作为样本结果呢?以什么样的原则来选择a和b呢?你的选择能够保证概率相等吗?
这里就用到了著名的蓄水池抽样算法。
蓄水池抽样算法
假设给定一个数据流,数据流长度N很大,如何从中随机选取k个数据,并且要保证每个数据被抽取到的概率相等。
当k = 1,只取一个元素时,要保证每条数据被抽取到的概率相等,那么每个数被抽取的概率应该为1/N,只要采取这种策略,只需要遍历一遍数据流就可以得到采样值,并且保证所有数据被选中的概率均为1/N
当k > 1,取k个元素时,要保证每条数据被抽取到的概率相等,那么每个数被抽取的概率应该为k / N。
算法实现思路为:
一个一个遍历数据流,在取第i个数据的时候,生成一个0到1的随机数p,如果p < k / i,替换池中任意一个数替换为第i个数;当p > k / i,继续保留前面的数。直到数据流结束,返回此k个数。但是为了保证计算准确性,一般是生成一个0到i的随机数,跟k相比。
图解如下:
本题题解:
注意这里其实就是K=1的情况,取随机数rand,范围为【0,i),随机数+1,变成【1,i】范围,两边都是闭合的,更容易理解。所以,原来的小于k,即小于1,现在+1,四舍五入都变成了1,所以边界判断范围就是,随机数rand=1,则样本替换为当前遍历的节点,否则保留之前的样本节点,继续往下遍历。
其余就都是链表的操作了。
代码实现如下:
//给定一个单链表,随机选择链表的一个节点,并返回相应的节点值。保证每个节点被选的概率一样。
//
// 进阶:
//如果链表十分大且长度未知,如何解决这个问题?你能否使用常数级空间复杂度实现?
//
// 示例:
//
//
//// 初始化一个单链表 [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()方法应随机返回1,2,3中的一个,保证每个元素被返回的概率相等。
//solution.getRandom();
//
// Related Topics 水塘抽样 链表 数学 随机化
// 172 0 //leetcode submit region begin(Prohibit modification and deletion) import java.util.Random; /**
* 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 { // 需要将链表传递给getRandom方法,所以只能提取作为类变量
ListNode head;
public Solution(ListNode head) {
this.head = head;
} public int getRandom() {
// 定义一个变量,存储采样的结果值
int result = 0;
// 定义一个变量i,标记遍历到了第几个节点
int i = 0;
// 将当前链表head指针赋值给cur
ListNode cur = head;
// 循环遍历链表
while (cur != null) {
i++;
// 取随机数rand 范围 [1, i]
int rand = new Random().nextInt(i) + 1;
// 因为rand最小值为1,这个边界只能取rand = 1
if (rand == 1) {
result = cur.val;
}
// 指针往后移动,遍历下一个节点
cur = cur.next;
} // 返回采样结果
return result;
}
} /**
* Your Solution object will be instantiated and called as such:
* Solution obj = new Solution(head);
* int param_1 = obj.getRandom();
*/
//leetcode submit region end(Prohibit modification and deletion)
LeetCode382-链表随机节点的更多相关文章
- [Swift]LeetCode382. 链表随机节点 | Linked List Random Node
Given a singly linked list, return a random node's value from the linked list. Each node must have t ...
- Java实现 LeetCode 382 链表随机节点
382. 链表随机节点 给定一个单链表,随机选择链表的一个节点,并返回相应的节点值.保证每个节点被选的概率一样. 进阶: 如果链表十分大且长度未知,如何解决这个问题?你能否使用常数级空间复杂度实现? ...
- [LeetCode] Linked List Random Node 链表随机节点
Given a singly linked list, return a random node's value from the linked list. Each node must have t ...
- 382 Linked List Random Node 链表随机节点
给定一个单链表,随机选择链表的一个节点,并返回相应的节点值.保证每个节点被选的概率一样.进阶:如果链表十分大且长度未知,如何解决这个问题?你能否使用常数级空间复杂度实现?示例:// 初始化一个单链表 ...
- [LeetCode] 382. Linked List Random Node 链表随机节点
Given a singly linked list, return a random node's value from the linked list. Each node must have t ...
- [CareerCup] 2.3 Delete Node in a Linked List 删除链表的节点
2.3 Implement an algorithm to delete a node in the middle of a singly linked list, given only access ...
- 【链表】在O(1)的时间删除链表的节点
/** * 在O(1)的时间删除链表的节点 * * @author * */ public class Solution { public static void deleteNode(Node he ...
- 剑指Offer:删除链表的节点【18】
剑指Offer:删除链表的节点[18] 题目描述 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3-& ...
- (CSDN迁移) 输入一个链表,从尾到头打印链表每个节点的值
题目描述 输入一个链表,从尾到头打印链表每个节点的值. 思路1. 翻转链表,使用java自带的翻转函数或者从头到尾依次改变链表的节点指针 /** * public class ListNode { * ...
随机推荐
- hadoop前期准备
最近想要学习一下hadoop,现在想边学习边记录下,方便以后自己或别人查看.(注意最好ubantu,jdk及其他软件选择32bit的,jdk最好7以上) 首先配置下jdk,下载下jdk的包,把jdk- ...
- oracle 数据库修改端口号1521
1.关闭监听 2.修改配置文件,port=1933 #vi $ORACLE_HOME/network/admin/listener.ora 3.登录并查看local_listener参数,因为使用的是 ...
- 【PowereDesigner】使用方法|mysql画图使用|不在跟新
自己画E-R图时, 运行:Power Designer ..1 ..2 ..3 可以先放两个空的实体,然后,分别修改属性(鼠标右键,最后一项Properties),名称为:学生.课程. ..4 创建一 ...
- 【Go语言学习笔记】Go的defer
关键字 defer ⽤于延迟一个函数或者方法(或者当前所创建的匿名函数)的执行. 注意,defer语句只能出现在函数或方法的内部. defer语句经常被用于处理成对的操作,如打开.关闭.连接.断开连接 ...
- 字符编码之间的转换 utf-8 , gbk等,(解决中文字符串乱码)
目录 1.背景. 2.编码的理解 3.编码之间的相互转化 4. str类型说明 5. 可以使用的编码类型 6.参考文章 1.背景 Python中与其他程序进行交互时,如果存在字符串交互,特别是字符串中 ...
- 多线程 | 03 | CAS机制
Compare and swap(CAS) 当前的处理器基本都支持CAS,只不过每个厂家所实现的算法并不一样罢了,每一个CAS操作过程都包含三个参数:一个内存地址V,一个期望的值A和一个新值B,操作的 ...
- 2021 羊城杯WriteUP
比赛感受 题目质量挺不错的,不知道题目会不会上buu有机会复现一下,躺了个三等奖,发下队伍的wp Team BinX from GZHU web Checkin_Go 源码下载下来发现是go语言写的 ...
- scrapy获取58同城数据
1. scrapy项目的结构 项目名字 项目名字 spiders文件夹 (存储的是爬虫文件) init 自定义的爬虫文件 核心功能文件 **************** init items 定义数据 ...
- Nginx支持WebSocket反向代理
WebSocket是目前比较成熟的技术了,WebSocket协议为创建客户端和服务器端需要实时双向通讯的webapp提供了一个选择.其为HTML5的一部分,WebSocket相较于原来开发这类app的 ...
- R数据分析:如何给结构方程画路径图,tidySEM包详解
之前一直是用semPlot这个包给来进行结构方程模型的路径绘制,自从用了tidySEM这个包后就发现之前那个包不香了,今天就给大家分享一下tidySEM. 这个包的很大特点就是所有的画图原始都是存在数 ...