leetcode链表总结(一)

本文详细介绍了LeetCode中涉及链表操作的几道经典题目,包括两数相加、删除链表节点、合并有序链表、两两交换节点等,并提供了相应的解题思路和代码实现。通过这些实例,深入理解链表操作和算法优化。

本次题目列表为


2. 两数相加 - 力扣(LeetCode) (leetcode-cn.com)

简单题 要注意进位问题和最后对进位参数的处理

思路:

1用两个指针分别遍历两个链表,遍历条件是只要有一个链表还有后继节点就继续遍历

2储存当前节点的值,对其进行运算,加上上一次进位的值,储存前要先判断节点是否为空,如果空则设置值为0

3取余作为当前节点值,取整作为下一节点值

4判断两个指针是否到结尾,如果到结尾设置为0

5遍历结束,如果进位值存在,节点加1

6返回头节点,结束

代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        #优化于2022.3.21 来源于评论区
        flag = 0
        p, q, r = l1, l2, ListNode(0) # 新建了链表的头节点 但是返回值是从头节点的下一个节点开始返回
        head = r # 储存表头节点
        while (p or q): #只要有一个非None就要一直加
            x = p.val if p else 0
            y = q.val if q else 0 #避免了Nonetype报错
            r.next = ListNode((x + y + flag) % 10) 
            # 要写在下面的flag前面 因为 接下来flag是下一个循环的flag
            flag = (x + y + flag) // 10 #进位 #这里的flag不要忘记了
            p = p.next if p else 0 
            #这里if后面好像带不带next都可以#错了 这里不能有next不然下次循环会出现0.next报错
            q = q.next if q else 0
            r = r.next
        if flag > 0:
            r.next = ListNode(1) #最后记得清空flag储存的值
        return head.next

 19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode) (leetcode-cn.com)

多种思路,本题采用思维最简单的一种,先确定长度再进行删除,时间复杂度O(N)

还可以用快慢指针来做

思路:

1遍历一次整个链表,获得链表节点数

2如果节点数等于N则返回head.next即可,否则找到倒数第N+1个节点,将其next修改为next.next从而略过中间的节点,达到删除节点的目的

3返回头节点

代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        if head == None:
            return head
        p = head
        # 以下为测试长度部分
        lenList = 0
        while p:
            p = p.next
            lenList += 1
        # 以上为测试长度部分
        q = head
        if lenList == n:
            #要考虑弹出第一个的情况
            return head.next
        else:
            for i in range(lenList - n - 1):
                q = q.next #到了要删除 的前一个
            if q.next != None:
                q.next = q.next.next # 要先判断q.next.next是否存在 比如单个节点需要直接接None
            else:
                head = None
                return None
            return head

21. 合并两个有序链表 - 力扣(LeetCode) (leetcode-cn.com) 

简单题

思路:

1用两个指针对两个链表同时进行遍历,结束条件是两个链表都到None

2每次遍历时,储存两个值,比较两个值大小,向新链表储存较小的值,保存较大的值用于下次比较

3遍历完返回新链表

代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
        p = list1
        q = list2
        r = ListNode(0)
        head = r
        while (p or q):
            x = p.val if p else 1000 #不存在用个很大的数代替
            y = q.val if q else 1000
            if y >= x: # 不一定都存在 需要进行判断
                r.next = ListNode(x)
                p = p.next if p else 0
                r = r.next
            else:
                r.next = ListNode(y)
                q = q.next if q else 0
                r = r.next
        return head.next

24. 两两交换链表中的节点 - 力扣(LeetCode) (leetcode-cn.com)

见往期

leetcode 24 两两交换链表中的节点_L1_Sta2的博客-优快云博客


 61. 旋转链表 - 力扣(LeetCode) (leetcode-cn.com)

中等难度题,要注意要动脑子,不能暴力无脑O(N²)否则会超时

思路:

1如果空链表直接返回链表

2遍历链表,确定链表的长度,最后一个节点的时候顺便将最后一个节点的后继节点设置为头节点

3用旋转次数对链表长度取余为n,余数即要将倒数第n个节点取下后链接到链表开头

4找到倒数第n+1个节点,先储存下一个节点即倒数第n个节点为表头head,再修改下一个节点为None(顺序切记不可颠倒)

5返回head

代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
        if not head:
            return head # 空链表 直接返回
        p = head
        lenth = 1
        while p.next:
            lenth += 1
            p = p.next
        # 找到链表总长度和最后一个节点
        p.next = head
        # 把最后一个节点连接到第一个节点 #这里提前弄了 节省时间
        k = k % lenth # 其实就是把倒数第这个数字的节点全都接到前面去
        for i in range(lenth - k):
            p = p.next # 找到前一个节点
        head = p.next # 设置新的表头
        p.next = None
        return head

82. 删除排序链表中的重复元素 II - 力扣(LeetCode) (leetcode-cn.com) 

中等难度题,要想想

由于头节点可能需要被删除,所以要先设置一个哑节点,即设置一个空头节点,做到这里才想到第19题也可以利用哑节点来解决删除数字等于链表长度问题

思路:

1判断链表是否为空或者为单节点链表,如果是直接返回即可

2新建一个哑节点new_head,值设置为0,后继节点为head

3用指针p对new_head进行遍历,条件是p.next 且p.next.next

这里用到了and短路的特性,如果直接p.next.next在链表的最后会触发NoneType的异常,因为NoneType无next

4遍历时如果存在下一节点的值和下下节点的值相等,储存下一节点的值,进入循环,循环中每次将p的后继节点设置为p.next.next即p.next = p.next.next这样结束循环时,当前节点就和中间被删除后的后一个节点相连

5如果不存在上述情况,指针向后移动一个节点

注意 这里一定要是不存在相等再后移,如果相等的循环结束之后也后移可能会导致连续的两组相同数值的后一组无法被删除,比如[1, 1, 2, 2]

6循环结束,返回哑节点的下一个节点

代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        if not head or head.next == None:
            return head # 当空链表或者单节点列表的时候直接返回
        new_head = ListNode(0, head) # 新建一个头节点
        p = new_head
        while p.next and p.next.next: # 不能直接p.next.next 要利用短路机制先判断p.next
            if p.next.next.val == p.next.val:
                memorry = p.next.val
                while p.next and p.next.val == memorry: # 同样需要先判断p.next是否存在
                    p.next = p.next.next
            else:
                p = p.next #需要放到else里面 放到外面的话无法消除连续两组相同的节点
        return new_head.next #不能返回head因为开头可能需要被删除 需要返回哑节点

83. 删除排序链表中的重复元素 - 力扣(LeetCode) (leetcode-cn.com)

简单题,没什么好写的,思路和上题大致相同,只是不需要哑节点,每次删除的时候保留第一个节点即可

代码:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        if not head: return head
        p = head
        while p.next :
            if p.val == p.next.val:
                x = p.val
                while p.next and p.next.val == x:
                    p.next = p.next.next
            else:
                p = p.next
        return head

86. 分隔链表 - 力扣(LeetCode) (leetcode-cn.com)

中等难度题

思路有二

(一)时间换空间

1两次遍历,第一次把比目标值小的加入新链表,第二次加入剩下的

2.返回

(二)空间换时间

1一次遍历,小的储存到small链表,大于等于的存到big链表

2small的尾节点指向big的表头并返回

但是事实上却发现结果与猜想截然相反,多次提交后第一种方法的时间消耗平均值小于第二种且内存大于第二种,第二种的时间消耗平均值大于第一种且内存消耗小于第一种。

平均下来(一)比(二)还快了8ms左右,内存却大了0.1M

不知道什么情况,希望有大佬看到后能不吝赐教

代码(注释部分为时间换空间):

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def partition(self, head: ListNode, x: int) -> ListNode:
        # 进阶版 一次循环 牺牲内存
        if not head:
            return head
        p = head
        q = small = ListNode(0)
        r = big = ListNode(0)
        while p:
            if p.val < x:
                q.next = ListNode(p.val)
                q = q.next
            else:
                r.next = ListNode(p.val)
                r = r.next
            p = p.next
        q.next = big.next
        return small.next
'''以下为原方法'''
# class Solution:
#     def partition(self, head: ListNode, x: int) -> ListNode:
#         # 脑袋做麻了 在一个链表里面整啥呢
#         p = head
#         new = ListNode(0)
#         q = new
#         while p:
#             if p.val < x:
#                 q.next = ListNode(p.val)
#                 q = q.next
#             p = p.next
#         # 第一遍循环 添加所有比x小的节点
#         p = head
#         while p:
#             if p.val >= x:
#                 q.next = ListNode(p.val)
#                 q = q.next
#             p = p.next
#         return new.next
'''以上为原方法'''

以上

坚持 共勉

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值