算法&数据结构(四):链表

剑指offer:从尾到头打印链表

问题描述:输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

解法:栈 a=[]   a.append()    a.pop()     a.pop(0)

时间复杂度:O(n)

# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        node = []
        while listNode:
            node.append(listNode.val)
            listNode = listNode.next
        return node[::-1]

剑指offer:链表中倒数第k个结点

问题描述:输入一个链表,输出该链表中倒数第k个结点

解法:两个指针,距离为k,当走在前面的指针指向None,遍历结束,返回走在后面的指针

时间复杂度:O(n)

# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def FindKthToTail(self, head, k):
        # 指针头结点为空,k小于等于0
        if head is None or k <= 0:
            return None
        p_end = head
        p_res = head
        for i in range(k):
            # p_end从头结点开始,最大移动步数为节点个数,此时p_end指向None
            if p_end:
                p_end = p_end.next
            # 链表没有k个结点
            else:
                return None
        # 当p_end指向None时,循环结束
        while p_end:
            p_end = p_end.next
            p_res = p_res.next
        return p_res

剑指offer:反转链表

问题描述:输入一个链表,反转链表后,输出新链表的表头

解法:三个指针,pre-指向前一个结点,cur-当前结点,nex-保存当前结点曾经指向的位置

时间复杂度:O(k)

# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        if pHead is None or pHead.next is None:
            return pHead
        pre = None
        cur = pHead
        while cur:
            nex = cur.next
            cur.next = pre
            pre = cur
            cur = nex
        return pre

剑指offer:合并两个排序的链表

问题描述:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则

解法:递归的方式,返回链表1和2中指针指向的较小的值

时间复杂度:O(n)

class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        if pHead1 is None:
            return pHead2
        elif pHead2 is None:
            return pHead1
        if pHead1.val <= pHead2.val:
            head = pHead1
            head.next = self.Merge(pHead1.next, pHead2)
        else:
            head = pHead2
            head.next = self.Merge(pHead1, pHead2.next)
        return head

剑指offer:复杂链表的复制

问题描述:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head

解法:先克隆节点并且 A’ 链接到 A 后面,然后复制克隆节点指向对应的克隆节点,最后拆分成两个链表

时间复杂度:O(n)

# -*- coding:utf-8 -*-
# class RandomListNode:
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None
class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        # 1 创建克隆节点
        node = pHead
        if not node:
            return None
        while node:
            clone = RandomListNode(node.label)
            clone.next = node.next
            node.next = clone
            node = clone.next

        # 2 克隆节点指向克隆节点
        node = pHead
        while node:
            clone = node.next
            if node.random:
                clone.random = node.random.next
            node = clone.next

        # 3 长链表拆分为两个链表
        node = pHead
        if node:
            clone_head = clone = node.next
            node.next = clone.next
            node = node.next
        while node:
            clone.next = node.next
            clone = clone.next
            node.next = clone.next
            node = node.next
        return clone_head

leetcode:141. 环形链表

问题描述:给定一个链表,判断链表中是否有环

解法:边界条件是没有元素or只有一个元素,都无法构成环形。快指针领先一个位置,且速度快,如果不是环形会先到达终点。慢指针每次移动一步,而快指针每次移动两步。如果慢指针追上了快指针,说明是环形数组。

class Solution(object):
    def hasCycle(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """
        # 没有元素or只有一个元素,都无法构成环形
        if not head or not head.next:
            return False
        # 快指针在前面一步
        k1 = head
        k2 = head.next
        # 慢指针每次移动一步,而快指针每次移动两步
        while k1 != k2:
            # 快指针领先一个位置,且速度快,如果不是环形会先到达终点
            if k2 is None or k2.next is None:
                return False
            k1 = k1.next
            k2 = k2.next.next
        return True
        

剑指offer:两个链表的第一个公共结点

问题描述:输入两个链表,找出它们的第一个公共结点。

解法:

思路一:把两个链表放入两个栈里,找到最后一个相同的结点。注意公共结点可能在某一个链表的开始!

思路二:遍历链表的长度,长度差为k,长链表从k位置开始走,找到第一个公共结点

时间复杂度:O(m+n)

class Solution:
    def FindFirstCommonNode(self, pHead1, pHead2):
        # 思路一:把两个链表放入两个栈里,找到最后一个相同的结点
        if not pHead1 or not pHead2:
            return 
        stack1 = []
        stack2 = []
        while pHead1:
            stack1.append(pHead1)
            pHead1 = pHead1.next
        while pHead2:
            stack2.append(pHead2)
            pHead2 = pHead2.next
        # 提前保存原始链表长度
        length1 = len(stack1)
        length2 = len(stack2)
        node1 = []
        node2 = []
        while node1 == node2 and stack1 and stack2:
            node1.append(stack1.pop())
            node2.append(stack2.pop())
        if len(node1) <= 1 and node1 != node2:
            return 
        if node1 == node2:
            return node1[-1]
        else:
            return node1[-2]
        

        # 思路二:遍历链表的长度,长度差为k,长链表从k位置开始走,找到第一个公共结点
        if not pHead1 or not pHead2:
            return 
        dis1 = 0
        dis2 = 0
        node1 = pHead1
        node2 = pHead2
        # 计算第一个链表的长度
        while node1:
            dis1 += 1
            node1 = node1.next
        # 计算第二个链表的长度
        while node2:
            dis2 += 1
            node2 = node2.next
        # 较长链表先走k步,k=长度差
        if dis1 > dis2:
            k = dis1 - dis2
            while k:
                k -= 1
                pHead1 = pHead1.next
        else:
            k = dis2 - dis1
            while k:
                k -= 1
                pHead2 = pHead2.next
        # 同时遍历,找到第一个相同的结点
        while pHead1 != pHead2:
            pHead1 = pHead1.next
            pHead2 = pHead2.next
        return pHead2

leetcode:

问题描述:

解法:

时间复杂度:

剑指offer:

问题描述:

解法:

时间复杂度:

发布了93 篇原创文章 · 获赞 119 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_18310041/article/details/95196062