学习笔记@代码随想录day4:链表part01&&链表part02

学习笔记@代码随想录day4:链表part01&&链表part02

链表定义补充

以下代码用于个人理解链表定义及调用过程。

#定义节点
class Node(object):
    def __init__(self,item):
        self.item=item
        self.next=None
#定义链表
class singlelikelist(object):
    def __init__(self):
        self._head= Node

if __name__=="__main__":
    #创建链表
    link_list=singlelikelist()
    node1=Node(1)
    node2 = Node(2)
    link_list._head=node1
    node1.next=node2
    # 访问链表
    print(link_list._head.item)  # 访问第一个结点数据
    print(link_list._head.next.item)  # 访问第二个结点数据

移除链表元素

from typing import Optional
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        '''方法一,无虚拟头节点'''
        #如果头节点值等于删除值
        # while head is not None and head.val == val:
        #     head = head.next
        # #如果非头节点值等于删除值
        # cul = head
        # while cul is not None and cul.next is not None:
        #     if cul.next.val == val:
        #         cul.next = cul.next.next
        #     else:
        #         cul = cul.next
        #return head
        '''方法二,有虚拟头节点'''
        dummy_head= ListNode(0,head)
        cul = dummy_head
        while cul is not None and cul.next is not None:
            if cul.next.val == val:
                cul.next = cul.next.next
            else:
                cul = cul.next
        return dummy_head.next
if __name__=="__main__":
    #head = ListNode(1, ListNode(2, ListNode(6, ListNode(3, ListNode(4, ListNode(5, ListNode(6)))))))
    head = ListNode(1, ListNode(2, ListNode(6, ListNode(3, ListNode(4, ListNode(5, ListNode(6)))))))
    val = 6
    s = Solution()
    # Call the removeElements method with the input linked list and value
    result = s.removeElements(head, val)
    current = result
    while current:
        print(current.val, end=" ")
        current = current.next

设计链表

使用虚拟头节点,避免特殊情况需要额外处理,比如头节点。
第n个节点前插入值时操作的也是第n个节点,而非前一个节点。

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

class MyLinkedList:

    def __init__(self):
        self.dummy_head=ListNode
        self.size =0

    def get(self, index: int) -> int:
        '''获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1 '''
        #如果不合法,返回-1
        if index <0 or index >=self.size:
            return -1
        #使用虚拟头节点
        current=self.dummy_head.next
        for i in range(index):
            current=current.next
        return current.val

    def addAtHead(self, val: int) -> None:
        '''将一个值为 val 的节点插入到链表中第一个元素之前。'''
        #ListNode(val, self.dummy_head.next) 创建一个新的节点,值为 val,并将它的 next 指针指向给定 index 处的当前节点。
        self.dummy_head.next=ListNode(val,self.dummy_head.next)
        self.size+=1


    def addAtTail(self, val: int) -> None:
        '''将一个值为 val 的节点追加到链表中作为链表的最后一个元素'''

        current=self.dummy_head
        while current.next:
            current=current.next
        current.next=ListNode(val)
        self.size+=1

    def addAtIndex(self, index: int, val: int) -> None:
        '''将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。
        如果 index 比长度更大,该节点将 不会插入 到链表中。'''
        if index <0 or index>=self.size:
            return
        current=self.dummy_head
        for i in range(index):
            current=current.next
        current.next =ListNode(val,current.next)
        self.size+=1

    def deleteAtIndex(self, index: int) -> None:
        ''' 如果下标有效,则删除链表中下标为 index 的节点'''
        if index <0 or index> self.size:
            return
        current=self.dummy_head
        for i in range(index):
            current= current.next
        current.next=current.next.next
        self.size-=1

以上代码是照着随想录的代码自己敲了一遍,有时间再来独立敲一遍。

反转链表

双指针法,理解写在了注释里

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        '''双指针法'''
        #初始化,最终结果是让cur指向pre,当cur指向None时终止,cur和pre指针同时向后移动
        cur = head
        pre = None
        #反转前先将下一个节点的值预先保存,不然经过反转,指针已经发生改变,无法找到下一个值
        while cur:
            #保存下一个节点
            temp=cur.next
            #令cur指向pre
            cur.next=pre
            #pre向后移动
            pre=cur
            #cur向后移动
            cur=temp
        return pre

递归法。初始调用时cur为头节点,pre为空,思想同双指针法。再次调用时cur指针和pre指针向后移动。

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        return self.reverse(head,None)
    def reverse(self,cur:ListNode,pre:ListNode):
        if cur==None:
            return pre
        temp=cur.next
        cur.next=pre
        #cur指针和pre指针向后移动,cur指针为cur.next,pre指针为cur
        return self.reverse(temp,cur)

链表part02:两两交换链表中的节点

首先需要设置虚拟头节点保持操作一致。虚拟头节点为初始cur,终止条件为cur.next为空(节点数为偶数)或者cur.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: Optional[ListNode]) -> Optional[ListNode]:
        # 定义虚拟头节点
        dummy_head = ListNode(next=head)
        cur = dummy_head
        while cur.next and cur.next.next:
            #假设为途中四个节点,虚拟头节点初始指向1
            #1.虚拟头节点指向2
            #2.2指向1
            #3.1指向3
            #虚拟头节点要改变指向的节点,所以预先要保存节点1
            temp=cur.next
            #同样节点2要改变指向的节点,因此要预先保存节点3
            temp1=cur.next.next.next
             #1.虚拟头节点指向2:开始指向1,现在指向1的下一个节点
            cur.next=cur.next.next
             #2.2指向1,原来指向2,现在指向1
            cur.next.next=temp
            #3.1指向3,操作完两个节点交换以后,cur指针移向下下个节点
            temp.next=temp1
            cur = cur.next.next
        return dummy_head.next

链表part02:删除链表的倒数第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: Optional[ListNode], n: int) -> Optional[ListNode]:
        #创建虚拟头节点
        dummy_head=ListNode(next=head)
        #创建两个指针,快指针和满指针,并将他们初始化为虚拟头节点
        slow=dummy_head
        fast=dummy_head
        # 快指针比慢指针慢n+1步
        for i in range(n+1):
            fast=fast.next
        #移动两个指针,知道快指针到达链表的末尾
        while fast:
            slow=slow.next
            fast=fast.next
        #通过更新第n-1个节点的next指针删除第n个节点
        slow.next= slow.next.next
         
        return dummy_head.next

一开始不理解倒数第n个节点式怎么找到的,看了代码以后理解了整个流程:
定义两个指针,同时移动,且快指针比慢指针快n+1步,那么当快指针到达链表末尾是,慢指针到达倒数第n+1个节点,恰好对第n个节点进行删除操作。

链表part02:链表相交

数值相同,不代表指针相同。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
'''
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。
如果两个链表不存在相交节点,返回 null 。
'''
class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
        lenA,lenB=00
        cur=headA
        #求链表A的长度
        while cur:
            cur=cur.next
            lenA+=1
        cur=headB
        #求headB的长度
        while cur:
            cur=cur.next
            lenB+=1
        curA=headA
        curB=headB
        #让curA为最长链表的头,lenB为其长度
        if lenA>lenB:
            curA,curB=curB,curA
            lenA,lenB=lenB,lenA
        for _ in range(lenB-lenA):
            curB=curB.next
        #遍历curA和curB,遇到相同则直接返回
        while curA:
            if curA==curB:
                return curA
            else:
                curA=curA.next
                curB=curB.next
        return None

照着随想录撸了下代码,不太理解。

链表part02:环形链表II

'''
给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 
为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。
如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
'''

a.判断是否有环
b.如何找到这个环的入口

判断是否有环

使用快慢指针法:分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
为什么一定会相遇?
这是因为fast是走两步,slow是走一步,其实相对于slow来说,fast是一个节点一个节点的靠近slow的,所以fast一定可以和slow重合。(环内肯定会重合

如何找到这个环的入口

这里不太明白,明日搞懂。

总结

因为有事拖了两天进度,今天也没能完成所有任务,改变下计划,每天先学习新知识,再把之前不够懂的搞懂,加油加油!
参考链接1:https://zhuanlan.zhihu.com/p/60057180
参考链接2:https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值