基于力扣,分析链表操作

在力扣中,已经对单链表的节点有了定义。

        具有两个参数:该节点的值和指向下一个节点(类)的指针

如下所示:

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

目录

删除链表的倒数第 N 个结点

合并两个有序链表

反转链表

两两交换链表中的节点

K 个一组翻转链表 


删除链表的倒数第 N 个结点

 第一道题删除链表的倒数第 N 个结点

由于每个节点链接的是下一个节点,所以链表只能从前向后查询,不能从后向前查询。

所以我们并不能从后向前查询n个节点,

但是要找到这个节点,我们可以从前向后查询(s-n)个节点(假设共有s个节点)

所以这道题的思路是:首先查询所给链表总节点个数

                                    然后从前向后查询(s-n)个节点,使得这个节点前的那个节点直接链接到这                               个节点后的那个节点去(形式上删除这个节点)

代码如下:

# 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:

        def getLength(head: ListNode):
            lent = 0
            while(head):
                head = head.next
                lent = lent + 1
            return lent

        dummy = ListNode(0, head)
        cur = dummy
        lenth = getLength(head)
        for i in range(0, lenth-n):
            cur = cur.next
        cur.next = cur.next.next

        return dummy.next

注意:这里我们自己建立一个头节点(这里其实也可以不建) 


合并两个有序链表

第二道题合并两个有序链表

 一个基本的想法是把两个有序链表合成一个新的链表

这两个链表各有一个指针,

        给新链表一个元素,就往后移一个元素

        否则就不往后移

        对于新链表而言,每获得一个元素,指针就往后移一个元素

       

        这两个指针,用于比较两个有序链表最前端的两个元素的大小,小的则会赋值给新链表

        这个循环执行下去,直到其中一个链表被扫描完,此时新链表只需连接另一个链表剩余元素就可以了。

代码如下:

# 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, l1: ListNode, l2: ListNode) -> ListNode:

        dummy = ListNode(0)
        cur = dummy

        while(l1 and l2):
            if(l1.val < l2.val):
                cur.next = l1
                l1 = l1.next
            else:
                cur.next = l2
                l2 = l2.next
            cur = cur.next

        if(l1):
            cur.next = l1
        if(l2):
            cur.next = l2

        return dummy.next

 注意:这道题需要定义一个头指针(头节点),以使得对新链表的第一个节点创建 和 链表中的其他节点一样。


反转链表

第三道题反转链表

此处采用递推的想法来解决这个问题

我们需要为翻转后的链表构造一个为空的尾节点

从链表的第一个节点开始扫描,记录该节点后的节点,使当前节点与前一个节点相连(如果是第一个节点,它需要和那么构造的第一个节点相连)

更新前一个节点和当前节点

 代码如下:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        # 构造要连成链表的尾结点
        prev = None
        # 初始化当前节点(从头结点开始)
        curr = head
        while(curr != None):
            # 记录当前节点后的一个节点
            lian = curr.next
            # 当前节点和前一个节点相连
            curr.next = prev

            #递推
            prev = curr
            curr = lian

        return prev

 最后需要返回最后原链表最后一个节点(不是None)


两两交换链表中的节点

第四道题两两交换链表中的节点

这道题目我们采用递归的写法,我们首先保存下不为None的head.next.next节点

 采用递归的写法,我们将首先翻转链表尾部的两个节点,依次,最后再翻转头部的两个节点

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:
        if(not head or not head.next):
            return head 
        subResult = self.swapPairs(head.next.next)
        headNext = head.next
        headNext.next = head
        head.next = subResult

        return headNext

现在我们来考虑第四道题 合并K个升序链表

我们已经学会了合并两个有序链表,那么对于 合并k个有序链表

一种想法:

我们可以初始化一个空链表,只有一个为None的head节点,

        然后对于我们要合并的k个链表的操作一样:

                使得head链表首先与第一个链表合并,记为head链表

                使得head链表再与第二个链表合并,记为head链表

                ... ...

                head链表与第k个链表合并,记为head链表

                最后返回head

对应代码:

# 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:
        head = None
        for lNode in lists:
            head = self.merge(head, lNode)

        return head
    
    def merge(self, head: ListNode, lx: ListNode) -> ListNode:
        dummy = ListNode(0)
        cur = dummy

        while(head and lx):
            if(head.val < lx.val):
                dummy.next = head
                head = head.next
            else:
                dummy.next = lx
                lx = lx.next
            dummy = dummy.next

        if(head):
            dummy.next = head
        if(lx):
            dummy.next = lx

        return cur.next

K 个一组翻转链表 

第五道题K 个一组翻转链表

我们已经学会了如何翻转链表,

        那么我们只需要从第一个节点开始数k个节点,将第一个节点作为头节点,将第k个节点作为尾节点,对这k个节点翻转链表。

        如果我们数数不足k个,说明已经到了链表尾部。不需进行操作,直接返回头节点。

        需要注意的是我们需要记录头节点的前一个节点,和尾节点后的一个节点,因为翻转后的链表的头尾节点已不再和之前相同,我们需要将他们进行连接。

        每翻转k个节点,我们需要更新一下,需要连接的前一个节点pre,需要连接的后一个节点nex将在查k个节点的时候取得,以及便于循环操作的k个节点链表的head节点

代码如下:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverse(self, head: ListNode, tail: ListNode):
    # 构造要连成链表的尾结点
        prev = None
        # 初始化当前节点(从头结点开始)
        tailNext = tail.next
        curr = head
        while(curr != tailNext):
            # 记录当前节点后的一个节点
            lian = curr.next
            # 当前节点和前一个节点相连
            curr.next = prev

            #递推
            prev = curr
            curr = lian

        return prev, head

    def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
        hair = ListNode(0)
        hair.next = head
        # 赋予初值
        pre = hair
        tail = hair
        while(head):
            for i in range(k):
                tail = tail.next               
                if(not tail):
                    return hair.next
                # 若tail不为None,记录下翻转链表后的一个节点
                nex = tail.next
            head, tail = self.reverse(head, tail)
            # 每次循环需要记录翻转链表的前一个节点和后一个节点,即pre和nex
            # 使得pre和翻转后的链表和nex相连
            pre.next = head  
            tail.next = nex
            
            #为下一次循环更新pre    
            pre = tail
            head = tail.next
        
        return hair.next

最后,我们讲一道题目最长公共前缀

这道题目是给出一系列字符串列表,指出这些字符串的公共前缀是什么

我们可以先初始化一个字符串,记为这些字符串的公共前缀,然后依次找它与第0个,第1个,第2个,...,第n个字符串的公共前缀(这个字符串可以先初始化为第一个字符串)

那么最后这个字符串就是公共前缀

那么现在问题是怎么寻找两个字符串的公共前缀呢?

        我们可以从第0个字符开始寻找,如果相同,则在初始为空的两者公共前缀上连接这个字符,

        否则,寻找结束

        返回这个两个字符串的公共前缀

代码如下:

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        longestStr = strs[0]
        count = len(strs)
        for i in range(1, count):
            longestStr = self.longerStr(longestStr, strs[i])

        return longestStr

    def longerStr(self, str1, str2) -> str:
        commonStr = ''
        index = 0
        lenth = min(len(str1), len(str2))
        for i in range(index, lenth):
            if(str1[i] != str2[i]):
                break
            else:
                commonStr = commonStr + str1[i]
        
        return commonStr

欢迎交流、指正!

参考题解:

力扣

力扣

 力扣

​​​​​​力扣
      ​​​​​​力扣

力扣

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值