LeetCode 382. Linked List Random Node 解题报告
2016-09-22 21:24
405 查看
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 the same probability of being chosen.示例
// 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();
限制条件
What if the linked list is extremely large and its length is unknown to you? Could you solve this efficiently without using extra space?解题思路
我的思路:
不考虑限制条件,很直观的就是设置一个变量size,用于存储链表的大小。生成一个范围在[0, size]内的随机数random,从表头开始移动random个位置,返回对应节点存储的值。然而题目说了这个链表的长度很大,我们无法获得它的具体长度,同时不能使用额外的存储空间。其实就是不允许使用变量存储链表的长度,或是使用其他的STL存储链表的元素。
苦思之后,我不知道怎么办,还是惭愧地点开了LeetCode里这道题目的tag,是Reservoir Sampling。是一个我没有听过的算法,经过查资料学习,下面给出这道题正确的解法。
参考思路:
Reservoir Sampling是水塘抽样算法(又叫蓄水池抽样算法)。这个算法用在这道题上的思想是:在具有n个元素的链表中,对于第m个元素,以1m的概率选择它,有m−1m不被选择。这样每一个元素被选中的概率都是1n。证明如下:第m个元素最后被选中的概率 = m被选中的概率 × m之后的元素都不被选中的概率。
p(m)=1m×(mm+1×m+1m+2×...×n−2n−1×n−1n)=1n
可能有人会想:不用考虑m之前的元素么?是不用的,因为不管前面的元素是否被选中,只要m被选中而且之后的元素都不被选中的话,那么最后选择的元素就会是m。
在具体实现时,我们可以通过rand()%m得到范围为[0,m]的一个随机数。选择0作为标准,0在[0,m]中的概率是1m,所以rand()%m==0就相当于以1m选择第m个元素。程序的结束条件是遍历完所有的n个元素。
代码
我的代码
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: /** @param head The linked list's head. Note that the head is guaranteed to be not null, so it contains at least one node. */ Solution(ListNode* head): head(head), size(0) { for(ListNode *cur = head; cur; cur = cur->next) { size++; } } /** Returns a random node's value. */ int getRandom() { int random = rand() % size; ListNode *cur = head; for (int i = 0; i < random; i++) { cur = cur->next; } return cur->val; } private: ListNode *head; int size; }; /** * Your Solution object will be instantiated and called as such: * Solution obj = new Solution(head); * int param_1 = obj.getRandom(); */
参考代码
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: /** @param head The linked list's head. Note that the head is guaranteed to be not null, so it contains at least one node. */ Solution(ListNode* head): head(head) {} /** Returns a random node's value. */ int getRandom() { int random = head->val; ListNode *cur = head->next; for (int i = 2; cur; i++) { // choos i with a probability of 1/i if (rand() % i == 0) random = cur->val; cur = cur->next; } return random; } private: ListNode *head; }; /** * Your Solution object will be instantiated and called as such: * Solution obj = new Solution(head); * int param_1 = obj.getRandom(); */
总结
今天学到了一个之前没有接触过的新算法,感觉收获蛮大的,很开心呐。不过如果是我自己能够想出这种解法就更棒了(好吧, 我想多了。。。)。下面列出一些关于Reservoir Sampling的资料:1.huagong_adu: 蓄水池抽样——《编程珠玑》读书笔记。
2.数据工程师必知算法:蓄水池抽样
终于填好了这个坑,不容易,继续加油!
相关文章推荐
- HDFS中namenode的HA高可用机制
- Win10安装nodejs 错误代码2502,2503
- Node.js readline模块
- LeetCode-Swap Nodes in Pairs
- nodejs模块中exports和module.exports的区别
- nodejs 本地应用部署
- node js 异步执行流程控制模块Async介绍
- nodejs之async异步编程
- node+express----请求对象req
- 桶排序-Node.js-对象排序
- jsonp 演示实例 —— 基于node
- Node.js DNS模块
- Node.js--Hello word!
- [Leetcode] Count Complete Tree Nodes
- Is the built-in Promise of nodejs ready?
- JS_node_错误总结
- [LeetCode-Java]24. Swap Nodes in Pairs
- NodeJS基本
- NodeJs批量复制文件
- 桶排序-Node.js