leetcode链表题

2020/8/8

160链表相交

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

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        curA=headA
        curB=headB
        #计算长度差
        n=0
        while(curA):
            n+=1
            curA=curA.next
        while(curB):
            n-=1
            curB=curB.next
        if(curA!=curB):
            return None        
        #长链表先走【长度差】
        curA=headA if n>0 else headB
        curB=headB if n>0 else headA
        n=abs(n)
        while(n>0):
            n-=1
            curA=curA.next
        while(curA!=curB):
            curA=curA.next
            curB=curB.next
        return curA
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        cur1=headA
        cur2=headB
        while(cur1 != cur2):
            cur1=cur1.next if cur1 else headB
            cur2=cur2.next if cur2 else headA
        return cur1

206翻转链表

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

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        pre=None
        cur=head
        while(cur):
            temp=ListNode(cur.val)
            temp.next=pre
            pre=temp
            cur=cur.next
        return pre
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        pre=None
        while(head):
            temp=head.next
            head.next=pre
            pre=head
            head=temp
        return pre

21合并两个有序链表

迭代

# 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:
        #选择当前l1 l2中较小的元素
        pre=ListNode(None)
        cur=pre
        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
        pre=pre.next
        return pre

83 删除排序链表中重复值

暴力解法

class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        #遍历 遇到重复 就指向其下一个      
        if(not head):
            return None
        cur=head
        while(cur and cur.next):
            #当前是重复值
            if(cur.val==cur.next.val):
                cur.next=cur.next.next
            #当前不重复
            else:
                cur=cur.next
        return head

2020/8/9

19删除链表倒数第N个节点

哑节点为了两种情况:
①一个节点 ②node_num==n

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        node_nums=0
        cur=head
        while(cur):
            node_nums+=1
            cur=cur.next
        cur=head
        #为了包含这两种情况 可以增加哑节点
        if(node_nums==1):
            return None
        if(node_nums==n):
            return head.next
        #以上
        for i in range(0,node_nums-n-1):
            cur=cur.next
        cur.next=cur.next.next
        return head
        
class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        node_nums=0
        prehead=ListNode(None)
        prehead.next=head
        cur=head
        while(cur):
            node_nums+=1
            cur=cur.next
        cur=prehead
        for i in range(0,node_nums-n):
            cur=cur.next
        cur.next=cur.next.next
        return prehead.next

双指针 一次遍历

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:

        pre=ListNode(0)
        pre.next=head
        cur1=pre
        cur2=pre
        while(cur2.next):
            if(n>0):
                cur2=cur2.next
                n-=1
            else:
                cur2=cur2.next
                cur1=cur1.next
        cur1.next=cur1.next.next
        return pre.next

2020/9/10

24两两交换节点

class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:
        pre=ListNode(-1)
        pre.next=head
        cur=pre
        while(cur.next and cur.next.next):
            #交换cur.next cur.next.next
            p1=cur.next
            p2=p1.next
            p1.next=p2.next
            p2.next=p1
            cur.next=p2
            cur=cur.next.next
        return pre.next

445两数相加II

用栈保存两组数 用a1.pop a2.pop更方便写

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        result=None
        a1,a2=[],[]
        while(l1):
            a1.append(l1.val)
            l1=l1.next
        while(l2):
            a2.append(l2.val)
            l2=l2.next
        t=0 #进位 1或0
        len1,len2=len(a1),len(a2)
        if(len1<len2):
            a1,a2=a2,a1
            len1,len2=len2,len1
        #a1长位 a2短位 或者位数相同
        for i in range(-1,-1-len1,-1):
            singleSum=a1[i]+a2[i]+t if -i<=len2 else a1[i]+t
            temp=ListNode(singleSum%10)
            temp.next=result
            result=temp
            # print(singleSum)
            # print(result)
            if(singleSum>=10):
                t=1
            else:
                t=0

        if(t==1):
            temp=ListNode(1)
            temp.next=result
            result=temp
        return result 

234回文链表

class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        #两个字符串
        a=[]
        while(head):
            a.append(head.val)
            head=head.next
        return a==a[::-1]

递归可以使得空间复杂度o(1) 或者切割成两半 反转一半 判断是否相等

725分割链表

class Solution:
    def splitListToParts(self, root: ListNode, k: int) -> List[ListNode]:
        #每份应当是num/k 前num%k个数应该+1 k>num时后面num-k份 null
        #获取节点数
        num=0
        result=[]
        cur=root
        while(cur):
            num+=1
            cur=cur.next
        #计算份数 平均节点数
        singleNum=int(num/k)
        moreNum=num%k
        #给每一份 按照 节点数 得到结果
        cur=root
        for i in range(0,k):
            iNum=singleNum+1 if i<moreNum else singleNum

            if(iNum==0):
                result.append(None)
            else:
                if(iNum>=2):
                    for j in range(0,iNum-1):
                        cur=cur.next
                temp=cur.next
                cur.next=None
                result.append(root)
                root=temp
                cur=root

        return result
class Solution:
    def splitListToParts(self, root: ListNode, k: int) -> List[ListNode]:
        #每份应当是num/k 前num%k个数应该+1 k>num时后面num-k份 null
        #获取节点数
        num=0
        result=[]
        cur=root
        while(cur):
            num+=1
            cur=cur.next
        #计算份数 平均节点数
        singleNum=int(num/k)
        moreNum=num%k
        #给每一份 按照 节点数 得到结果
        cur=root
        for i in range(0,k):
            iNum=singleNum+1 if i<moreNum else singleNum

            if(iNum==0):
                result.append(None)
            else:
                for j in range(0,iNum-1):
                    if(cur):
                        cur=cur.next
                temp=cur.next
                cur.next=None
                result.append(root)
                root=temp
                cur=root

        return result

328链表元素按奇偶聚集

遍历 是奇数点 连到h1 是偶数点 连到h2
h1的末尾连h2开头(cur1连cur2.next)
五个指针

class Solution:
    def oddEvenList(self, head: ListNode) -> ListNode:
        cur=head
        h1,h2=ListNode(-1),ListNode(-1)
        cur1,cur2=h1,h2
        flag=True#奇数
        while(cur):
            temp=cur.next
            cur.next=None
            if(flag):
                cur1.next=cur
                cur1=cur1.next
            else:
                cur2.next=cur
                cur2=cur2.next
            flag=not flag
            cur=temp

        cur1.next=h2.next
        return h1.next

下面是官方 4个指针

class Solution:
    def oddEvenList(self, head: ListNode) -> ListNode:
        while(head==None or head.next==None):
            return head
        cur1=head#奇:头head 尾cur1
        h2=head.next#偶:头h2 尾cur2
        cur2=h2
        while(cur1.next and cur2.next):
            cur1.next=cur2.next
            cur2.next=cur2.next.next
            cur1,cur2=cur1.next,cur2.next
        cur1.next=h2
        return head

2021/5/14

23. 合并K个升序链表

顺序合并很慢

# 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:
        p1=None
        result=None
        for p2 in lists:
            result=self.merge2List(p1,p2)
            p1=result

        return result
        

    def merge2List(self,l1,l2):
        cur=ListNode(-1)
        pre=cur
        while(l1 and l2):
            if(l1.val<=l2.val):
                pre.next=l1
                l1=l1.next
            else:
                pre.next=l2
                l2=l2.next
            pre=pre.next
        
        if(l1):
            pre.next=l1
        if(l2):
            pre.next=l2
        return cur.next

这题关键是分治

# 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:
        return self.part(lists,0,len(lists)-1)

    # 两两合并 返回l r位置合并后的一个链表
    def part(self,lists,l,r):
        # print('part:l{},r{}'.format(l,r))
        if(l==r):
            return lists[l]
        if(l>r):
            return None
        mid=(l+r)//2
        # 传参两个链表 返回排序合并的链表
        return self.merge2List(self.part(lists,l,mid),self.part(lists,mid+1,r))
        

    def merge2List(self,l1,l2):
        cur=ListNode(-1)
        pre=cur
        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 pre.next

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: ListNode, k: int) -> ListNode:
        if((not head) or (k==0) or (head and not head.next)):
            return head

        step=1
        tmp=head
        while(tmp and tmp.next):
            tmp=tmp.next
            step+=1
        k=k%step
        if(k==0):
            return head

        # 找到倒数第k个位置
        # [1,2,3,4,5] k=2,快慢指针找到3
        # 快慢指针找到tmp tmp.next就是第K个
        fast=ListNode(-1)
        slow=ListNode(-1)
        fast.next=head
        slow.next=head
        left=slow

        # 快的先走k步 因为k<len 所以直接走就好了
        for i in range(k):
            fast=fast.next
        
        while(fast and fast.next):
            fast=fast.next
            slow=slow.next

        # fast是最后一个元素(非None)
        # slow在3 fast在5
        # print(slow) # 3-4-5
        # print(fast) # 5

        result=slow.next # slow不可能是最后一个
        resultCur=slow.next
        while(resultCur and resultCur.next):
            resultCur=resultCur.next

        # while(slow and slow.next):
        #     slow=slow.next
        slow.next=None
        resultCur.next=left.next
        
        return result

看了题解 发现先连成环 再断开 会很方便 代码量少很多

# 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: ListNode, k: int) -> ListNode:
        if((not head) or (k==0) or (head and not head.next)):
            return head

        # [1,2,3,4,5] k=2

        step=1
        cur=head
        while(cur.next):
            cur=cur.next
            step+=1
        k=k%step
        # 此时cur在5
        if(k==0):
            return head

        # 成环 找断开位置 找到3 (len-k)即可
        cur.next=head 
        for i in range(step-k):
            cur=cur.next

        result=cur.next
        cur.next=None
        
        return result

2021/5/16

92. 反转链表 II

这题真心不太懂 按照自己的思路还可以

class Solution:
    def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
        if(left==right or not head or not head.next):
            return head

        dummy=ListNode(-1)
        dummy.next=head

        p1=dummy
        # p1走到left前一个位置
        for _ in range(left-1):
            p1=p1.next

        # p2=[left-----right-last]
        p2=p1.next
        p3=p2
        # p3走到right位置
        for _ in range(right-left+1):
            p3=p3.next

        # 现在 p1在left-1;p2是[left---right--last];p3是[last]
        print(p1)
        print(p2)
        print(p3)

        pre=p3 # pre是p2的头 后面就变成p2的尾 后面连p3
        for _ in range(right-left+1):
            nxt=p2.next
            p2.next=pre
            pre=p2
            p2=nxt        


        p1.next=pre
        # p2.next=p3

        return dummy.next

官方题解方法一看不懂 关键是弄明白那个变量怎么修改链表 哪些变量是关联的 变量1变会不会影响变量2

2021/5/18

817. 链表组件

这题完全是题目描述不清晰。。

class Solution:
    def numComponents(self, head: ListNode, nums: List[int]) -> int:
        if(not head):
            return 0
        a=[] # 临时存储序列
        nums=set(nums)
        ret=0

        while(head):
            # 如果连续
            if(head.val in nums):
                a.append(head.val)
                # print(a)
                #idx=nums[idx::].index(head.val)+idx+1 # 更新开始搜索的下一个idx
                #nums[idx-1]=-1 # 使用过的G位置数字置为-1
                #nums.remove(head.val)
            else:
                # 说明断开连续了 重置
                if(len(a)>0):
                    a=[] 
                    ret+=1

            head=head.next

        ret=ret+1 if len(a)>0 else ret
        return ret

143. 重排链表

直接用数组存储节点值

class Solution:
    def reorderList(self, head: ListNode) -> None:
        """
        Do not return anything, modify head in-place instead.
        """
        if(not head or not head.next):
            return
        a=[]
        cur=head
        while(cur):
            a.append(cur.val)
            cur=cur.next
        # [1,2,3,4,5]
        left=0
        right=len(a)-1
        cur=head
        while(left<=right):
            if(left==right):
                cur.next=ListNode(a[left])
            else:
                if(left>0):
                    cur.next=ListNode(a[left])
                    cur=cur.next
                cur.next=ListNode(a[right])
                cur=cur.next
            left+=1
            right-=1

为了节约空间,可以:

  • 找中点
  • 中点.next做右边;翻转右边
  • 左右间隔相差
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reorderList(self, head: ListNode) -> None:
        """
        Do not return anything, modify head in-place instead.
        """
        if(not head or not head.next):
            return
        # 找Mid作为right
        right=head
        fast=head
        while(fast and fast.next):
            fast=fast.next.next
            right=right.next
        # 断开左右
        l2=right.next
        right.next=None
        # 翻转右边
        l2_reverse=None
        while(l2):
            nxt=l2.next
            l2.next=l2_reverse
            l2_reverse=l2
            l2=nxt
        # print(head)
        # print(l2_reverse)
        # 合并左右
        cur=head # head一定大于等于l2_reverse
        while(cur and l2_reverse):
            nxt=l2_reverse.next
            # 从l2中插入到l1中
            l2_reverse.next=cur.next
            cur.next=l2_reverse
            l2_reverse=nxt
            cur=cur.next.next

82. 删除排序链表中的重复元素 II

这题想明白了 就是写的很别扭

  • 用dummy
  • 用node.next判断值
class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        if(not head or not head.next):
            return head
        # 快慢指针
        dummy=ListNode(-1)
        dummy.next=head
        slow=dummy
        fast=dummy.next
        flag=False
        while(fast and fast.next):
            # 当fast相等于slow的下一个时
            if(fast.next.val==slow.next.val):
                flag=True
                fast=fast.next
            else:
                # 不等的时候 falg=True说明fast的pre是相等的要删除
                if(flag):
                    slow.next=fast.next
                    fast=fast.next
                    flag=False
                else:
                    slow=slow.next
                    fast=fast.next
        # 排除[2,1,1]情况 因为fast到了最后1的时候 fast.next=None 跳出循环
        if(flag):
            slow.next=fast.next        

        return dummy.next

还是题解简单

class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        if(not head or not head.next):
            return head
        # 快慢指针
        dummy=ListNode(-1)
        dummy.next=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

2021/9/24

430. 扁平化多级双向链表

这题的核心是怎么更新cur的last

  • 当cur.child时,last=cur.child.last
  • 当cur.next时,lst=cur.next

刚开始一直不理解这个last,刚开始是写的注释掉的2写法,其实也可以但是会慢一点,主要就是搞清楚当node是第一个child时,其nxt中出现了child,那么node的tail怎么计算:

  • 首先,node_nxt中出现一个child时,cur_node_tail = dfs(node_child)
  • 核心在这,因为要遍历node这一链路,所以会继续更新 cur_node_tail;当node_child遍历完回来,node还有nxt时,还会往下遍历如果nxt没有child,tail又会更新为nxt;所以就完成了tail的更新
class Solution:
    def flatten(self, head: 'Node') -> 'Node':
        if(not head):
            return head

        self.dfs(head)
        return head

    # head是child时 返回这条链路最后一个node
    def dfs(self,head):
        tail=head
        cur=tail

        while(cur):
            nxt=cur.next
            # cur有child时
            if(cur.child):
                # 1 更新head的tail
                tail=self.dfs(cur.child)
                print(f'cur:{cur.child.val},tail:{tail.val}')
                # 更新child连接
                cur.next=cur.child
                cur.next.prev=cur
                cur.child=None
                # 更新tail.next
                if(nxt):
                    tail.next=nxt
                    nxt.prev=tail
            else:
                tail=cur
            # # 2 当前head是child节点
            # # 2 所以当前head的tail 如果有child tail=dfs(child);紧接着如果nxt tail=nxt
            # if(nxt):
            #     tail=nxt

            cur=nxt

        return tail
class Solution:
    def flatten(self, head: 'Node') -> 'Node':
        if(not head):
            return head

        self.dfs(head)
        return head

                
    # 将child这一链路修改 返回这一路的last
    def dfs(self,node):
        cur=node
        tail=node
        while(cur):
            nxt=cur.next
            if(cur.child):
                child_t=self.dfs(cur.child)
                # 第一步 cur-next
                cur.next=cur.child
                cur.child.prev=cur
                cur.child=None   
                # 第二步 last-nxt
                if(nxt):
                    child_t.next=nxt
                    nxt.prev=child_t
                
                # 注意这个tail的更新位置
                tail=child_t
            else:
                tail=cur

            cur=nxt                         

        return tail

114. 二叉树展开为链表

注意tail的位置

class Solution:
    def flatten(self, root: TreeNode) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        if(not root):
            return root
        self.dfs(root)
        return root

    # 当root是left时 返回left链路的最后一个node
    def dfs(self,root):
        cur=root    
        tail=root
        while(cur):
            nxt=cur.right
            if(cur.left):
                # left节点的链路最后一个node
                left_tail=self.dfs(cur.left)
                # print(f'cur{cur.val},left_tail{left_tail.val},right{nxt.val}')
                left_tail.right=nxt
                cur.right=cur.left
                cur.left=None
                tail=left_tail

            # right存在时
            cur=nxt
            if(nxt):
                tail=nxt


        return tail
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值