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.

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();

解:
虽然可以初始化的时候遍历一遍列表求的它的长度,但本题的意思是在不提前求得列表长度的时候,列表以顺序流的方式访问,如何得到一个随机的节点。

其实这是一个reservoir sampling的问题

https://en.wikipedia.org/wiki/Reservoir_sampling
PROBLEM:

Choose k entries from n numbers. Make sure each number is selected with the probability of k/n
BASIC IDEA:

Choose 1, 2, 3, …, k first and put them into the reservoir.
For k+1, pick it with a probability of k/(k+1), and randomly replace a number in the reservoir.
For k+i, pick it with a probability of k/(k+i), and randomly replace a number in the reservoir.
Repeat until k+i reaches n
PROOF:

For k+i, the probability that it is selected and will replace a number in the reservoir is k/(k+i)
For a number in the reservoir before (let’s say X), the probability that it keeps staying in the reservoir is
P(X was in the reservoir last time) × P(X is not replaced by k+i)
P(X was in the reservoir last time) × (1 - P(k+i is selected and replaces X))
= k/(k+i-1) × (1 - k/(k+i) × 1/k)
= k/(k+i)
When k+i reaches n, the probability of each number staying in the reservoir is k/n
EXAMPLE

Choose 3 numbers from [111, 222, 333, 444]. Make sure each number is selected with a probability of 3/4
First, choose [111, 222, 333] as the initial reservior
Then choose 444 with a probability of 3/4
For 111, it stays with a probability of
P(444 is not selected) + P(444 is selected but it replaces 222 or 333)
= 1/4 + 3/4*2/3
= 3/4
The same case with 222 and 333
Now all the numbers have the probability of 3/4 to be picked
THIS PROBLEM

This problem is the sp case where k=1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,以下是回复: 首先,我们可以使用Python语言来实现这个功能。具体步骤如下: 1. 导入random模块,用于生成随机数。 2. 定义一个链表类,包含节点类和链表类。 3. 定义一个函数,用于生成100个随机整数并存入链表。 4. 定义一个函数,用于将链表分为两个,一个存放所有负整数,另一个存放所有非负整数。 5. 输出三个链表,分别为原链表、负整数链表和非负整数链表。 具体代码如下: ```python import random # 节点类 class Node: def __init__(self, data): self.data = data self.next = None # 链表类 class LinkedList: def __init__(self): self.head = None # 在链表末尾添加节点 def append(self, data): new_node = Node(data) if self.head is None: self.head = new_node return last_node = self.head while last_node.next: last_node = last_node.next last_node.next = new_node # 输出链表 def print_list(self): curr_node = self.head while curr_node: print(curr_node.data, end=' ') curr_node = curr_node.next print() # 生成100个随机整数并存入链表 def generate_list(): linked_list = LinkedList() for i in range(100): linked_list.append(random.randint(-100, 100)) return linked_list # 将链表分为两个,一个存放所有负整数,另一个存放所有非负整数 def split_list(linked_list): negative_list = LinkedList() non_negative_list = LinkedList() curr_node = linked_list.head while curr_node: if curr_node.data < : negative_list.append(curr_node.data) else: non_negative_list.append(curr_node.data) curr_node = curr_node.next return negative_list, non_negative_list # 测试代码 if __name__ == '__main__': linked_list = generate_list() print('原链表:') linked_list.print_list() negative_list, non_negative_list = split_list(linked_list) print('负整数链表:') negative_list.print_list() print('非负整数链表:') non_negative_list.print_list() ``` 希望能对您有所帮助! ### 回答2: 将100个随机整数存储到链表中,我们可以定义一个链表节点结构体,包含一个整数类型的value和指向下一个节点的指针。然后从-100到100遍历100次,每次生成一个随机数,并将其加入链表中。 以下是示例代码: ```c++ #include <iostream> #include <cstdlib> #include <ctime> using namespace std; struct ListNode { int value; ListNode *next; ListNode(int value) : value(value), next(NULL) {} }; ListNode *createList() { srand(time(NULL)); ListNode *head = new ListNode(0); ListNode *tail = head; for (int i = 0; i < 100; i++) { int value = rand() % 201 - 100; ListNode *node = new ListNode(value); tail->next = node; tail = node; } return head->next; } void printList(ListNode *head) { while (head != NULL) { cout << head->value << " "; head = head->next; } cout << endl; } ListNode *splitList(ListNode *head) { ListNode *positiveHead = new ListNode(0); ListNode *positiveTail = positiveHead; ListNode *negativeHead = new ListNode(0); ListNode *negativeTail = negativeHead; while (head != NULL) { if (head->value >= 0) { positiveTail->next = head; positiveTail = head; } else { negativeTail->next = head; negativeTail = head; } head = head->next; } positiveTail->next = NULL; negativeTail->next = NULL; return make_pair(positiveHead->next, negativeHead->next); } int main() { ListNode *head = createList(); cout << "随机生成的链表为:"; printList(head); pair<ListNode *, ListNode *> result = splitList(head); cout << "正整数链表为:"; printList(result.first); cout << "负整数链表为:"; printList(result.second); return 0; } ``` 在这个代码中,我们生成了100个随机整数,并将它们存储到一个链表中。然后我们使用splitList函数将链表分成了两个链表,一个存储正整数,另一个存储负整数。最后我们输出了这两个链表。 ### 回答3: 本题要求的是随机生成100个整数,再将它们按照正负分为两个链表输出。因为需要使用链表来存储生成的数字,所以我们需要首先定义链表结构体,其具体实现如下: ```c typedef struct Node{ int data; struct Node* next; }Node, *LinkList; ``` 定义好链表结构体之后,我们需要计算随机生成100个整数的具体实现过程。由于本题所要求的整数范围在[-100,100]之间,因此,我们可以使用rand()函数生成一个在0到199之间的整数,然后将其减去100便可得到[-100,100]之间的整数。因此,生成100个整数的具体实现过程如下: ```c srand(time(NULL)); LinkList head = (LinkList)malloc(sizeof(Node)); head->next = NULL; int i = 0; for (i = 0; i < 100; i++){ int data = rand() % 200 - 100; Node* p = (Node*)malloc(sizeof(Node)); p->data = data; p->next = head->next; head->next = p; } ``` 上述代码中,我们利用rand函数生成了100个在[-100, 100]之间的随机整数,然后将这些整数保存到一个单向链表中,链表头为head。通过这个链表,我们可以遍历所有的生成的整数,并分别输出它们。具体的代码实现过程如下: ```c void printList(LinkList head){ Node* p = head->next; while (p != NULL){ printf("%d ", p->data); p = p->next; } } ``` 接下来,我们需要将链表中的整数根据它们的正负分成两个链表。本题中,我们可以使用两个指针分别遍历整个链表,当指针所指向的整数为负数时,将其赋值到一个新的链表中。最终,我们就可以得到两个链表,一个存放所有负整数,另一个存放所有非负整数。具体代码实现如下: ```c LinkList negative(LinkList head){ LinkList p = head->next; LinkList negHead = (LinkList)malloc(sizeof(Node)); negHead->next = NULL; while (p != NULL){ if (p->data < 0){ Node* q = (Node*)malloc(sizeof(Node)); q->data = p->data; q->next = negHead->next; negHead->next = q; } p = p->next; } return negHead->next; } LinkList nonNegative(LinkList head){ LinkList p = head->next; LinkList nonNegHead = (LinkList)malloc(sizeof(Node)); nonNegHead->next = NULL; while (p != NULL){ if (p->data >= 0){ Node* q = (Node*)malloc(sizeof(Node)); q->data = p->data; q->next = nonNegHead->next; nonNegHead->next = q; } p = p->next; } return nonNegHead->next; } ``` 最后,我们需要输出这两个分别存储所有负整数和非负整数的链表。当然,我们还是需要使用printList函数输出整数,只不过这次,我们需要对两个链表调用printList函数。这里不再赘述。 综上所述,随机生成100个整数存入链表,再将链表分为两个以存储正数和负数,输出这两个链表,是一道比较典型的链表操作题目。除了需要熟悉链表的定义、创建和输出之外,我们还需要使用原理较为简单的随机数生成算法,并对正负数分别进行分类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值