📅  最后修改于: 2023-12-03 14:50:22.681000             🧑  作者: Mango
链表是常见的数据结构之一,面试中也是常考的知识点。下面介绍了前20名链表面试问题,希望对程序员们有所帮助。
常见的链表操作有以下几种:
这是面试中最常考的问题之一。要求反转一个单向链表的结构。可以使用迭代或递归两种方法实现。下面是迭代的实现方法:
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
prev = None
while head:
curr = head
head = head.next
curr.next = prev
prev = curr
return prev
题目要求返回位于单向链表中倒数第N个节点的数据。具体可以使用两个指针,先将其中一个指针向后移动N个位置,然后两个指针同时向后移动,直到第一个指针到达链表结尾。此时第二个指针所指位置即为倒数第N个节点。
class Solution:
def findNthFromEnd(self, head: ListNode, n: int) -> ListNode:
first, second = head, head
for i in range(n):
if not first:
return None
first = first.next
while first:
first = first.next
second = second.next
return second
检查一个链表是否有环,也是面试中常见的问题。可以使用双指针的方法,一个指针走一步,一个指针走两步,若出现两个指针指向同一个节点,则说明链表中有环。
class Solution:
def hasCycle(self, head: ListNode) -> bool:
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
删除链表中的指定元素只需要遍历链表,找到并删除目标元素即可。需要注意的是,如果要删除的元素在链表头部,则需要特判。
class Solution:
def removeElements(self, head: ListNode, val: int) -> ListNode:
sentinel = ListNode(0)
sentinel.next = head
prev, curr = sentinel, head
while curr:
if curr.val == val:
prev.next = curr.next
else:
prev = curr
curr = curr.next
return sentinel.next
将两个有序链表合并成一个有序链表,可以使用递归实现。
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
if not l1:
return l2
if not l2:
return l1
if l1.val < l2.val:
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
else:
l2.next = self.mergeTwoLists(l1, l2.next)
return l2
去除链表中重复的元素。可以使用一个指针来遍历链表,如果找到了重复元素,则将该元素删除。需要注意的是,如果有多个重复元素,则需要一次性删除。
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
sentinel = ListNode(0)
sentinel.next = head
prev, curr = sentinel, head
while curr:
if curr.next and curr.val == curr.next.val:
while curr.next and curr.val == curr.next.val:
curr = curr.next
prev.next = curr.next
else:
prev = prev.next
curr = curr.next
return sentinel.next
将链表向右旋转k个位置。可以使用双指针的方法,让其中一个指针先走k步,然后两个指针同时走,直到第一个指针走到链表结尾。此时第二个指针所指节点即为链表旋转后的头节点。
class Solution:
def rotateRight(self, head: ListNode, k: int) -> ListNode:
if not head or not head.next:
return head
n = 1
curr = head
while curr.next:
curr = curr.next
n += 1
curr.next = head
k = k % n
for i in range(n - k):
curr = curr.next
head = curr.next
curr.next = None
return head
将链表中的奇数位置和偶数位置上的节点分别连接起来,形成一个新的链表。可以使用双指针的方法实现。
class Solution:
def oddEvenList(self, head: ListNode) -> ListNode:
if not head:
return head
odd = head
even = head.next
evenHead = even
while even and even.next:
odd.next = even.next
odd = odd.next
even.next = odd.next
even = even.next
odd.next = evenHead
return head
将链表按照升序或降序排序。可以使用归并排序的思路实现。
class Solution:
def sortList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
slow, fast = head, head.next
while fast and fast.next:
slow = slow.next
fast = fast.next.next
mid = slow.next
slow.next = None
left = self.sortList(head)
right = self.sortList(mid)
def merge(l, r):
sentinel = ListNode(0)
curr = sentinel
while l and r:
if l.val < r.val:
curr.next = l
l = l.next
else:
curr.next = r
r = r.next
curr = curr.next
curr.next = l if l else r
return sentinel.next
return merge(left, right)
实现一个带有随机指针节点的链表的复制。可以使用哈希表存储原链表中每个节点和它对应的复制节点,然后再遍历一遍原链表,根据哈希表中保存的信息构建复制链表。
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
if not head:
return head
dic = {}
cur = head
while cur:
dic[cur] = Node(cur.val, None, None)
cur = cur.next
cur = head
while cur:
dic[cur].next = dic.get(cur.next)
dic[cur].random = dic.get(cur.random)
cur = cur.next
return dic[head]
给定两个单向链表,求它们相交的节点,如果不相交则返回空。可以分别求出两个链表的长度,然后让长链表先走一段距离,使得它们两个指针在同一起点上,然后再同时向后走,找到相交的位置。
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
currA, currB = headA, headB
lenA, lenB = 0, 0
while currA:
lenA += 1
currA = currA.next
while currB:
lenB += 1
currB = currB.next
currA, currB = headA, headB
if lenA > lenB:
for i in range(lenA - lenB):
currA = currA.next
if lenB > lenA:
for i in range(lenB - lenA):
currB = currB.next
while currA and currB:
if currA == currB:
return currA
currA = currA.next
currB = currB.next
return None
判断一个链表是否为回文链表。可以使用快慢指针的方法找到链表中间节点,然后将后半部分链表反转,判断两个链表是否相等即可。
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
if not head or not head.next:
return True
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
def reverseList(head):
prev = None
while head:
curr = head
head = head.next
curr.next = prev
prev = curr
return prev
last = reverseList(slow)
while head and last:
if head.val != last.val:
return False
head = head.next
last = last.next
return True
在插入排序中,我们每次将一个元素插入到已经排好序的序列中。在链表中实现插入排序,需要使用两个指针,一个指向已排好序的部分,另一个指向未排序的部分。
class Solution:
def insertionSortList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
dummy = ListNode(0)
dummy.next = head
lastSorted = head
curr = head.next
while curr:
if lastSorted.val <= curr.val:
lastSorted = lastSorted.next
else:
prev = dummy
while prev.next.val <= curr.val:
prev = prev.next
lastSorted.next = curr.next
curr.next = prev.next
prev.next = curr
curr = lastSorted.next
return dummy.next
给定两个非空链表表示两个非负整数,将它们相加并以链表的形式返回。可以遍历两个链表,并将它们对应位置的数字相加后构建新的链表。
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
dummy = ListNode(0)
curr = dummy
carry = 0
while l1 or l2:
sum = carry
if l1:
sum += l1.val
l1 = l1.next
if l2:
sum += l2.val
l2 = l2.next
carry = sum // 10
curr.next = ListNode(sum % 10)
curr = curr.next
if carry > 0:
curr.next = ListNode(carry)
return dummy.next
给定一个非负整数,表示链表中每个节点的值,将整数加1并以链表形式返回。可以将链表反转后,从头节点开始加1并进位,最后将链表再反转回来。
class Solution:
def plusOne(self, head: ListNode) -> ListNode:
def reverseList(head):
prev = None
while head:
curr = head
head = head.next
curr.next = prev
prev = curr
return prev
def addOne(head):
carry = 1
curr = head
while curr:
sum = curr.val + carry
carry = sum // 10
curr.val = sum % 10
if carry == 0:
break
curr = curr.next
if carry > 0:
curr.next = ListNode(carry)
return head
head = reverseList(head)
head = addOne(head)
head = reverseList(head)
return head
给定两个链表,判断它们是否相交。可以遍历一遍两个链表,记录下它们的长度,然后让长链表先走一定的距离,使得它们两个指针在同一起点上,然后同时向后移动,找到第一个相交的位置即可。
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
lenA, lenB = 0, 0
currA, currB = headA, headB
while currA:
lenA += 1
currA = currA.next
while currB:
lenB += 1
currB = currB.next
currA, currB = headA, headB
if lenA > lenB:
for i in range(lenA - lenB):
currA = currA.next
if lenB > lenA:
for i in range(lenB - lenA):
currB = currB.next
while currA and currB:
if currA == currB:
return currA
currA = currA.next
currB = currB.next
return None
将链表旋转k个位置,可以将链表看成一个环,然后将尾节点指向头节点,然后断开循环,找到新的头节点和尾节点即可。
class Solution:
def rotateRight(self, head: ListNode, k: int) -> ListNode:
if not head or not head.next:
return head
n = 1
curr = head
while curr.next:
curr = curr.next
n += 1
curr.next = head
k = k % n
for i in range(n - k):
curr = curr.next
head, curr.next = curr.next, None
return head
给出两个非负整数,每个整数都是由链表形式表示的,请将两个整数相加。
class Solution:
def addInList(self, head1: ListNode, head2: ListNode) -> ListNode:
def reverseList(head):
prev = None
while head:
curr = head
head = head.next
curr.next = prev
prev = curr
return prev
head1, head2 = reverseList(head1), reverseList(head2)
dummy = ListNode(0)
curr = dummy
carry = 0
while head1 or head2:
sum = carry
if head1:
sum += head1.val
head1 = head1.next
if head2:
sum += head2.val
head2 = head2.next
carry = sum // 10
curr.next = ListNode(sum % 10)
curr = curr.next
if carry > 0:
curr.next = ListNode(carry)
return reverseList(dummy.next)
给定链表,返回链表中间节点。如果有两个中间节点,则返回第二个中间节点。
class Solution:
def middleNode(self, head: ListNode) -> ListNode:
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
return slow