LeetCode讲解算法3-数据结构[链表](Python版)


一、链表

1.1 单链表

1.1.1 单链表定义

  带头节点的单链表

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

1.1.2 插入元素

  带头结点的单链表
  头节点在第i个位置插入elem

def Insert(head,i,elem):
	assert i >= 0 #断言,插入元素的位置必须大于等于0
	cur = head #指向头指针
	while(i!=0): #指向插入位置的前一个链表元素
		i -= 1 
		cur = cur.next
		if not cur:
			reuturn False #插入位置超出链表长度,返回False
	temp = cur.next #指向下一位置
	cur.next = elem #下一位置指向新元素
	elem.next = temp #元素的末尾指向下一个元素
	return True

  不带头节点的单链表
  在第i个位置插入elem

def Insert(i,elem): 
	global head #全局变量头指针
	assert i >=0 #断言,插入元素的位置必须大于等于0
	if(i==0): #插入的元素在第一个
		elem.next = head #插入元素的下一位指向头节点
		head = elem #令该元素为头节点
	cur = head #记录头节点
	while(i>1): #插入的元素大于第一个,指向插入位置的前一个链表元素
		i -= 1
		cur = cur.next
		if not cur:
			return False #插入位置超出链表长度,返回False
	temp = cur.next #指向下一位置
	cur.next = elem #下一位置指向新元素
	elem.next = temp #元素的末尾指向下一个元素
	return True

1.1.3 删除元素

def ListDelete(head,i):
	assert i>=0 #删除的元素位置大于等于0
	cur = head #记录头节点
	while(i!=0): #指向删除位置的前一个链表元素
		i -= 1 
		cur = cur.next
		if not cur.next
			return False #删除位置超出链表长度,返回False
	cur.next = cur.next.next #将待删除的元素隔过去
	return True

1.1.4 创建单链表

尾插法创建单链表
  带头结点的单链表

def BuildLink_Tail(l):
	if not l: #如果列表为空
		return None #返回空
	head = ListNode() #创建头节点
	temp = head #记录头节点
	for elem in l:
		temp.next = ListNode(elem) #当前指向下一个元素
		temp = temp.next #temo指针后移
	return head

head = BuildLink_Tail([1,2,3,4])
while head.next: #判断链表是否为空
	head = head.next #包含头节点所以,先后移
	print(head.val)

  不带头结点的单链表:

def BuildLink_Tail(l):
	if not l: #如果列表为空
		return None #返回空
	head = ListNode(l[0]) #头节点存储第一个元素
	temp = head #记录头节点
	for elem in l[1:]: #尾插插入元素
		temp.next = ListNode(elem)
		temp = temp.next
	return head
	
head = BuildLink_Tail([1,2,3,4])
while head: #当年节点是否为空
	print(head.val) #没有头节点,先打印
	head = head.next

头插法创建单链表
  带头节点的单链表

def BuildLink_Head(l):
	head = ListNode() #建立头节点
	for elem in l: #对元素遍历 
		temp = head.next #存储头节点
		head.next = ListNode(elem,temp) #头节点后插入新元素
	return head

不带头结点的单链表

def BuildLink_Head(l):
	head = None 
	for elem in l:
		head = ListNode(elem,head) #向头节点后插入元素
	return head

1.2 双链表

class DLinkNode:
	def __init__(self,val=0,next=None,prior):
		self.val = val
		self.next = next
		self.prior = prior #头指针

  解决单链表无法逆向索引的问题

二、例题

2.1 两数相加

  给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
  如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
  您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

"""
2. 两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能
存储一位数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
"""
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next

# 1. 定义单向链表
# class ListNode(object):
#     # 注意点:python中的空用None表示
#     # 1.1 初始化,初始化方法也就是构造函数,入参初始默认值
#     def __init__(self, val=0, next=None):
#         # 1.2 初始化私有属性
#         self.val = val
#         self.next = next
# 2. 定义解题类及方法
class Solution:
    # 2.1 定义方法,入参、出参做类型限制
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        # 2.2(关键点) 定义虚拟指针和当前指针,并同时指向初始化默认值为0的节点,该节点也是
        # 结果链表的头节点。dummy用于返回最后计算结果列表
        # 注意点:创建新节点不用new关键词,区别与其他编程语言
        dummy = curr = ListNode()
        # 2.3 定义并初始化进位
        carry = 0
        # 2.4(关键点)while循环同时遍历l1、l2,当不知道要循环多少次的时候要用while,
        # 注意点:while循环链表的时候,循环体中一定要有推进循环结束的指针后移,这里l1、l2、curr都要
        # 后移(定性加定量分析,涉及到3个指针的移动)
        # 注意点:不为空的判断选择简洁的方式,但这不是最严谨的方式
        # while l1 is not None or l2 is not None:
        while l1 or l2:
            # 2.5 同时取两个相加链表当前节点位的值,长度短的链表节点位的value取值为0
            x = l1.val if l1 else 0
            y = l2.val if l2 else 0

            # 2.6 处理结果链表头结点的下一节点的值(这也是返回值取头结点的下一节点的原因)
            # 和进位值,这里的carry是上一步结果中的进位值
            sum = x + y + carry
            # 2.7 计算当前位的值,基于该值创建节点,并将当前指针指向该节点
            curr.next = ListNode(sum % 10)
            # 2.8 将当前指针后移,注意顺序是先创建节点,再移动指针
            curr = curr.next
            # 2.9 计算进位值 "/"表示浮点数除法,返回浮点结果; "//"表示整数除法,返回不大于结果的一个最大的整数
            carry = sum // 10
            
            # 2.10 移动加数链表指针,移动前注意判断非空
            if l1:
                l1 = l1.next
            # 2.11 移动被加数位链表指针,移动前注意判断非空
            if l2:
                l2 = l2.next
        # 2.12 l1、l2移动结束后,如果进位值依然大于0,将当前进位值保存到当前指针的下一个节点(这一步是不是可以不要?)
        # 易错点:容易遗漏, 而且要写在while循环之外
        if carry:
            curr.next = ListNode(carry)
        # 易错点:不是返回dummy, 可以画图理解, 初始化时dummy、curr中的值是0
        return dummy.next

"""
总结:涉及到三次指针的移动,两次指针的赋值
方法名称:单链表求两数之和
步骤:
考查知识点:
关键点:定义1个虚拟指针,1个移动指针
"""

2.2 两两交换链表中的节点

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:

输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例 2:

输入:head = [1]
输出:[1]

解题思路
我们首先需要建立pre、node1、node2和lat四个指针即可。

pre   node1  node2   lat
 h  ->  1  ->  2  ->  3  ->  4

然后pre->next=node2;node2.next=node1;node1.next=lat

class Solution:
    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        h = ListNode(-1)
        h.next = head
        pre = h
        while pre.next != None and pre.next.next != None:
            node1 = pre.next
            node2 = node1.next
            lat = node2.next

            pre.next = node2            
            node2.next = node1
            node1.next = lat
            
            pre = node1

        return h.next

2.3 合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

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


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        if l1 and l2:
            if l1.val > l2.val: 
                l1, l2 = l2, l1
            l1.next = self.mergeTwoLists(l1.next, l2)
        return l1 or l2

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

总裁余(余登武)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值