技术面试必备:算法与链表实战演练
2024-02-13 15:51:43
今夜算法时刻,让我们一起踏上征程,探索算法与链表的世界。从尾到头打印链表、返回倒数第 k 个节点、环形链表、K 个一组翻转链表、只出现一次的数字,这些经典题目将成为我们今晚的训练场。
从尾到头打印链表
从尾到头打印链表是一个经典的算法问题。链表是一种线性的数据结构,由一组节点组成,每个节点包含一个值和一个指向下一个节点的指针。从尾到头打印链表需要逆向遍历链表,将每个节点的值从后往前打印出来。
我们可以使用栈或递归来解决这个问题。使用栈时,我们将节点压入栈中,然后弹出栈顶节点并打印其值。使用递归时,我们可以将问题分解为更小的子问题,即打印链表的剩余部分,然后再打印当前节点的值。
# 使用栈
def print_list_from_tail_using_stack(head):
stack = []
while head:
stack.append(head)
head = head.next
while stack:
print(stack.pop().val)
# 使用递归
def print_list_from_tail_using_recursion(head):
if head is None:
return
print_list_from_tail_using_recursion(head.next)
print(head.val)
返回倒数第 k 个节点
返回倒数第 k 个节点也是一个常见的算法问题。与从尾到头打印链表类似,我们需要遍历链表,但这次我们只需要找到第 k 个节点的值。
我们可以使用双指针法来解决这个问题。我们使用两个指针,一个指向链表头,另一个指向链表尾。我们先让尾指针向前移动 k 步,然后让两个指针同时向前移动。当尾指针到达链表末尾时,头指针指向的节点就是倒数第 k 个节点。
def find_kth_from_tail(head, k):
if head is None or k <= 0:
return None
fast = head
slow = head
for _ in range(k):
fast = fast.next
while fast is not None:
fast = fast.next
slow = slow.next
return slow
环形链表
环形链表是指链表中存在一个环,即链表中某个节点的 next 指针指向了之前的某个节点。检测环形链表的一个简单方法是使用快慢指针。
我们使用两个指针,一个指向链表头,另一个指向链表头。我们让快指针每次移动两步,慢指针每次移动一步。如果链表中有环,则快指针最终会追上慢指针。
def has_cycle(head):
if head is None or head.next is None:
return False
slow = head
fast = head.next
while slow != fast:
if fast is None or fast.next is None:
return False
slow = slow.next
fast = fast.next.next
return True
K 个一组翻转链表
K 个一组翻转链表是指将链表中的节点每 k 个一组翻转。例如,对于链表 1->2->3->4->5,k=2 时,翻转后的链表为 2->1->4->3->5。
我们可以使用双指针和递归来解决这个问题。使用双指针时,我们使用两个指针,一个指向当前组的头节点,另一个指向当前组的尾节点。我们先将当前组的节点翻转,然后将尾节点的 next 指针指向下一组的头节点。使用递归时,我们可以将问题分解为更小的子问题,即翻转链表的剩余部分,然后翻转当前组的节点。
# 使用双指针
def reverse_k_group_using_two_pointers(head, k):
if head is None or k <= 1:
return head
dummy = ListNode(0)
dummy.next = head
prev = dummy
curr = head
while curr:
next_group_head = curr
for _ in range(k - 1):
next_group_head = next_group_head.next
if next_group_head is None:
return dummy.next
next_group_tail = next_group_head.next
next_group_head.next = None
prev.next = reverse_list(curr)
curr.next = next_group_tail
prev = curr
curr = next_group_tail
return dummy.next
# 使用递归
def reverse_k_group_using_recursion(head, k):
if head is None or k <= 1:
return head
curr = head
for _ in range(k):
if curr is None:
return head
curr = curr.next
new_head = reverse_list(head, curr)
head.next = reverse_k_group_using_recursion(curr, k)
return new_head
只出现一次的数字
只出现一次的数字是指在一个数组中,除了一个元素之外,其他所有元素都出现了两次。找出这个只出现一次的元素。
我们可以使用异或运算来解决这个问题。异或运算的性质是,相同的数字异或为 0,不同的数字异或为 1。因此,我们可以遍历数组,将每个元素与结果进行异或运算。最终的结果就是只出现一次的元素。
def find_single_number(nums):
result = 0
for num in nums:
result ^= num
return result
结语
算法与链表是技术面试中的重要组成部分。通过解决这些经典题目,我们可以提高算法思维和链表操作技能。在今后的学习和工作中,这些知识和技能将为我们解决实际问题提供坚实的基础。