文章目录

  • 链表
  • 链表的概念概念
  • 不同的链表类型
  • 单链表(linked list)
  • 双链表(double linked list)
  • 链表练习
  • 如何将一个list构造一个链表并编写一个打印单链表的函数
  • 反转链表
  • 合并两个排序的链表
  • 相交链表
  • 环形链表
  • 两数相加


链表

链表的概念概念

  • 链表是一种常见的链式结构(linked list)
  • 链表由节点链接而成
  • 每个链表的节点包含数据成员和指向下一个节点的指针

不同的链表类型

单链表(linked list)
  • 特点:
  • 1、可以方便地追加元素到链表尾部,O(1)
  • 2、不支持随机下标访问,查找元素地时间复杂度是O(n),需要从头开始一个个查找
class Node:
	def __init__(self, value, next=None):
		self.value = value
		self.next = next
双链表(double linked list)
  • 特点:
  • 1、可以给单链表再加一个指针(节点前后都有一个指针,左指针和右指针),指向前一个节点
  • 2、双链表可以支持反向遍历
  • 3、知道了双链表的一个节点后,可以将它的左指针或右指针指向另一个节点,即将两个节点串起来,从而实现**O(1)**插入,同理删除也是O(1)
  • 4、双链表还可以首位指针相连形成一个循环双端链表(至少两个节点)
  • 5、双链表可以高效地往两头增加或删除元素
class Node:
	def __init__(self, value, prev=None, next=None):
		self.value, self.prev, self,next = value, prev, next

链表练习

如何将一个list构造一个链表并编写一个打印单链表的函数
class LinkedListNode():
    def __init__(self, value, next=None):
        self.value = value
        self.next = next


def gen_linked_list(nums):

    if not nums:
        return None
    head = LinkedListNode(nums[0])
    cur = head
    for i in range(1, len(nums)):
        node = LinkedListNode(nums[i])
        cur.next = node
        cur = node
    return head


def print_linked_list(head):
    cur = head
    while cur:
        print('{}->'.format(cur.value), end='')
        cur = cur.next
    print('nil')

if __name__ == "__main__":
    nums = [1,2,3,4]
    head = gen_linked_list(nums)
    print_linked_list(head)
反转链表
  • 解法:
  • 第一种方法利用指针迭代,比较好理解
  • 第二种使用递归,找出最后一个节点,然后递归实现最后一个节点需要做的事情
class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        # 迭代 时间复杂度:O(n),空间复杂度:O(1)
        # pre = None
        # cur = head
        # while cur:
        #     nextnode = cur.next
        #     cur.next = pre
        #     pre = cur
        #     cur = nextnode
        # return pre

        # 递归 时间复杂度:O(n),空间复杂度:O(1)
        if not (head and head.next):
            return head
        newhead = self.reverseList(head.next)
        head.next.next = head
        head.next = None
        return newhead


# when-changed -r -v -1 'filepath' pytest -s 'filepath'
def test_reverselist():
    L = [1,2,3,4,5]
    head = gen_linked_list(L)
    print()
    print_linked_list(head)
    pre = Solution().reverseList(head)
    print_linked_list(pre)
合并两个排序的链表
  • 解法:
  • 纸上做草稿,使用指针完成
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

示例1:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
# Definition for singly-linked list.
class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution(object):
    def mergeTwoLists(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        pre = ListNode(0)
        cur = pre
        while l1 and l2:
            if l1.val <= l2.val:
                cur.next = l1
                l1 = l1.next
                cur = cur.next
            else:
                cur.next = l2
                l2 = l2.next
                cur = cur.next

        cur.next = l1 or l2
        return pre.next

def test_mergeTwoLists():
    l1 = gen_linked_list([1,2,4])
    l2 = gen_linked_list([1,3,4])
    s = Solution().mergeTwoLists(l1, l2)
    print_linked_list(s)


def gen_linked_list(nums):

    if not nums:
        return None
    head = ListNode(nums[0])
    cur = head
    for i in range(1, len(nums)):
        node = ListNode(nums[i])
        cur.next = node
        cur = node
    return head


def print_linked_list(head):
    cur = head
    while cur:
        print('{}->'.format(cur.val), end='')
        cur = cur.next
    print('nil')
相交链表
  • 解法:
  • 第一种方式,将长链表砍掉一部分使得它的长度与短链表一样长,然后判断
  • 第二种方式,将两个链表相交即长度都相等了,再判断
编写一个程序,找到两个单链表相交的起始节点。
class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        # 第一种方式,将长链表砍掉一部分使得它的长度与短链表一样长
        # if headA is None or headB is None:
        #     return None 

        # curA = headA
        # lenA = 0
        # while curA:
        #     lenA += 1
        #     curA = curA.next

        # curB = headB
        # lenB = 0
        # while curB:
        #     lenB += 1
        #     curB = curB.next
        
        # ldiff = abs(lenA-lenB) 
        # if lenA > lenB:
        #     for _ in range(ldiff):
        #         headA = headA.next
        # else:
        #     for _ in range(ldiff):
        #         headB = headB.next
        
        # while headA and headB:
        #     if headA == headB:
        #         # print(headA,headB)
        #         return headA
        #     headA = headA.next
        #     headB = headB.next
        
        # return None

        # 第二种方式,将两个链表相交即长度都相等了,再判断
        ha, hb = headA, headB
        while ha != hb:
            ha = ha.next if ha else headB
            hb = hb.next if hb else headA
        return ha
环形链表
  • 思路:
  • 1、开辟一个新的内存空间即创建一个set(集合),利用集合元素不重复的特性
  • 2、快慢指针,若闭环,快慢指针一定会相遇
给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
# Definition for singly-linked list.
class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution(object):
    def hasCycle(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """
        # 第一种使用hash表存储(集合,根据元素不重复的特性)
        # 时间复杂度O(n),空间复杂度O(n)
        # hash = {}
        # cur = head
        # while cur:
        #     if hash.get(cur.next) is not None:
        #         return True
        #     hash[cur] = 1
        #     cur = cur.next
        # return False
        
        # 利用快慢指针
        # 时间复杂度O(n),空间复杂度O(1)
        slow, fast = head, head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                return True
        return False
两数相加
  • 思路:
  • 1、竖式计算,定义多几个变量(指针)进行操作,会方便很多,重点在于获取值的方式,%10为获取个位,//10获取进位
  • 2、使用递归的方式
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution:
	# 迭代的方式
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        # 迭代的方式,创建了新的链表,空间复杂度O(n),时间复杂度O(n)
        pre = cur = ListNode(None) # pre变量用于返回,cur用于指向新创建的节点
        s = 0                       # 中间暂存变量
        while l1 or l2 or s:
            # if l1 == None:
            #     l1 = ListNode(0)
            # if l2 == None:
            #     l2 = ListNode(0)
            s += (l1.val if l1 else 0) + (l2.val if l2 else 0)  # 注意是+=,存储l1和l2节点的值
            cur.next = ListNode(s%10) # 新节点赋值  %10取个位
            s = s//10   # 取进位的值
            cur = cur.next # 使指向新节点的指针向前指
            l1 = l1.next if l1 else None # l1向前走
            l2 = l2.next if l2 else None # l2向前走
        return pre.next # 返回新节点的首节点

# 递归的方式,添加参数carry
# class Solution:
    # def addTwoNumbers(self, l1: ListNode, l2: ListNode, carry=0) -> ListNode:
    #     if l1==None and l2==None and carry==0:  
    #         return None

    #     if l1==None and l2==None and carry==1 :
    #         return ListNode(1)
        
    #     if l1==None :
    #         l1 = ListNode(0)
    #     if l2==None :
    #         l2 = ListNode(0)

    #     l1.val, carry = (l1.val+l2.val+carry)%10, (l1.val+l2.val+carry)//10
    #     l1.next = self.addTwoNumbers(l1.next, l2.next, carry)

    #     return l1


def test_addTwoNumbers():
    l1 = gen_linked_list([2,4,3,2])
    l2 = gen_linked_list([5,6,4])
    s = Solution().addTwoNumbers(l1,l2)
    print_linked_list(s)

def gen_linked_list(nums):

    if not nums:
        return None
    head = ListNode(nums[0])
    cur = head
    for i in range(1, len(nums)):
        node = ListNode(nums[i])
        cur.next = node
        cur = node
    return head


def print_linked_list(head):
    cur = head
    while cur:
        print('{}->'.format(cur.val), end='')
        cur = cur.next
    print('nil')