3 链表处理 9题
sy304: 链表遍历 简单
https://sunnywhy.com/sfbj/7/3/304
现有n个结点(编号为从1到n),以及链表的第一个结点的编号,请依次输出这条链表上每个结点的信息。
输入
第一行两个整数n、first(
接下来n行,每行给出一个结点的信息:
id data next其中整数id(1 <= id <= n)表示结点的编号(每个id只出现一次,顺序不定),整数data(1 <= data < 10^3^)表示结点的数据域,整数next(1 <= next <= n或 next = -1)表示当前结点指向的结点编号(其中next = -1表示NULL)。
输出
按链表结点的顺序,每行输出链表中一个结点的id、data、next,中间用空格隔开。
样例1
输入
5 2
1 10 3
2 35 5
3 12 -1
4 23 3
5 58 1输出
2 35 5
5 58 1
1 10 3
3 12 -1解释
第一个结点编号为2,因此整条链表为:2(35)->5(58)->1(10)->3(12)->NULL,结点4是多余的。
The user is asking for a Python program that simulates a linked list. The program should read a sequence of nodes from the input, build the linked list, and print the nodes in the order they appear in the linked list.
Here is a Python program that accomplishes this:
class Node:
def __init__(self, id, data, next):
self.id = id
self.data = data
self.next = next
def main():
n, first = map(int, input().strip().split())
nodes = {}
for _ in range(n):
id, data, next = map(int, input().strip().split())
nodes[id] = Node(id, data, next)
current = nodes[first]
while current:
print(f"{current.id} {current.data} {current.next}")
if current.next in nodes:
current = nodes[current.next]
else:
break
if __name__ == "__main__":
main()In this program, we define a Node class to represent a node in the linked list. The main function reads the number of nodes and the id of the first node from the input, then reads each node's id, data, and next id, and stores them in a dictionary. The program then starts from the first node and follows the next pointers to print each node in the order they appear in the linked list.
sy305: 链表的结点个数 简单
https://sunnywhy.com/sfbj/7/3/305
现有n个结点(编号为从1到n),以及链表的第一个结点的编号,求这条链表上的结点个数。
输入
第一行两个整数n、first(
接下来n行,每行给出一个结点的信息:
id data next其中整数id(1 <=id <= n)表示结点的编号(每个id只出现一次,顺序不定),整数data(1 <= data <= 10^3^)表示结点的数据域,整数next(1 <= next <= n或 next = -1)表示当前结点指向的结点编号(其中next = -1表示NULL)。
输出
输出一个整数,表示链表上的结点个数。
样例1
输入
5 2
1 10 3
2 35 5
3 12 -1
4 23 3
5 58 1输出
4解释
第一个结点编号为2,因此整条链表为:2(35)->5(58)->1(10)->3(12)->NULL。因此总共有4个结点。
The user is asking for a Python program that simulates a linked list. The program should read a sequence of nodes from the input, build the linked list, and print the number of nodes in the linked list.
Here is a Python program that accomplishes this:
class Node:
def __init__(self, id, data, next):
self.id = id
self.data = data
self.next = next
def main():
n, first = map(int, input().strip().split())
nodes = {}
for _ in range(n):
id, data, next = map(int, input().strip().split())
nodes[id] = Node(id, data, next)
current = nodes[first]
count = 0
while current:
count += 1
if current.next in nodes:
current = nodes[current.next]
else:
break
print(count)
if __name__ == "__main__":
main()In this program, we define a Node class to represent a node in the linked list. The main function reads the number of nodes and the id of the first node from the input, then reads each node's id, data, and next id, and stores them in a dictionary. The program then starts from the first node and follows the next pointers to count each node in the order they appear in the linked list. The program prints the count when it reaches a node with no next node.
sy306: 链表头插法 简单
https://sunnywhy.com/sfbj/7/3/306
现有n个结点(编号为从1到n),以及链表的第一个结点的编号,使用头插法在链表头部依次插入个结点,然后依次输出新链表上每个结点的信息。
输入
第一行两个整数n、first(
接下来n行,每行给出一个结点的信息:
id data next其中整数id(1 <=id <= n)表示结点的编号(每个id只出现一次,顺序不定),整数data(1 <= data <= 1000)表示结点的数据域,整数next(1 <= next <= n或 next = -1)表示当前结点指向的结点编号(其中next = -1表示NULL)。
接着在一行中给出一个整数m(1 <= m <=1000),表示待插入的结点个数。
接下来m行,每行给出一个待插入的结点信息:
id data其中整数id(1 <=id <= n)表示结点的编号(每个id只出现一次,顺序不定),整数data(1 <= data <= 10^3^)表示待插入的结点的数据域。
输出
按链表结点的顺序,每行输出链表中一个结点的id、data、next,中间用空格隔开。
样例1
输入
5 2
1 10 3
2 35 5
3 12 -1
4 23 3
5 58 1
2
6 21
7 18输出
7 18 6
6 21 2
2 35 5
5 58 1
1 10 3
3 12 -1解释
第一个结点编号为2,因此整条链表为:2(35)->5(58)->1(10)->3(12)->NULL,结点4是多余的。
接着在头部插入结点6(21),链表变为:6(21)->2(35)->5(58)->1(10)->3(12)->NULL;
最后在头部插入结点7(18),链表变为:7(18)->6(21)->2(35)->5(58)->1(10)->3(12)->NULL。
The user is asking for a Python program that simulates a linked list. The program should read a sequence of nodes from the input, build the linked list, insert new nodes at the head of the list, and print the nodes in the order they appear in the linked list.
Here is a Python program that accomplishes this:
class Node:
def __init__(self, id, data, next):
self.id = id
self.data = data
self.next = next
def main():
n, first = map(int, input().strip().split())
nodes = {}
for _ in range(n):
id, data, next = map(int, input().strip().split())
nodes[id] = Node(id, data, next)
head = nodes[first]
m = int(input().strip())
for _ in range(m):
id, data = map(int, input().strip().split())
new_node = Node(id, data, head.id)
nodes[id] = new_node
head = new_node
current = head
while current:
print(f"{current.id} {current.data} {current.next}")
if current.next in nodes:
current = nodes[current.next]
else:
break
if __name__ == "__main__":
main()In this program, we define a Node class to represent a node in the linked list. The main function reads the number of nodes and the id of the first node from the input, then reads each node's id, data, and next id, and stores them in a dictionary. The program then reads the number of new nodes and their id and data, creates a new node with the current head as its next node, and updates the head to the new node. The program then starts from the new head and follows the next pointers to print each node in the order they appear in the linked list.
sy307: 链表删除元素 中等
https://sunnywhy.com/sfbj/7/3/307
现有n个结点(编号为从1到n),以及链表的第一个结点的编号,请删去链表上所有数据域等于整数的结点,然后依次输出新链表上每个结点的信息。
输入
第一行三个整数n、first、k(1<=first<=n<=100,1<=k<=1000),分别表示结点的个数、链表第一个结点的编号、待删除结点的数据域;
接下来行,每行给出一个结点的信息:
id data next其中整数id(1 <=id <= n)表示结点的编号(每个id只出现一次,顺序不定),整数data(1 <= data <= 1000)表示结点的数据域,整数next(1 <= next <= n或 next = -1)表示当前结点指向的结点编号(其中next = -1表示NULL)。
数据保证至少有一个结点的数据域不为。
输出
按链表结点的顺序,每行输出链表中一个结点的id、data、next,中间用空格隔开。
样例1
输入
5 2 58
1 10 3
2 35 5
3 58 -1
4 23 3
5 58 1输出
2 35 1
1 10 -1解释
第一个结点编号为2,因此整条链表为:2(35)->5(58)->1(10)->3(58)->NULL,结点4是多余的。
由于结点3和结点5的数据域是58,因此删除结点3和结点5,得到新链表为:2(35)->1(10)->NULL
The user is asking for a Python program that simulates a linked list. The program should read a sequence of nodes from the input, build the linked list, delete nodes with a specific data value, and print the nodes in the order they appear in the linked list.
Here is a Python program that accomplishes this:
class Node:
def __init__(self, id, data, next):
self.id = id
self.data = data
self.next = next
def main():
n, first, k = map(int, input().strip().split())
nodes = {}
for _ in range(n):
id, data, next = map(int, input().strip().split())
nodes[id] = Node(id, data, next)
head = nodes[first]
prev = None
current = head
while current:
if current.data == k:
if prev is None:
head = nodes[current.next] if current.next in nodes else None
else:
prev.next = current.next
if prev.next in nodes:
prev.next = nodes[prev.next]
else:
prev = current
current = nodes[current.next] if current.next in nodes else None
current = head
while current:
print(f"{current.id} {current.data} {current.next}")
if current.next in nodes:
current = nodes[current.next]
else:
break
if __name__ == "__main__":
main()In this program, we define a Node class to represent a node in the linked list. The main function reads the number of nodes, the id of the first node, and the data value to delete from the input, then reads each node's id, data, and next id, and stores them in a dictionary. The program then starts from the first node and follows the next pointers to delete each node with the specified data value. The program prints the remaining nodes in the order they appear in the linked list.
核心思路
Python 中没有指针的概念,且题目给出的节点编号是离散的(虽然范围是
- 存储:使用字典
nodes,其中key是节点的 ID,value是一个元组或列表(data, next_id)。这样可以实现的查找速度。 - 遍历:从给定的
head开始,通过next_id不断查找字典中的下一个节点,直到-1。 - 筛选:在遍历过程中,如果当前节点的
data不等于待删除的,则将该节点的 ID 加入到一个列表 res中。 - 输出:遍历列表
res,依次输出。注意输出时的next必须指向列表中的下一个元素;如果是列表最后一个元素,next输出-1。
Python 代码实现
为了应对可能的大量输入(sys.stdin.read 进行快速 I/O。
import sys
def main():
# 1. 快速读取所有输入
input_data = sys.stdin.read().split()
if not input_data:
return
iterator = iter(input_data)
try:
# 读取头信息:节点数、头结点ID、待删除的值 k
n = int(next(iterator))
head = int(next(iterator))
k = int(next(iterator))
# 2. 构建字典存储链表节点
# nodes[id] = (data, next_node_id)
nodes = {}
for _ in range(n):
node_id = int(next(iterator))
data = int(next(iterator))
next_node = int(next(iterator))
nodes[node_id] = (data, next_node)
except StopIteration:
return
# 3. 遍历链表并进行过滤
valid_nodes = [] # 存储保留下来的节点ID
curr = head
# 顺着链表 next 指针走
while curr != -1:
# 获取当前节点的数据
# 注意:题目描述有“多余节点”,但顺着 next 指针走自然会忽略掉那些不在主链上的点
if curr in nodes:
data, next_id = nodes[curr]
# 如果数据不等于 k,则保留
if data != k:
valid_nodes.append(curr)
# 无论是否删除,都要走向原链表的下一个节点
curr = next_id
else:
# 理论上不应该走到这里,除非输入数据有误(next指到了不存在的ID)
break
# 4. 输出重构后的链表
# 需要重新建立 next 关系
count = len(valid_nodes)
for i in range(count):
curr_id = valid_nodes[i]
curr_data = nodes[curr_id][0] # 从字典里取回原始数据
# 确定新的 next 指向
if i < count - 1:
# 指向结果列表中的下一个 ID
next_output_id = valid_nodes[i+1]
else:
# 最后一个节点指向 -1
next_output_id = -1
print(f"{curr_id} {curr_data} {next_output_id}")
if __name__ == "__main__":
main()代码解析
sys.stdin.read().split():将所有输入一次性读入并按空白字符分割成列表。这比在循环中使用input()快得多,能有效防止超时。- 字典映射:
nodes[node_id] = (data, next_node)这一步相当于将乱序的输入整理成了可随机访问的“内存”。 - 逻辑删除:我们没有去修改字典里原本的
next值,而是建立了一个新的列表valid_nodes。只要数据不等于,就入队。 - 重构输出:这是关键的一步。原链表中,A 指向 B,B 指向 C。如果 B 被删除了,输出时 A 的
next应该直接变成 C 的 ID。这一点通过valid_nodes[i+1]自动实现了。
复杂度
- 时间复杂度:
。建立字典、遍历链表、输出结果各遍历一次。 - 空间复杂度:
。用于存储字典和结果列表。
sy308: 链表反转 中等
https://sunnywhy.com/sfbj/7/3/308
现有个结点(编号为从1到n),以及链表的第一个结点的编号,请将链表反转(结点顺序颠倒),然后依次输出新链表上每个结点的信息。
输入
第一行两个整数n、first(1<=first<=n<=100),分别表示结点的个数、链表第一个结点的编号;
接下来n行,每行给出一个结点的信息:
id data next其中整数id(1 <=id <= n)表示结点的编号(每个id只出现一次,顺序不定),整数data(1 <= data <= 1000)表示结点的数据域,整数next(1 <= next <= n或 next = -1)表示当前结点指向的结点编号(其中next = -1表示NULL)。
输出
按链表结点的顺序,每行输出链表中一个结点的id、data、next,中间用空格隔开。
样例1
输入
5 2
1 10 3
2 35 5
3 12 -1
4 23 3
5 58 1输出
3 12 1
1 10 5
5 58 2
2 35 -1解释
第一个结点编号为2,因此整条链表为:2(35)->5(58)->1(10)->3(12)->NULL,结点4是多余的。
将链表反转后可以得到新链表:3(12)->1(10)->5(58)->2(35)->NULL
首先,我们需要创建一个Node类来存储节点的信息,包括id、data和next。然后,使用字典来存储所有的节点。接着,我们需要根据输入的链表第一个节点的编号,找到链表的头节点,然后遍历链表,将链表中的节点按照顺序添加到一个新的列表中。反转新列表。最后,我们需要更新每个节点的next属性,使其指向新列表中的下一个节点,然后按照新的顺序输出每个节点的信息。
以下是实现这个过程的Python代码:
class Node:
def __init__(self, id, data, next):
self.id = id
self.data = data
self.next = next
n, first = map(int, input().split())
nodes = {}
for _ in range(n):
id, data, next = map(int, input().split())
nodes[id] = Node(id, data, next)
# Reverse the linked list
reversed_nodes = []
current = nodes[first]
while current is not None:
reversed_nodes.append(current)
if current.next != -1:
current = nodes[current.next]
else:
current = None
reversed_nodes.reverse()
# Update the next attribute of each node
for i in range(len(reversed_nodes) - 1):
reversed_nodes[i].next = reversed_nodes[i + 1].id
reversed_nodes[-1].next = -1
# Output the reversed linked list
for node in reversed_nodes:
print(node.id, node.data, node.next)这段代码首先读取输入,然后创建一个Node类的实例来存储每个节点的信息。然后,它遍历链表,将链表中的节点按照顺序添加到一个新的列表中。反转新列表。然后,它更新每个节点的next属性,使其指向新列表中的下一个节点。最后,它按照新的顺序输出每个节点的信息。
sy309: 链表去除重复元素 中等
https://sunnywhy.com/sfbj/7/3/309
现有n个结点(编号为从1到n),以及链表的第一个结点的编号,请去掉链表上所有数据域重复的结点(只保留第一个),然后依次输出新链表上每个结点的信息。
输入
第一行两个整数n、first(1<=first<=n<=100),分别表示结点的个数、链表第一个结点的编号;
接下来行,每行给出一个结点的信息:
id data next其中整数id(1 <=id <= n)表示结点的编号(每个id只出现一次,顺序不定),整数data(1 <= data <= 1000)表示结点的数据域,整数next(1 <= next <= n或 next = -1)表示当前结点指向的结点编号(其中next = -1表示NULL)。
输出
按链表结点的顺序,每行输出链表中一个结点的id、data、next,中间用空格隔开。
样例1
输入
5 2
1 10 3
2 35 5
3 58 -1
4 23 3
5 58 1输出
2 35 5
5 58 1
1 10 -1解释
第一个结点编号为2,因此整条链表为:2(35)->5(58)->1(10)->3(58)->NULL,结点4是多余的。
由于结点3和结点5的数据域是58,但结点5先出现,因此删除结点3,可以得到新链表:2(35)->5(58)->1(10)->NULL
首先,我们需要创建一个Node类来存储节点的信息,包括id、data和next。然后,我们需要创建一个字典来存储所有的节点,以便于我们可以通过节点的id快速找到节点。接着,我们需要根据输入的链表第一个节点的编号,找到链表的头节点,然后遍历链表,将链表中的节点按照顺序添加到一个新的列表中。在这个过程中,我们需要使用一个集合来存储已经出现过的数据,如果遇到重复的数据,我们就跳过这个节点。最后,我们需要更新每个节点的next属性,使其指向新列表中的下一个节点,然后按照新的顺序输出每个节点的信息。
以下是实现这个过程的Python代码:
class Node:
def __init__(self, id, data, next):
self.id = id
self.data = data
self.next = next
n, first = map(int, input().split())
nodes = {}
for _ in range(n):
id, data, next = map(int, input().split())
nodes[id] = Node(id, data, next)
# Construct the linked list and remove duplicates
unique_data = set()
filtered_nodes = []
current = nodes[first]
while current is not None:
if current.data not in unique_data:
unique_data.add(current.data)
filtered_nodes.append(current)
if current.next != -1:
current = nodes[current.next]
else:
current = None
# Update the next attribute of each node
for i in range(len(filtered_nodes) - 1):
filtered_nodes[i].next = filtered_nodes[i + 1].id
filtered_nodes[-1].next = -1
# Output the filtered linked list
for node in filtered_nodes:
print(node.id, node.data, node.next)这段代码首先读取输入,然后创建一个Node类的实例来存储每个节点的信息。然后,它遍历链表,将链表中的节点按照顺序添加到一个新的列表中,同时跳过数据域重复的节点。然后,它更新每个节点的next属性,使其指向新列表中的下一个节点。最后,它按照新的顺序输出每个节点的信息。
sy310: 升序链表中位数 中等
https://sunnywhy.com/sfbj/7/3/310
现有n个结点(编号为从1到n),以及升序链表的第一个结点的编号,求链表中结点数据域的中位数。
注:
- 升序链表指按结点连接顺序,结点的数据域是递增的链表;
- 如果结点个数为偶数,那么中位数指最中间两个数的平均值。
输入
第一行两个整数n、first(1<=first<=n<=100),分别表示结点的个数、链表第一个结点的编号;
接下来n行,每行给出一个结点的信息:
id data next其中整数id(1 <=id <= n)表示结点的编号(每个id只出现一次,顺序不定),整数data(1 <= data <= 1000)表示结点的数据域,整数next(1 <= next <= n或 next = -1)表示当前结点指向的结点编号(其中next = -1表示NULL)。
输出
输出中位数,保留一位小数。
样例1
输入
5 2
1 35 3
2 10 4
3 58 -1
4 12 5
5 23 1输出
23.0解释
第一个结点编号为2,因此整条链表为:2(10)->4(12)->5(23)->1(35)->3(58)->NULL。
由于有奇数个结点,因此中位数即最中间结点的数据域,即结点5的数据域23。
样例2
输入
5 2
1 23 3
2 10 5
3 58 -1
4 35 3
5 12 1输出
17.5解释
第一个结点编号为2,因此整条链表为:2(10)->5(12)->1(23)->3(58)->NULL,结点4是多余的。
由于有偶数个结点,因此中位数中间两个结点数据域的平均值,即结点5的数据域12和和结点1的数据域23的平均值17.5。
首先,我们需要创建一个Node类来存储节点的信息,包括id、data和next。然后,我们需要创建一个字典来存储所有的节点,以便于我们可以通过节点的id快速找到节点。接着,我们需要根据输入的链表第一个节点的编号,找到链表的头节点,然后遍历链表,将链表中的节点按照顺序添加到一个新的列表中。最后,我们需要找到新列表中的中位数。
以下是实现这个过程的Python代码:
class Node:
def __init__(self, id, data, next):
self.id = id
self.data = data
self.next = next
n, first = map(int, input().split())
nodes = {}
for _ in range(n):
id, data, next = map(int, input().split())
nodes[id] = Node(id, data, next)
# Construct the linked list
linked_list = []
current = nodes[first]
while current is not None:
linked_list.append(current)
if current.next != -1:
current = nodes[current.next]
else:
current = None
# Find the median
length = len(linked_list)
if length % 2 == 1:
median = linked_list[length // 2].data
else:
median = (linked_list[length // 2 - 1].data + linked_list[length // 2].data) / 2
print(f"{median:.1f}")这段代码首先读取输入,然后创建一个Node类的实例来存储每个节点的信息。然后,它遍历链表,将链表中的节点按照顺序添加到一个新的列表中。然后,它找到新列表中的中位数,并以一位小数的形式输出。
sy311: 链表倒数第k个结点 中等
https://sunnywhy.com/sfbj/7/3/311
现有n个结点(编号为从1到n),以及链表的第一个结点的编号,求该链表的倒数第k个结点(假设表示最后一个结点)。
输入
第一行三个整数n、first、k(1<=first<=n<=100,1<=k<=链表长度),分别表示结点的个数、链表第一个结点的编号、倒数的结点序号;
接下来n行,每行给出一个结点的信息:
id data next其中整数id(1 <=id <= n)表示结点的编号(每个id只出现一次,顺序不定),整数data(1 <= data <= 1000)表示结点的数据域,整数next(1 <= next <= n或 next = -1)表示当前结点指向的结点编号(其中next = -1表示NULL)。
输出
在一行中输出链表倒数第个结点的的id、data、next,中间用空格隔开。
样例1
输入
5 2 2
1 10 3
2 35 5
3 12 -1
4 23 3
5 58 1输出
1 10 3解释
第一个结点编号为2,因此整条链表为:2(35)->5(58)->1(10)->3(12)->NULL,结点4是多余的。
因此倒数第2个结点是结点1。
为了找到链表的倒数第k个节点,我们可以首先遍历整个链表,将所有节点存储在一个列表中。然后,我们可以简单地从列表中获取倒数第k个元素。
以下是实现这个过程的Python代码:
class Node:
def __init__(self, id, data, next):
self.id = id
self.data = data
self.next = next
n, first, k = map(int, input().split())
nodes = {}
for _ in range(n):
id, data, next = map(int, input().split())
nodes[id] = Node(id, data, next)
# Construct the linked list
linked_list = []
current = nodes[first]
while current is not None:
linked_list.append(current)
if current.next != -1:
current = nodes[current.next]
else:
current = None
# Find the kth node from the end
kth_node = linked_list[-k]
print(kth_node.id, kth_node.data, kth_node.next)这段代码首先读取输入,然后创建一个Node类的实例来存储每个节点的信息。然后,它遍历链表,将链表中的节点按照顺序添加到一个新的列表中。然后,它找到新列表中的倒数第k个元素,并输出其id、data和next。
sy312: 回文链表 中等
https://sunnywhy.com/sfbj/7/3/312
现有n个结点(编号为从1到n),以及链表的第一个结点的编号,判断该链表是否是回文的,即链表的结点按数据域正序和逆序是相同的。
输入
第一行两个整数n、first(1<=first<=n<=100),分别表示结点的个数、链表第一个结点的编号;
接下来行,每行给出一个结点的信息:
id data next其中整数id(1 <=id <= n)表示结点的编号(每个id只出现一次,顺序不定),整数data(1 <= data <= 1000)表示结点的数据域,整数next(1 <= next <= n或 next = -1)表示当前结点指向的结点编号(其中next = -1表示NULL)。
输出
如果链表是回文的,那么输出Yes,否则输出No。
样例1
输入
5 2
1 12 3
2 10 4
3 10 -1
4 12 5
5 23 1输出
Yes解释
第一个结点编号为2,因此整条链表为:2(10)->4(12)->5(23)->1(12)->3(10)->NULL。
显然链表是回文的。
样例2
输入
2 1
1 23 2
2 10 -1输出
No解释
第一个结点编号为1,因此整条链表为:1(23)->2(10)->NULL。
显然链表不是回文的。
为了判断链表是否是回文的,我们可以首先遍历整个链表,将所有节点的数据域存储在一个列表中。然后,我们可以检查这个列表是否等于它的逆序。
以下是实现这个过程的Python代码:
class Node:
def __init__(self, id, data, next):
self.id = id
self.data = data
self.next = next
n, first = map(int, input().split())
nodes = {}
for _ in range(n):
id, data, next = map(int, input().split())
nodes[id] = Node(id, data, next)
# Construct the linked list
linked_list = []
current = nodes[first]
while current is not None:
linked_list.append(current.data)
if current.next != -1:
current = nodes[current.next]
else:
current = None
# Check if the linked list is a palindrome
if linked_list == linked_list[::-1]:
print("Yes")
else:
print("No")这段代码首先读取输入,然后创建一个Node类的实例来存储每个节点的信息。然后,它遍历链表,将链表中的节点的数据域按照顺序添加到一个新的列表中。然后,它检查这个列表是否等于它的逆序,如果是,则输出"Yes",否则输出"No"。