Leetcode-链表专题

         本文声明:本文参考【代码随想录】的文章,思路以及代码。基于他的文章(希望大家直接去看原作者的优秀文章【代码随想录】,这篇博客仅为了记录自己的学习过程),形成了自己的,希望总结成自己的经验与知识,于是发表了这篇博客,如有不妥的地方欢迎大家指正。

链表的理论基础

1,链表的定义

        链表是通过指针串联起来的线性结构,每一个结点分为两个部分:数据域和指针域(用于指向下一个结点的指针)

        链表的定义定义代码如下:

// 单链表 C++
struct ListNode {
    int val;  // 节点上存储的元素
    ListNode *next;  // 指向下一个节点的指针
    ListNode(int x) : val(x), next(NULL) {}  // 节点的构造函数
};
#python
class ListNode:
    def __init__(self, val, next=None):
        self.val = val
        self.next = next

2,链表的分类

        角度一:有虚拟头结点 和 无虚拟头结点。 Tips:很多时候Leetcode都是提供无虚拟头结点的链表,此时可以考虑自己创造一个虚拟头结点(利用构造函数创建)

        角度二:单连表,双链表,循环链表, 循环双链表等 (理论知识扎实即可,一般用不到)、

3,链表特性:

        存储方式:数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。链表是通过指针域的指针链接在内存中各个节点。所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。

4,链表与数组的差异!!!

        待补充完善

链表的解题模板总结

        主要还是的区分开数组与链表两种存储结构以及差异。!!!易错点创建指针指向某一个结点,这里仅多了一个指向该结点的指针,没有多出一个结点哦(自己做题迷糊了两次)。解题模板与专题一大差不大,主要是熟悉链表这一存储方法和数据类型的操作方法,这部分专题多练,一定得多多多练习。

1,设计链表

        本题可多刷。设计并实现自己的链表:(很多时候会做题不行,基础的扎实)。实现 MyLinkedList 类:

  • MyLinkedList() 初始化 MyLinkedList 对象。
  • int get(int index) 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1 。
  • void addAtHead(int val) 将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。
  • void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
  • void addAtIndex(int index, int val) 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。
  • void deleteAtIndex(int index) 如果下标有效,则删除链表中下标为 index 的节点。
(版本一)单链表法
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:
        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:
        self.dummy_head.next = ListNode(val, self.dummy_head.next)
        self.size += 1

    def addAtTail(self, val: int) -> None:
        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:
        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:
        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
2,翻转链表

题目:Leetcode 206翻转链表icon-default.png?t=N7T8https://leetcode.cn/problems/reverse-linked-list/description/ 额外补充:建立单连的过程可分为:头插法和尾插法。每次把新节点插入到头节点之后,创建的单链表和数据输入顺序相反。尾插法:每次把新节点链接到链表的尾部,因此需要一个尾指针永远指向链表的尾节点。

 思路:有两种方法可实现:

        法1断链法:遍历一遍单连表,只需要改变链表结点的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表。

        法2头插法:将链表的每个结点从头开始遍历,对于遍历结点以头插法的形式加以虚拟头结点后面(因为头插法会实现倒序)

class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        #反转链表 两种方法:断链法 和 头插法
        if head == None or head.next == None:
           return head
        
        #尾部头插法
        newhead = head
        while newhead.next:
            newhead = newhead.next
        
        p = head
        while p != None and p != newhead:
            r = p.next  #防止断链
            p.next = newhead.next
            newhead.next = p
            p = r

        return newhead
        
"""
        #断链法 正确写法
        pre = None
        p = head
        while p:
            r = p.next  #防止断链
            p.next = pre
            pre = p
            p = r
        return pre

        自己写的有问题:
        pre = head
        p = head
        while p.next:
            r = p.next
            r.next = pre    #这里错啦   会导致转圈圈
            pre = r
            p = p.next      #这两处配合,闭环啦
        return pre

        混淆了指针与节点:(重大经验教训)
            认为r = p.next 此时就会右两个节点,其实不然只是加了一个指向那个节点的指针r
            除非你创建一个新结点是吧才会都一个节点node
"""
3,两两交换链表的结点

题目:Leetcode 24 两两交换链表中的结点icon-default.png?t=N7T8https://leetcode.cn/problems/swap-nodes-in-pairs/description/        没什么思路,这个题直接硬码。自己对链表掌握还有待提升,这个题写的很复杂

        注意如何创造头结点:调用构造方法(很多时候添加一个虚拟头结点,方便一万倍)

dummy_head = ListNode(next = head)
class Solution(object):
    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        #大佬写的,自己没写出来(基础语法不过关怕)
        dummyHead = ListNode(next = head)
        current = dummyHead

        # 必须有cur的下一个和下下个才能交换,否则说明已经交换结束了
        #若为单数, 5直接跟在3后面即可,无需改变:2 1 4 3 5
        while current.next and current.next.next:
            temp = current.next
            temp1 = current.next.next.next  #防止断链

            current.next = current.next.next
            current.next.next = temp    #上一行推进了一个next

            temp.next = temp1

            current = current.next.next
        
        return dummyHead.next    #自己写的要是有一个虚拟头结点,能省好几个指针
        


"""
    自己写的
    O(n) , S(n)有点大,但都是系数大,量级还好
        #先拆成两个表  再合并
        #本题没得技巧,全是感情
        if head == None or head.next == None:
            return head
        head1 = head
        head2 = head.next
        r1 = head1
        r2 = head2

        p = head2.next
        flag = 1
        while p:
            if flag == 1:
                r1.next = p
                r1 = p
                flag = 0
            elif flag == 0:
                r2.next = p
                r2 = p
                flag = 1
            p = p.next

        if r2.next :
            #单数节点
            r2.next = None
        else:
            #双数节点   最后3还是指向4的
            r1.next = None   #防止乱串啦

        head = head2
        while True:
            if head2:
                r = head2.next
                head2.next = head1
                head2 = r
            else:
                break
            
            if head1:
                r = head1.next
                head1.next = head2
                pre = head1
                head1 = r
            else:
                break
        
        #若为双数可以直接while结束就返回,若为单数还需要如下:
        if head2 == None:
            pre.next = head1

        return head
"""
4,删除链表的倒数第N个结点

题目:Leetcode 19删除链表倒数第N个1结点icon-default.png?t=N7T8https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/       思路分析:该题为典型的快慢指针(双指针法):fast指针先走N步,之后fast指针和slow指针同步移动,直至fast遍历结束。Tip:y有些小细节需要注意是否添加头结点,倒数第N个结点(slow与fast之间的距离),遍历结束的条件(fast == None, 还是 fast.next == None),以及删除diN个结点则slow最后应该停留正倒数第N+1个结点。

class Solution(object):
    def removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        #双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,
            #直到fast指向链表末尾。删掉slow所指向的节点就可以了。
        #自己写的,第二版:带虚拟头结点
        dummyHead = ListNode(next = head)

        fast = dummyHead
        slow = dummyHead
        while fast.next and n > 0:  #可以n >= 0 :让fast走n+1步, 下面的同步一点,while fast:
            fast = fast.next
            n -= 1
        
        if n > 0: return None   #n > len(head)
        else:
            while fast.next:
                fast = fast.next
                slow = slow.next
        
        slow.next = slow.next.next
        return dummyHead.next
5,环形链表

题目:Leetcode 142 环形链表2 中等难度icon-default.png?t=N7T8https://leetcode.cn/problems/linked-list-cycle-ii/description/        这个题正常做好难,到目前为止自己还没有理解清楚。但是用哈希法来说就几行代码,之间附代码啦:

class Solution(object):
    def detectCycle(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        """
        法一:从思路入手
            主要考察两知识点:
                判断链表是否环
                如果有环,如何找到这个环的入口
        
        问题一:判断链表是否有环:
            使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,
fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,
说明这个链表有环。 (一定可以相遇, 不会存在错过的情况)

        问题er:有环,如何找到这个环的入口
            没看懂......
        """
        slow = head
        fast = head
        
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            
            # If there is a cycle, the slow and fast pointers will eventually meet
            if slow == fast:
                # Move one of the pointers back to the start of the list
                slow = head
                while slow != fast:
                    slow = slow.next
                    fast = fast.next
                return slow
        # If there is no cycle, return None
        return None


"""
        #哈希表法
        if head == None :
            return None
        
        hasNode = set()
        p = head
        while p :
            if p in hasNode:
                return p
            hasNode.add(p)
            p = p.next
        
        return None
"""

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值