大厂算法面试系列---链表操作

1、有序链表合并

1.1 两个有序链表合并

题目描述
给出两个有序的整数数组A和B,请将数组 B合并到数组A中,变成一个有序的数组
注意:
可以假设A数组有足够的空间存放B数组的元素,A和B中初始的元素数目分别为m和n 
  • 解题思路

      一般有递归与迭代两种方法,迭代方法后续补充

       方法一:递归

                    如果left或者right一开始就是空链表,那么没有任何操作需要合并,所以我们只需要返回非空链表。

                    否则,我们要判断left 和right 哪个链表的头节点的值更小,然后递归地决定下一个添加到结果里的节点,如果两个链表都为空,递归结束。

  • 复杂度分析  

           时间复杂度:

           O(n + m), 其中n, m分别为两个链表的长度。因为每次调用递归都会去掉left, right的头节点(直到其中一个为空),函数merge至多只会调用每个节点一次。因此,时间复杂度取决于合并后的链表的长度,即O(n + m)

           空间复杂度:

           O(n + m),其中n, m分别为两个链表的长度。递归调用merge函数时,需要耗费栈空间,栈空间的大小取决于递归调用的深度。结束递归调用时merge函数最多调用 n + m 次, 所以空间复杂度为O(n + m

  • 代码实现
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next

class Solution:
    def mergeTwoList(self, left, right):
        if left is None: return right
        if right is None: return left
        if left.val < right.val:
            left.next = self.mergeTwoList(left.next, right)
            return left
        else:
            right.next = self.mergeTwoList(left, right.next)
            return right

1.2  对K个有序链表合并

题目描述
合并 k 个已排序的链表并将其作为一个已排序的链表返回。分析并描述其复杂度。 
示例1
输入
[{1,2,3},{4,5,6,7}]
返回值
{1,2,3,4,5,6,7}
  • 解题思路

      采用分治法来合并有序链表

  • 代码实现
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        if len(lists) == 0 :
            return 
        head = None
        for list_ in lists:
            head = self.mergeTwoList(head, list_)
        return head

    def mergeTwoList(self, left, right):
        if left is None: return right
        if right is None: return left
        if left.val < right.val:
            left.next = self.mergeTwoList(left.next, right)
            return left
        else:
            right.next = self.mergeTwoList(left, right.next)
            return right

2、判断链表是否存在环

    hash map 与快慢指针

  • 解题思路

      方法一:快慢指针,如果慢指针能追上快指针说明存在环

      用一快一慢指针,开始两个指针都指向链表头部。慢指针每次向前走一步,快指针每次向前走两步。如果有环,则两个指针最终一定会相遇。这种方法无须额外的空间。

  • 代码实现
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

#
# 
# @param head ListNode类 
# @return bool布尔型
#
class Solution:
    def hasCycle(self , head ):
        # write code here
        if head is None or head.next is None:
            return False
        fast = head
        slow = head
        while (fast is not None) and (fast.next is not None):
            fast = fast.next.next
            slow = slow.next
            if fast == slow:
                return True
        return False

3、删除链表中一个元素

题目描述
给定一个链表,删除链表的倒数第n个节点并返回链表的头指针
例如,
 给出的链表为:1->2->3->4->5, n= 2.
 删除了链表的倒数第n个节点之后,链表变为1->2->3->5.
备注:
题目保证n一定是有效的
请给出请给出时间复杂度为\ O(n) O(n)的算法
  • 解题思路

        基本思路双指针,问题的关键在于找到倒数第N个节点,并且尽量只使用一次循环。

        采用双指针,对前指针,使其先走出N步,随后两指针同时前进,当前指针达到链表尾部时, 后指针到达倒数第N个节点的位置。

  • 代码实现
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

#
# 
# @param head ListNode类 
# @param n int整型 
# @return ListNode类
#
class Solution:
    def removeNthFromEnd(self , head , n ):
        # write code here
        if head is None and head.next is None:
            return head
        
        dummy = ListNode(0)
        dummy.next = head
        head = dummy
        
        fast = head
        slow = head
        
        for _ in range(n):
            fast = fast.next
            
        while fast.next:
            slow = slow.next
            fast = fast.next
            
        temp = slow.next
        slow.next = slow.next.next
        return dummy.next

猜你喜欢

转载自blog.csdn.net/jinhao_2008/article/details/114071160
今日推荐