一、水库抽样算法
给你一个未知长度的单链表,请你设计一个算法,只能遍历一次,随机地返回连表中的一个节点,这里的随机是要求每个节点被返回的概率是1/n。
下面给出一个示例:
import random
class ListNode:
def __init__(self, value=0, next=None):
self.val = value
self.next = next
def get_random_node(head):
if not head:
return None
random_node = head
current = head
n = 1
while current:
if random.randint(1, n) == 1:
random_node = current
current = current.next
n += 1
return random_node
# 使用示例
# 创建一个简单的链表:1 -> 2 -> 3 -> 4
node4 = ListNode(4)
node3 = ListNode(3, node4)
node2 = ListNode(2, node3)
node1 = ListNode(1, node2)
# 获取随机节点
random_node = get_random_node(node1)
print("随机选中的节点值为:", random_node.val)
算法解释:
random_node
初始化为链表的头部节点。- 随着链表的遍历,逐步更新计数器
n
,并在每个节点上以1/n
的概率更新random_node
。 - 最终,当遍历结束时,
random_node
包含了以均等概率选择的链表中的一个节点,多次运行之后,random_node节点应该是均等选择各个节点
。
这种方法确保了每个节点被选中的概率是均等的,即 1/n
,其中 n
是链表的长度。这样做的优点是我们不需要知道链表的长度,也不需要存储额外的数据结构,从而保持了空间复杂度为 O(1),时间复杂度为 O(n)。
二、bingo棋盘
1、假设你有一个5*5的棋盘,第一行可选1-15之间的数字,第二行可选16-30的数字,后面的行依次类推,每一行的数字都不能重复,只能使用random(x,y)函数来确定每个位置的数字,random(x,y)函数会生成x-y之间的随机数,要求能够构造出所有可能且有效的棋盘。
第一问感觉还是比较简单的,这里描述一下自己的思路,不一定是正确的:
定义列表number = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
- 选择第一个数时,使用random(1, 15)生成一个随机数,假如生成的结果是4,将第4个位置对应的数字4和number的最后一个数字15交换,此时number = [1, 2, 3, 15, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 4]。
- 选择第二个数时,使用random(1, 14)生成一个随机数,假如生成的结果是1,将第1个位置对应的数字1和number的倒数第二个数字14交换,此时number = [14, 2, 3, 15, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 4]。
- 选择第三个数时,使用random(1, 13)生成一个随机数,假如生成的结果是4,将第4个位置对应的数字15和number的倒数第三个数字13交换,此时number = [14, 2, 3, 13, 5, 6, 7, 8, 9, 10, 11, 12, 15, 1, 4]。
- 这样执行五轮次之后,假设number = [14, 2, 3, 13, 12, 6, 7, 8, 11, 10, 9, 5, 15, 1, 4],此时number的最后五个数字就可以作为棋盘的第一行的数字,并且是随机且无重复的,这种方法理论上是可以取遍所有情况的。
- 同样,其他行按照此方法进行操作。
import random
def generate_board_row(start, end):
numbers = list(range(start, end + 1))
row = []
for i in range(5):
# 随机选取一个位置的数字
pick_index = random.randint(0, len(numbers) - 1 - i)
# 将选中的数字添加到行中
row.append(numbers[pick_index])
# 将选中的数字和当前最后一个可选数字交换
numbers[pick_index], numbers[-1 - i] = numbers[-1 - i], numbers[pick_index]
return row
def generate_full_board():
board = []
for i in range(5):
start = i * 15 + 1
end = start + 14
row = generate_board_row(start, end)
board.append(row)
return board
# 生成棋盘并打印结果
board = generate_full_board()
for row in board:
print(row)
2、如果你现在有5个棋盘呢?要保证五个棋盘都是随机,并且五个棋盘都不一样(只要有一个元素不一样,就认为棋盘不一样)
这个题目我的方法是按照上面只有一个棋盘时选择第一行的方法,现在改为使用上面的方法选择五个棋盘的第一行的第一个元素,通过上面的方法可以保证五个棋盘第一行第一个元素值不同,这样就可以保证五个棋盘是不同的,然后第一个棋盘第一个元素选定之后,使用number1列表记录所选择的元素,并放在最后,同样,其他棋盘的第一行选定之后,都使用一个number列表记录所选择数字并将其放在最后。当五个棋盘第一个数字都选定之后,再依次按照对应的number列表选择每个棋盘第一行的其他元素。
import random
def initialize_numbers(start, end):
return list(range(start, end + 1))
def pick_unique_first_elements(numbers_list, count):
picked = []
for _ in range(count):
index = random.randint(0, len(numbers_list) - 1)
picked.append(numbers_list.pop(index))
return picked
def generate_row(numbers, already_picked):
row = [already_picked]
numbers.remove(already_picked)
for _ in range(4):
pick_index = random.randint(0, len(numbers) - 1)
row.append(numbers[pick_index])
numbers[pick_index], numbers[-1] = numbers[-1], numbers[pick_index]
numbers.pop()
return row
def generate_full_board(first_elements):
boards = []
for first_element in first_elements:
board = []
start = 1
for i in range(5):
end = start + 14
numbers = initialize_numbers(start, end)
if i == 0:
row = generate_row(numbers, first_element)
else:
row = generate_row(numbers, numbers[random.randint(0, 14)])
board.append(row)
start += 15
boards.append(board)
return boards
# 初始化第一行的所有可能数字
first_row_numbers = initialize_numbers(1, 15)
# 为五个棋盘挑选不同的第一个元素
first_elements = pick_unique_first_elements(first_row_numbers, 5)
# 生成五个不同的棋盘
boards = generate_full_board(first_elements)
# 打印棋盘
for i, board in enumerate(boards):
print(f"Board {i+1}:")
for row in board:
print(row)
print()
# 输出
Board 1:
[2, 12, 5, 6, 14]
[20, 22, 25, 30, 23]
[37, 31, 42, 35, 36]
[49, 58, 59, 55, 48]
[68, 67, 65, 75, 74]
Board 2:
[3, 8, 4, 6, 11]
[25, 20, 24, 23, 30]
[37, 36, 44, 39, 42]
[47, 59, 50, 52, 48]
[65, 72, 68, 74, 67]
Board 3:
[12, 10, 4, 5, 9]
[25, 22, 19, 20, 24]
[33, 43, 35, 40, 45]
[50, 57, 60, 54, 51]
[61, 75, 64, 65, 67]
Board 4:
[4, 2, 3, 1, 14]
[29, 22, 27, 18, 23]
[43, 38, 31, 45, 44]
[50, 59, 54, 53, 46]
[73, 67, 75, 61, 63]
Board 5:
[13, 5, 12, 3, 9]
[19, 23, 29, 27, 22]
[40, 37, 43, 42, 45]
[53, 60, 47, 59, 56]
[62, 65, 68, 70, 73]