leetcode-链表【4need again】


链表的定义:

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

1、移除链表元素(done)

203 移除链表元素
移除头结点和移除其他节点的操作是不一样的,因为链表的其他节点都是通过前一个节点来移除当前节点,而头结点没有前一个节点。所以可以设置一个虚拟头结点,这样原链表的所有节点就都可以按照统一的方式进行移除了;return 头结点的时候,别忘了 return dummy.next,这才是新的头结点。

class Solution:
    def removeElements(self, head: ListNode, val: int) -> ListNode:
        dummy = ListNode(next=head) #添加一个虚拟节点
        
        h = dummy
        while h.next:
            if h.next.val == val:
                h.next = h.next.next
            else:
                h = h.next
        return dummy.next  #不是返回h

2、设计链表(不会)

707 设计链表
在这里插入图片描述

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

class MyLinkedList:
    def __init__(self):
        self.size = 0
        self.head = ListNode(0)  # 虚拟头部节点
        

    def get(self, index: int) -> int:
        # if index is invalid
        if index < 0 or index >= self.size:
            return -1
        
        curr = self.head
        # index steps needed 
        # to move from sentinel node to wanted index
        for _ in range(index + 1):
            curr = curr.next
        return curr.val
            

    def addAtHead(self, val: int) -> None:
        self.addAtIndex(0, val)
        

    def addAtTail(self, val: int) -> None:
        self.addAtIndex(self.size, val)
        

    def addAtIndex(self, index: int, val: int) -> None:
        if index > self.size:
            return
        
        if index < 0:  #负数,插入头部
            index = 0
        
        self.size += 1
        # find predecessor of the node to be added
        pred = self.head
        for _ in range(index):
            pred = pred.next
            
        # node to be added
        to_add = ListNode(val)
        # insertion itself
        to_add.next = pred.next
        pred.next = to_add
        

    def deleteAtIndex(self, index: int) -> None:
        # if the index is invalid, do nothing
        if index < 0 or index >= self.size:
            return
        
        self.size -= 1
        # find predecessor of the node to be deleted
        pred = self.head
        for _ in range(index):
            pred = pred.next
            
        # delete pred.next 
        pred.next = pred.next.next

3、反转链表(done)

206 反转链表

  • 首先定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。
  • 把 cur->next 节点用tmp指针保存一下,也就是保存一下这个节点, 将cur->next 指向pre。
  • cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时我们return pre指针就可以了。
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        pre = None #虚拟头节点,不能用ListNode(None)
        cur = head

        while cur:
            temp = cur.next  #保存一下 cur的下一个节点,因为接下来要改变cur->next
            cur.next = pre  #翻转指针 
            #更新pre、cur指针   
            pre = cur     
            cur = temp
        return pre

4、两两交换链表中的节点(not done)

24. 两两交换链表中的节点
在这里插入图片描述
创建哑结点 dummyHead,令 dummyHead.next = head。令 temp 表示当前到达的节点,初始时 temp = dummyHead。每次需要交换 temp 后面的两个节点。
如果 temp 的后面没有节点或者只有一个节点,则没有更多的节点需要交换,因此结束交换。否则,获得 temp 后面的两个节点 node1 和 node2,通过更新节点的指针关系实现两两交换节点。
具体而言,交换之前的节点关系是 temp -> node1 -> node2,交换之后的节点关系要变成 temp -> node2 -> node1,因此需要进行如下操作。

temp.next = node2
node1.next = node2.next
node2.next = node1

完成上述操作之后,节点关系即变成 temp -> node2 -> node1。再令 temp = node1,对链表中的其余节点进行两两交换,直到全部节点都被两两交换。
两两交换链表中的节点之后,新的链表的头节点是 dummyHead.next,返回新的链表的头节点即可。

class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:
        dummyHead = ListNode(next=head)
        temp = dummyHead
        while temp.next and temp.next.next:
            node1 = temp.next
            node2 = temp.next.next
            temp.next = node2
            node1.next = node2.next
            node2.next = node1
            temp = node1
        return dummyHead.next

5、删除链表倒数第N个节点(done)

19. 删除链表倒数第N个节点
要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点即可。

  • 定义fast指针和slow指针,初始值为虚拟头结点;
  • fast首先走n ;
  • fast和slow同时移动,直到fast指向末尾;
  • 删除slow指向的下一个节点
class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        dummy =ListNode(next=head)
        l = dummy

        f = head
        for i in range(n):
            f = f.next
        
        while f:
            l = l.next
            f = f.next
        
        l.next = l.next.next  #删除
        return dummy.next

6、链表相交(done while A != B:)

0207. 链表相交
根据快慢法则,走的快的一定会追上走得慢的。
在这道题里,有的链表短,他走完了就去走另一条链表,我们可以理解为走的快的指针。那么,只要其中一个链表走完了,就去走另一条链表的路。如果有交点,他们最终一定会在同一个位置相遇。

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        if not headA or not headB:
            return None
        
        A = headA
        B = headB
        while  A != B:
            A = A.next if A else headB  # 如果a走完了,那么就切换到b走
            B = B.next if B else headA  #同理,b走完了就切换到a
        return A

7、环形链表II(done 不是比较val)

142. 环形链表II
分别定义 fast 和 slow指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。

class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        slow, fast = head, head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            # 如果相遇
            if slow == fast:
                p = head
                q = slow
                while p!=q:
                    p = p.next
                    q = q.next
                #你也可以return q
                return p

        return None

8、两数相加

2. 两数相加

class Solution:
    def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        dummy = ListNode(0)
        pre = dummy
        s = 0 #进位

        while l1 or l2 or s :
            s += (l1.val if l1 else 0) + (l2.val if l2 else 0)
            pre.next = ListNode(s%10)
            pre = pre.next 

            if l1: l1 = l1.next
            if l2: l2 = l2.next

            s //= 10 
        return dummy.next 

9、链表相加(二)

25. 链表中的两数相加
本题的主要难点在于链表中数位的顺序与我们做加法的顺序是相反的,为了逆序处理所有数位,我们可以使用栈:把所有数字压入栈中,再依次取出相加。

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        s1, s2 = [], []
        while l1:
            s1.append(l1.val)
            l1 = l1.next
        while l2:
            s2.append(l2.val)
            l2 = l2.next
        
        ans = None
        s = 0       #进位
        while s1 or s2 or s:
            a = 0 if not s1 else s1.pop()   #l1倒序
            b = 0 if not s2 else s2.pop()   #l2倒序
            cur = a + b + s
            s = cur // 10
            cur %= 10
            curnode = ListNode(cur)
            curnode.next = ans
            ans = curnode
        return ans

方法二:先反转l1,l2,相加后再反转结果

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        head1,head2 = self.reverse(l1),self.reverse(l2)

        dummy = ListNode(0)
        pre = dummy 
        s = 0 #进位 

        while s or head1 or head2:
            s += (head1.val if head1 else 0) + (head2.val if head2 else 0)
            pre.next = ListNode(s%10)
            pre = pre.next 

            if head1: head1 = head1.next 
            if head2: head2 = head2.next 
            s //= 10
        return  self.reverse(dummy.next )
    

    def reverse(self, head: ListNode):
        pre = None 
        cur = head 

        while cur:
            tmp = cur.next  #保存节点 
            cur.next = pre 

            #更新
            pre = cur 
            cur = tmp 
        return pre

10、旋转链表

61. 旋转链表

# 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 k == 0 or not head or not head.next:
            return head
        
        #计算链表长度
        n = 1 
        cur = head
        while cur.next:
            cur = cur.next
            n += 1
        
        # k 为 n 的倍数时,新链表将与原链表相同
        if k % n == 0:
            return head
        
        #将链表的末尾节点,与头节点相连
        cur.next = head
        add = n - k % n
        while add:
            cur = cur.next
            add -= 1
        
        ret = cur.next
        cur.next = None
        return ret

剑指 Offer

8、 从尾到头打印链表(done)

6. 从尾到头打印链表

class Solution:
    def reversePrint(self, head: ListNode) -> List[int]:
        stack = []
        while head:
            stack.append(head.val)
            head = head.next
        return stack[::-1]

9、 合并两个排序的链表(done)

25 合并两个排序的链表

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        dummpy = ListNode(None)
        cur = dummpy
        
        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
        cur.next = l1 if l1 else l2
        return dummpy.next

10、两个链表的第一个公共结点(双指针done)

52 两个链表的第一个公共结点

  • 只有当链表headA 和 headB 都不为空时,两个链表才可能相交。因此首先判断链表headA 和 headB是否为空,如果其中至少有一个链表为空,则两个链表一定不相交,返回 null。
  • 当链表headA 和 headB 都不为空时,创建两个指针pA 和pB,初始时分别指向两个链表的头节点headA 和headB,然后将两个指针依次遍历两个链表的每个节点。具体做法如下:
    每步操作需要同时更新指针pA 和pB。
    如果指针pA 不为空,则将指针pA 移到下一个节点;如果指针pB 不为空,则将指针pB 移到下一个节点。
    如果指针pA 为空,则将指针pA 移到链表 headB 的头节点;如果指针pB 为空,则将指针pB 移到链表headA 的头节点。
    当指针pA 和pB 指向同一个节点或者都为空时,返回它们指向的节点或者 null。
class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        if not headA or not headB:
            return None

        node1,node2 = headA,headB

        while node1 !=  node2:
            node1 = node1.next if node1 else headB
            node2 = node2.next if node2 else headA
        return node1

11、链表中倒数最后k个结点(done)

22. 链表中倒数第k个节点

class Solution:
    def FindKthToTail(self , pHead: ListNode, k: int) -> ListNode:
        if not pHead:
            return pHead
        
        slow,fast = pHead,pHead
        for _ in range(k):
            if fast:
                fast = fast.next
            else:
                return None  #k大于链表长度
        
        while fast:
            fast = fast.next
            slow = slow.next 
        return slow

12、删除排序链表中的重复元素 II(done)

82 删除排序链表中的重复元素 II
由于链表的头节点可能会被删除,因此我们需要额外使用一个哑节点(dummy node)指向链表的头节点。
具体地,我们从指针cur 指向链表的哑节点,随后开始对链表进行遍历。如果当前 cur.next 与cur.next.next 对应的元素相同,那么我们就需要将 cur.next 以及所有后面拥有相同元素值的链表节点全部删除。我们记下这个元素值 xx,随后不断将 cur.next 从链表中移除,直到 cur.next 为空节点或者其元素值不等于 x 为止。此时,我们将链表中所有元素值为 x 的节点全部删除。
如果当前 cur.next 与cur.next.next 对应的元素不相同,那么说明链表中只有一个元素值为 cur.next 的节点,那么我们就可以将cur 指向 cur.next。

class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        if not head:
            return head
        
        dummy = ListNode(0, head)

        cur = dummy
        while cur.next and cur.next.next:
            if cur.next.val == cur.next.next.val:
                x = cur.next.val
                while cur.next and cur.next.val == x:
                    cur.next = cur.next.next
            else:
                cur = cur.next

        return dummy.next

13、复杂链表的复制(……不会)

35 复杂链表的复制

14、二叉搜索树与双向链表

二叉搜索树与双向链表

class Solution:
    def treeToDoublyList(self, root: 'Node') -> 'Node':
        if not root:
            return None 
        
        ans = []
        def dfs(root):
            if root:
                dfs(root.left)
                ans.append(root)
                dfs(root.right)
        
        dfs(root)
        if len(ans) == 1:
            return root
        
         # 构造双向链表
        for i in range(len(ans)-1):
            ans[i].right = ans[i+1]
            ans[i+1].left = ans[i]
        return ans[0]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值