Python_Hot100

学习 Python 顺遍刷 Hot100 的过程记录

Python Hot100 学习笔记

这篇是我刷 Hot100 的总览页。
我会把每道题单独存到此篇笔记目录下的 .py 文件,并由页面自动读取展示。

目录

哈希
双指针
滑动窗口
子串
普通数组
矩阵
链表
二叉树
图论
回溯
二分查找
栈
堆
贪心算法
动态规划
多维动态规划
技巧

代码

1. 两数之和

class Solution(object):
    def twoSum(self, nums, target):
        l = len(nums)
        hashtable = dict()
        
        for i in range(l):
            if target - nums[i] in hashtable:
                return [hashtable[target - nums[i]], i]

            hashtable[nums[i]] = i

        return []

49. 字母异位词分组

class Solution(object):
    def groupAnagrams(self, strs):
        mp = dict()

        for s in strs:
            key = "".join(sorted(s))
            if key not in mp:
                mp[key] = []
            mp[key].append(s)

        return list(mp.values())

128. 最长连续序列

class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        hashset = set(nums)
        maxlen = 0

        for num in nums :
            if num-1 not in hashset :
                nowlen = 1
                nex = num+1

                while nex in hashset :
                    nex += 1
                    nowlen += 1

                maxlen = max(nowlen,maxlen)
                
        return maxlen

283. 移动零

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        length = len(nums)
        putindex = 0

        # 将非零元素依次放在前面
        for i in range(length):
            while putindex < length and nums[putindex] == 0:
                putindex += 1

            if putindex == length:
                nums[i] = 0
            else:
                nums[i] = nums[putindex]
                putindex += 1


11. 盛最多水的容器

class Solution:
    def maxArea(self, height: List[int]) -> int:
        left = 0
        right = len(height)-1
        maxArea = 0

        while left < right :
            area = (right-left) * min(height[right] , height[left])
            maxArea = max( maxArea , area)

            if height[right] < height[left] :
                right -= 1
            else :
                left += 1

        return maxArea

15. 三数之和

class Solution:
    def threeSum(self, nums: list[int]) -> list[list[int]]:
        # 双重for + set找need 有重复
        # 应该使用排序 + 双指针
        l = len(nums)
        nums.sort()
        ans = []
        for i in range(l) :
            if i > 0 and nums[i] == nums[i-1] :
                continue
            need = -nums[i]
            left = i+1
            right = l-1
            while left < right :
                if nums[left]+nums[right] > need : 
                    right -= 1
                elif nums[left]+nums[right] < need :
                    left += 1
                else :
                    ans.append([-need , nums[left] , nums[right]])
                    while left < right and nums[left] == nums[left + 1]: left += 1
                    while left < right and nums[right] == nums[right - 1]: right -= 1
                    left += 1
                    right -= 1
    
        return ans

42. 接雨水

class Solution:
    def trap(self, height: List[int]) -> int:
        l = len(height)
        pre = 0
        preheight = [0]*l

        for i in range(l) :
            pre = max(height[i],pre)
            preheight[i] = pre

        ans = 0
        nex = 0
        for j in range(l-1 , -1, -1) :
            nex = max(height[j],nex)
            ans += min(nex,preheight[j])-height[j]
        
        return ans

3. 无重复字符的最长子串

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        if not s :
            return 0
        mp = {}
        star , l = 0 , 1
        # map中存在即重复 新的star = key+1
        for i in range(len(s)) :
            c = s[i]
            if c not in mp or mp[c] < star :
                l = max(l , i-star+1)
                mp[c] = i
            else :
                star = mp[c]+1
                mp[c] = i

        return l

438. 找到字符串中所有字母异位词

class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        sl,pl = len(s),len(p)
        if sl < pl :
            return [] 

        sMap,pMap = [0]*26 , [0]*26
        ans = []
        for i in range(pl) :
            sMap[ ord(s[i]) - ord('a') ] += 1
            pMap[ ord(p[i]) - ord('a') ] += 1

        if sMap == pMap :
                ans.append(0)

        for i in range(0 , sl-pl) :
            sMap[ ord(s[i])-ord('a') ] -= 1
            sMap[ord(s[i+pl])-ord('a')] +=1

            if sMap == pMap :
                ans.append(i+1)

        return ans

560. 和为 K 的子数组

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        ans , nowsum = 0, 0
        mp = {}
        mp[0] = 1
        for num in nums :
            nowsum += num
            need = nowsum - k
            if need in mp :
                ans += mp[need]
            mp[nowsum] = mp.get(nowsum , 0) +1 
        return ans 

239. 滑动窗口最大值

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        l = len(nums)
        if k > l :
            return []
        left = 0
        heap = []
        ans = []
        for i in range(l) :
            # 存当前的元素
            heapq.heappush(heap , (-nums[i] , i))
            if i >= k-1 :
                # 满了 存 拿 移动left
                while heap[0][1] < left :
                    heapq.heappop(heap)
                ans.append(-heap[0][0])
                left += 1       
        return ans
        #也可以存递减的下标 

76. 最小覆盖子串

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        if len(t) > len(s) :
            return ""

        tmap ={}
        for tchar in t :
            tmap[tchar] = tmap.get(tchar, 0) + 1
        needchar = len(tmap)
        left , star = 0 , -1
        minLength = len(s) + 1
        for right in range(len(s)) :
            addchar = s[right]
            if addchar in tmap:
                tmap[addchar] -= 1
                if tmap[addchar] == 0 : needchar -= 1
            while needchar == 0 :
                # 移除前面的无用字母 
                if s[left] not in tmap :
                    left += 1
                # 以及多余字母
                elif tmap[s[left]] < 0 :
                    tmap[s[left]] += 1
                    left += 1
                # 当前最短有效
                else :
                    if right-left+1 < minLength :
                        minLength = right-left+1
                        star = left
                    # 记录后 删除第一个有效字母
                    tmap[s[left]] += 1
                    needchar += 1
                    left += 1
        if star == -1 : return ""
        return s[star : star+minLength]

53. 最大子数组和

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        maxsum,nowsum = nums[0],0
    
        for right in range(len(nums)) :
            nowsum += nums[right]
            # 更新最大值
            maxsum = max(maxsum,nowsum)
            # 如果当前和小于0 就丢弃之前的和 从下一个开始
            if nowsum < 0:
                nowsum = 0

        return maxsum

56. 合并区间

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        pq = []
        ans = []
        for interval in intervals :
            heapq.heappush(pq,interval)
        while pq :
            interval = heapq.heappop(pq)
            while pq and pq[0][0] <= interval[1] :
                add = heapq.heappop(pq)
                interval[1] = max (interval[1],add[1])
            ans.append(interval)
        return ans

189. 轮转数组

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        nums.reverse()
        l = len(nums)
        k = k % l
        left , right = 0 , k-1
        while left < right :
            temp = nums[left]
            nums[left] = nums[right]
            nums[right] = temp
            left += 1
            right -= 1
        left ,right = k ,l-1
        while left < right :
            temp = nums[left]
            nums[left] = nums[right]
            nums[right] = temp
            left += 1
            right -= 1
        

238. 除了自身以外数组的乘积

class Solution:
    def productExceptSelf(self, nums: List[int]) -> List[int]:
        l = len(nums)
        pre, nex = [1]*l, [1]*l
        for i in range(l-1) :
            pre[i+1] = pre[i]*nums[i]
            nex[l-2-i] = nex[l-1-i] * nums[l-1-i]
        ans = [1]*l
        for i in range(l) :
            ans[i] = pre[i] * nex[i]
        return ans

41. 缺失的第一个正数

class Solution:
    def firstMissingPositive(self, nums: List[int]) -> int:
        l = len(nums)
        for index in range(l):
            while 1 <= nums[index] <= l  and nums[index] != index+1 and nums[nums[index]-1] != nums[index]:
                temp = nums[index]
                nums[index] = nums[temp-1]
                nums[temp-1] = temp 

        for index in range(l):
            if index+1 != nums[index] :
                return index+1
        return l+1

73. 矩阵置零

class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        hst, lst=set(), set()
        for i in range(len(matrix)) :
            for j in range(len(matrix[i])) :
                if matrix[i][j] == 0 :
                    hst.add(i)
                    lst.add(j)
        
        for i in range(len(matrix)) :
            for j in range(len(matrix[i])) :
                if matrix[i][j] != 0 and ( i in hst or j in lst ) :
                    matrix[i][j] = 0

54. 螺旋矩阵

class Solution:       
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        end, right= len(matrix)-1, len(matrix[0])-1
        top, left = 0, 0
        ans=[]
        while top<=end and left<=right :
            ans+=order(matrix,top,left,end,right)
            top +=1
            left +=1
            end -=1
            right -=1
        return ans
def order(matrix,top,left,end,right)-> List[int]:
    ans = []
    for i in range(left,right+1):
        ans.append(matrix[top][i])
    for i in range(top+1,end+1):
        ans.append(matrix[i][right])
    if end-top>0 :
        for i in range(right-1,left-1,-1):
            ans.append(matrix[end][i])
    if  right-left>0 :
        for i in range(end-1,top,-1):
            ans.append(matrix[i][left])
    return ans

48. 旋转图像

class Solution:
    def rotateSide(self,matrix,star,l) :
        if l <= 1 :
            return
        left,right,top,end = star,star+l-1,star,star+l-1
        for i in range(l-1):
            # 1. 存下左上角
            temp = matrix[top][left + i]
            # 2. 左上角 = 左下角
            matrix[top][left + i] = matrix[end - i][left]
            # 3. 左下角 = 右下角
            matrix[end - i][left] = matrix[end][right - i]
            # 4. 右下角 = 右上角
            matrix[end][right - i] = matrix[top + i][right]
            # 5. 右上角 = 暂存的左上角 (temp)
            matrix[top + i][right] = temp

    def rotate(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        l = len(matrix)
        i = 0
        while l > 0 : 
            # 类内定义的方法 类内调用必需使用self.
            self.rotateSide(matrix,i,l)
            l -= 2
            i += 1

240. 搜索二维矩阵 II

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        m, n = len(matrix), len(matrix[0])
        # 右上搜 <t 说明在下面i++ >t 说明在左边 j--
        i, j = 0,n-1
        while i<m and j>=0 :
            if matrix[i][j] == target :
                return True
            elif matrix[i][j] > target :
                j -= 1
            else :
                i += 1

        return False
    

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) -> Optional[ListNode]:
        linkset = set()
        A = headA
        while A :
            linkset.add(A)
            A = A.next
        B = headB
        while B :
            if B in linkset : 
                return B
            B = B.next 

        return None
         

206. 反转链表

# 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: Optional[ListNode]) -> Optional[ListNode]:
        if not head or not head.next :
            return head
            
        prehead = ListNode(0, head)
        now = head.next
        head.next = None
        while now :
            nex = now.next
            now.next = prehead.next
            prehead.next = now
            now = nex
        return prehead.next

234. 回文链表

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def isPalindrome(self, head: Optional[ListNode]) -> bool:
        if not head or not head.next :
            return True
        
        linkedStr = ""
        while head :
            linkedStr += str(head.val)
            head = head.next
        if linkedStr == linkedStr[::-1] :
            return True
        return Falsea

141. 环形链表

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

class Solution:
    def hasCycle(self, head: Optional[ListNode]) -> bool:
        slow,fast = head,head
        while  fast :
            if fast.next and fast.next.next :
                fast = fast.next.next
            else :
                return False
    
            slow=slow.next
            if fast == slow :
                return True
        return False
        

142. 环形链表 II

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

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        fast , slow = head,head
        while fast :
            if fast.next and fast.next.next :
                fast = fast.next.next
            else : return None
            slow = slow.next
            if fast==slow :
                fast = head
                # a+(n+1)b+nc=2(a+b)⟹a=c+(n−1)(b+c)
                while fast != slow :
                    fast = fast.next
                    slow = slow.next
                return fast
        return None

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, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
        prehead = ListNode()
        nownode = prehead
        p,q = list1,list2
        while p and q :
            if q.val < p.val :
                nownode.next = q
                q = q.next
                nownode = nownode.next
            else :
                nownode.next = p
                p = p.next
                nownode = nownode.next
        if p :
            nownode.next = p
        else :
            nownode.next = q
        return prehead.next

2. 两数相加

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        add = 0
        prehead = ListNode()
        now = prehead
        while l1 and l2 :
            val = l1.val+l2.val+add 
            add = val // 10 
            val %= 10
            node = ListNode(val)
            now.next =  node
            now = now.next
            l1 = l1.next
            l2 = l2.next
        if l1 :
            while l1 and add != 0 :
                val = l1.val+add 
                add = val // 10 
                val %= 10
                node = ListNode(val)
                now.next =  node
                now = now.next
                l1 = l1.next
            now.next=l1
        else :
            while l2 and add != 0 :
                val = l2.val+add 
                add = val // 10 
                val %= 10
                node = ListNode(val)
                now.next =  node
                now = now.next
                l2 = l2.next
            now.next=l2
        if add != 0 :
            now.next = ListNode(add)
        return prehead.next

19. 删除链表的倒数第 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]:
        prehead = ListNode(0,head)
        fast , slow = prehead, prehead
        setp = 0
        while fast.next :
            if setp >= n :
                slow = slow.next
            fast = fast.next
            setp += 1
        slow.next = slow.next.next
        return prehead.next

24. 两两交换链表中的节点

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

    def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if not head or not head.next :
            return head

        prehead = ListNode(0,head) 
        a,b = prehead,head
        while a.next and b.next :
            self.swapTwo(a,b)
            a = b
            b = b.next
        return prehead.next
        
        

25. K 个一组翻转链表

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseOnce(self,pre,k):
        end = pre.next
        for i in range(k-1):
            now = end.next
            end.next = now.next
            now.next = pre.next
            pre.next = now


    def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
        if k == 1 or not head : return head
        prehead = ListNode(0,head)
        pre = prehead
        now , num = head , 0

        while pre and now :
            num += 1
            nex = now.next

            if num == k :
                nextpre = pre.next
                self.reverseOnce(pre,k)
                num = 0
                pre = nextpre
                
            now = nex
    
        return prehead.next
        

138. 随机链表的复制

"""
# Definition for a Node.
class Node:
    def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
        self.val = int(x)
        self.next = next
        self.random = random
"""

class Solution:
    def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
        prehead = Node(0)
        nownode = prehead
        oldnode = head
        mp = {}
        while oldnode :
            newnode = Node(oldnode.val)
            mp[oldnode] = newnode
            oldnode = oldnode.next
            nownode.next = newnode
            nownode = nownode.next
        oldnode , nownode = head , prehead.next
        while oldnode :
            if oldnode.random :
                nownode.random = mp[oldnode.random]
            nownode = nownode.next
            oldnode = oldnode.next
        return prehead.next

148. 排序链表

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    # 快拍错误 因为链表每次自动选择第一个点固定位置特殊情况时间复杂度为n2
    # 归并
    def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if not head or not head.next : 
            return head
        # 简化1:快慢指针找中点的标准模板
        fast, slow = head.next, head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next

        mid = slow.next
        slow.next = None
        left = self.sortList(head)
        right = self.sortList(mid)

        return self.merge(left,right)

    def merge(self,slow,fast):
        prehead = ListNode()
        prenow = prehead
        while slow and fast :
            if slow.val < fast.val :
                prenow.next = slow
                slow = slow.next
                prenow = prenow.next
            else :
                prenow.next = fast
                fast = fast.next
                prenow = prenow.next
        if slow :
            prenow.next = slow
        else :
            prenow.next = fast
        return prehead.next

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[Optional[ListNode]]) -> Optional[ListNode]:
        newlist = []
        while len(lists) > 1 :
            for i in range(0, len(lists), 2) :
                if i+1 < len(lists):
                    newlist.append(self.mergeTwo(lists[i],lists[i+1]))
                else :
                    newlist.append(lists[i])
            lists = newlist
            newlist = []
        '''
        可以换成双端队列
        dq = deque(lists)
        while len(dq) > 1 :
            a,b = dq.pop() ,dq.pop()
            dq.appendleft( self.mergeTwo(a,b) )
        '''
        if not lists : return None
        else :  return lists[0]
    def mergeTwo(self,l1,l2) : 
        prehead = ListNode()
        pre = prehead
        while l1 and l2 :
            if l1.val<l2.val :
                pre.next = l1
                l1 = l1.next
                pre = pre.next
            else :
                pre.next = l2
                l2 = l2.next
                pre = pre.next
        
        pre.next = l1 if l1 else l2
        return prehead.next

146. LRU 缓存

class LRUCache:
    def __init__(self, capacity: int):
        self.capacity= capacity
        self.mp = {}
        self.head , self.end= ListNode(), ListNode()
        self.head.next = self.end
        self.end.pre = self.head

    def get(self, key: int) -> int:
        if key in self.mp :
            node = self.mp[key]
            node.remove()
            node.add(self.end)
            return node.val
        else :
            return -1

    def put(self, key: int, value: int) -> None:
        if key in self.mp : # 存在删链表
            self.mp[key].remove()  
        else : # 不存在 添加mp
            self.mp[key] = ListNode(key)
        # 更新
        node = self.mp[key]
        node.val = value
        node.add(self.end)
        # 容量校验
        if len(self.mp) > self.capacity:
            old_node = self.head.next
            old_node.remove()
            del self.mp[old_node.key]
            

class ListNode:
    def __init__(self,key=-1,val=-1, pre=None, nex=None):
        self.key,self.val ,self.pre ,self.next =key, val , pre , nex
    def remove(self) :
        self.pre.next=self.next
        self.next.pre=self.pre
    def add(self,end) :
        self.pre=end.pre
        self.next=end
        self.pre.next=self 
        self.next.pre=self 

94. 二叉树的中序遍历

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if not root : return [] 
        ans = []
        if root.left : 
            ans += self.inorderTraversal(root.left)
        ans.append(root.val)
        if root.right :
            ans += self.inorderTraversal(root.right)
        return ans

104. 二叉树的最大深度

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def maxDepth(self, root: Optional[TreeNode]) -> int:
        if not root : return 0
        left = self.maxDepth(root.left)
        right = self.maxDepth(root.right)
        return max(left,right)+1

226. 翻转二叉树

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if not root : return None
        temp = root.left
        root.left = root.right
        root.right = temp
        if root.left : self.invertTree(root.left)
        if root.right : self.invertTree(root.right)
        return root

101. 对称二叉树

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSymmetric(self, root: Optional[TreeNode]) -> bool:
        if not root : return True
        left ,right = root.left , root.right
        larr ,rarr =[],[]
        larr.append(left)
        rarr.append(right)
        while larr and rarr :
            left = larr.pop()
            right = rarr.pop()
            if not left and not right : continue 
            if not left or not right or left.val != right.val  :
                return False
            larr.append(left.left)
            larr.append(left.right)
            rarr.append(right.right)
            rarr.append(right.left)
        return True

543. 二叉树的直径

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
#  备注: 需要重新做
class Solution:
    def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:
        if not root : return 0
        self.ans = 0
        def deep(node) :# 点的深度 leftdeep + rightdeep == 边数
            if not node : return 0
            L = deep(node.left)
            R = deep(node.right)
            self.ans = max(self.ans , L+R)
            return max(L,R)+1
        deep(root)
        return self.ans

102. 二叉树的层序遍历

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        if not root : return []
        ans = []
        nodes = deque()
        nodes.append(root)
        while nodes :
            l,lay = len(nodes),[]
            for _ in range(l) :
                node = nodes.popleft()
                lay.append(node.val)
                if node.left : nodes.append(node.left)
                if node.right : nodes.append(node.right)
            ans.append(lay)
        return ans

108. 将有序数组转换为二叉搜索树

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
        if not nums: return None
        mid = len(nums)//2
    
        left = self.sortedArrayToBST(nums[:mid])
        right = self.sortedArrayToBST(nums[mid+1:])

        root = TreeNode(nums[mid],left,right)
        return root

98. 验证二叉搜索树

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isValidBST(self, root: Optional[TreeNode]) -> bool:
        if not root : return True

        def midarr(root) :
            if not root : return []
            ans = []
            ans += midarr(root.left)
            ans.append(root.val)
            ans += midarr(root.right)
            return ans
        
        arr = midarr(root)
        for i in range(len(arr)):
            if i <1 :continue
            if arr[i-1] >= arr[i] : return False

        return True  

230. 二叉搜索树中第 K 小的元素

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
        
        def midarr(root) :
            if not root : return []
            ans = []
            ans += midarr(root.left)
            ans.append(root.val)
            ans += midarr(root.right)
            return ans
        arr = midarr(root)
        return arr[k-1]

199. 二叉树的右视图

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
        if not root : return []
        dq = deque()
        dq.append(root)
        ans = []
        while dq:
            size = len(dq)
            for _ in range(size):
                node = dq.popleft()
                if node.left : dq.append(node.left)
                if node.right : dq.append(node.right)
                if _ == size-1 : ans.append(node.val)
        return ans 

114. 二叉树展开为链表

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def flatten(self, root: Optional[TreeNode]) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        if not root : return 
        prehead = TreeNode(0,None,root)
        pre = prehead
        stack = []
        stack.append(root)
        while stack :
            node = stack.pop()
            if node.right : stack.append(node.right)
            if node.left : 
                stack.append(node.left)
                node.left = None
            pre.right = node
            pre = pre.right

105. 从前序与中序遍历序列构造二叉树

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
        if not preorder : return None
        node = TreeNode()
        node.val = preorder[0]
        index = inorder.index(preorder[0])
        left = self.buildTree(preorder[1:1+index],inorder[:index])
        right = self.buildTree(preorder[1+index:],inorder[index+1:])
        node.left = left
        node.right = right
        return node

437. 路径总和 III

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int:
        if not root : return 0
        ans = 0
        mp = {} # dict()
        mp[root] = [root.val]
        if root.val == targetSum : ans += 1
        nodes = []
        nodes.append(root)
        while nodes:
            node = nodes.pop()
            if node.left :
                left = node.left
                nodes.append(left)
                mp[left] = [left.val]
                if left.val == targetSum : ans += 1
                for preval in mp[node]:
                    if preval + left.val == targetSum : ans += 1
                    mp[left].append( preval + left.val)
            if node.right :
                right = node.right
                nodes.append(right)
                mp[right] = [right.val]
                if right.val == targetSum : ans += 1
                for preval in mp[node]:
                    if preval + right.val == targetSum : ans += 1
                    mp[right].append( preval + right.val)
            
        return ans

236. 二叉树的最近公共祖先

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
# 需要重做
class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if not root : return None
        if root == p or root == q : return root
        left = self.lowestCommonAncestor(root.left,p,q)
        right = self.lowestCommonAncestor(root.right,p,q)
        if left and right : return root
        elif left : return left
        else : return right

124. 二叉树中的最大路径和

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def maxPathSum(self, root: Optional[TreeNode]) -> int:
        if not root : return 0
        self.maxsum = root.val
        def onePath(node):
            if not node : return 0
            left = onePath(node.left)
            right = onePath(node.right)
            mx= max(left,right,0)+ node.val
            self.maxsum = max(self.maxsum,left+right+node.val,mx)
            return mx
        onePath(root)
        return self.maxsum

200. 岛屿数量

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        def land(grid,i,j,m,n):
            if not 0<=i<m or not 0<=j<n : return
            if grid[i][j] == "0" : return 
            else : 
                grid[i][j] = "0"
                land(grid,i+1,j,m,n)
                land(grid,i-1,j,m,n)
                land(grid,i,j+1,m,n)
                land(grid,i,j-1,m,n)
        num,m,n = 0 ,len(grid),len(grid[0])
        for i in range(m) :
            for j in range(n):
                if grid[i][j] == "1":
                    num += 1
                    land(grid,i,j,m,n)
        return num

994. 腐烂的橘子

class Solution:
    def orangesRotting(self, grid: List[List[int]]) -> int:
        if not grid : return 0

        m,n = len(grid) , len(grid[0])
        unfresh ,freshnum= set() , 0
        for i in range(m) :
            for j in range(n) :
                if grid[i][j]==2 :
                    unfresh.add((i,j))
                if  grid[i][j]==1 :
                    freshnum += 1
        time = 0
        while unfresh : 
            newunfresh = set()
            for uf in unfresh :
                dirct = [(1,0),(-1,0),(0,1), (0,-1)]
                for d in dirct:
                    ni,nj = uf[0]+d[0], uf[1]+d[1]
                    if 0<=ni<m and 0<=nj<n and grid[ni][nj]==1 :
                        freshnum -= 1
                        grid[ni][nj] = 2
                        newunfresh.add((ni,nj))
            if not newunfresh : break
            unfresh = newunfresh
            time += 1
        if freshnum == 0: 
            return time
        return -1

207. 课程表

class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        needCourses ,canLearn,havelearn= [0]*numCourses ,{},0
        for i in range(numCourses) :
            canLearn[i] = set()

        for request in prerequisites :
            needCourses[request[0]] += 1
            canLearn[request[1]].add(request[0])
        learn = []
        for i in range(numCourses) :
            if needCourses[i] == 0 :
                learn.append(i)
        while learn :
            lc = learn.pop()
            havelearn += 1
            for prelearn in canLearn[lc]:
                needCourses[prelearn] -= 1
                if needCourses[prelearn] == 0:
                    learn.append(prelearn)
        if havelearn != numCourses : return False
        return True

208. 实现 Trie (前缀树)

class TreeNode:
    def __init__(self,end=False):
        self.isEnd = end
        self.sun = [None]*26

class Trie:
    def __init__(self):
        self.head = TreeNode()

    def insert(self, word: str) -> None:
        if not str : return
        node = self.head
        for char in word :
            index = ord(char) - ord('a') 
            
            if not node.sun[index] : 
                node.sun[index] = TreeNode() 
            node = node.sun[index]

        node.isEnd = True

    def search(self, word: str) -> bool:
        node = self.head
        for char in word :
            index = ord(char) - ord('a') 
            if node.sun[index] :
                node = node.sun[index]       
            else :
                return False
        
        return node.isEnd

    def startsWith(self, prefix: str) -> bool:
        node = self.head
        for char in prefix :
            index = ord(char) - ord('a') 
            if node.sun[index] :
                node = node.sun[index]
            else :
                return False
                
        return True


# Your Trie object will be instantiated and called as such:
# obj = Trie()
# obj.insert(word)
# param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix)

46. 全排列

class Solution: 
    # 使用deque 不断pop左 append右
    def permute(self, nums: List[int]) -> List[List[int]]:
        if not nums : return []

        nums = deque(nums)
        self.ans = []
        self.addans(nums,[])
        return self.ans

    def addans(self,nums,nowans):
        if not nums : 
            self.ans.append(nowans[:]) # 必需拷贝
            
        for i in range(len(nums)):
            num = nums.popleft()
            nowans.append(num)
            self.addans(nums,nowans)
            nowans.pop()
            nums.append(num)

class Solution: # 直接交换不同位置
    
    def permute(self, nums: List[int]) -> List[List[int]]:
        if not nums : return []

        def traceback(first = 0):
            if first == n : ans.append(nums[:])

            for i in range(first,n):
                nums[i],nums[first] = nums[first],nums[i]
                traceback(first+1)
                nums[i],nums[first] = nums[first],nums[i]
        
        n = len(nums)
        ans = []
        traceback()
        return ans

78. 子集

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        # 递归回溯
        if not nums : return []
        ans ,n= [] ,len(nums)
        def choose(index=0 , addnums=[]):
            if index == n : 
                ans.append(addnums[:])
                return
            addnums.append(nums[index])
            choose(index+1,addnums)
            addnums.pop()
            choose(index+1,addnums)
        choose()
        return ans
    
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        # 位运算 0~2^n-1 每个数的二进制表示一个子集
        ans ,n= [] ,len(nums)
        for i in range(2**n):
            thistime ,index= [],0
            while i != 0:
                if i % 2 == 1 :
                    thistime.append(nums[index])
                index += 1
                i = i>>1
            ans.append(thistime)
        return ans

17. 电话号码的字母组合

class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        if not digits : return []
        mp = [
            [],                  # 0 键
            [],                  # 1 键
            ['a', 'b', 'c'],     # 2 键
            ['d', 'e', 'f'],     # 3 键
            ['g', 'h', 'i'],     # 4 键
            ['j', 'k', 'l'],     # 5 键
            ['m', 'n', 'o'],     # 6 键
            ['p', 'q', 'r', 's'],# 7 键
            ['t', 'u', 'v'],     # 8 键
            ['w', 'x', 'y', 'z'] # 9 键
        ]
        que = deque()
        que.append("")
        for dig in digits :
            index = ord(dig) - ord('0')
            size = len(que)
            for _ in range(size):
                pre = que.popleft()
                for add in mp[index]:
                    que.append(pre+add)
        
        return list(que)

39. 组合总和

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        candidates.sort()
        mp = [None]*(target+1)
        mp[0],mp[target] = [[]],[]
        for num in candidates:
            for i in range(num,target+1):
                if mp[i-num] :
                    if not mp[i] : mp[i] = []
                    for arr in mp[i-num] :
                        narr = arr + [num] 
                        mp[i].append(narr)

        return mp[target]

22. 括号生成

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        
        def addchar(left=n,right=0,nowstr=''):
            if left == 0 and right == 0 :
                ans.append(nowstr)
            elif left == 0 :
                nowstr += ')'*right
                ans.append(nowstr)
            else :
                addchar(left-1,right+1,nowstr+'(')
                if right > 0 :
                    addchar(left,right-1,nowstr+')')
        
        ans = []
        addchar()
        return ans

79. 单词搜索

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        if not board : return False

        m , n =len(board),len(board[0])
        used = [None]*m
        for i in range(m) : used[i]=[False]*n
        
        star=[]
        for i in range(m) :
            for j in range(n):
                if board[i][j]==word[0] :
                    star.append([i,j])

        def findnext(i,j,index):
            if index == len(word) : 
                return True
            dirc = [[1,0],[-1,0],[0,1],[0,-1]]
            ans = False
            for d in dirc:
                ni,nj = i+d[0],j+d[1]
                if 0<=ni<m and 0<=nj<n and not used[ni][nj] and board[ni][nj] == word[index]:
                    used[ni][nj]=True
                    ans = findnext(ni,nj,index+1)
                    if ans : return ans
                    used[ni][nj]=False
            return False


        ans = False
        
        for s in star: 
            i , j = s
            used[i][j]=True
            ans = findnext(i,j,1)
            if ans :    
                return True
            used[i][j]=False

        return False

131. 分割回文串

class Solution:
    def partition(self, s: str) -> List[List[str]]:
        # 自己写的 多次递归 每次找切不切的点 复杂度较高
        def split(star=0,index=0,nowans=[]):
            if star == len(s): 
                ans.append(nowans[:])
            elif index == len(s): 
                return
            else :
                if s[star:index+1] == s[star:index+1][::-1] :# 分
                    nowans.append(s[star:index+1])
                    split(index+1,index+1,nowans) 
                    nowans.pop()
                split(star,index+1,nowans) # 不分

        ans = []
        split()
        return ans

class Solution:
    def partition(self, s: str) -> List[List[str]]:
        ans = []
        #从开始位置 找所有可以切的点进行下面的遍历 切光为止
        # 这个递归函数的目标无比纯粹:从 start 开始,把剩下所有的回文切片找出来
        def backtrack(start: int, nowans: List[str]):
            # 逻辑终点:整根“黄瓜”都被切完了,说明前面每一步的切法都合法!
            if start == len(s):
                ans.append(nowans[:]) # 存入最终结果
                return
            
            # 核心循环:枚举当前这一刀切在哪个位置(i 从 start 一路切到末尾)
            for i in range(start, len(s)):
                sub_str = s[start:i+1] # 这一刀切下来的片段
                
                # 核心校验:只有切下来的片段是回文,这一刀才算切成功了
                if sub_str == sub_str[::-1]:
                    nowans.append(sub_str)       # 1. 把切下来的这段装进盘子里
                    backtrack(i + 1, nowans)     # 2. 递归:让下一个人从 i+1 的位置继续往后切
                    nowans.pop()                 # 3. 回溯:把这段拿出来,腾出地方尝试“切得更长一点”
                    
        backtrack(0, [])
        return ans

51. N 皇后

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        if n == 0 : return []

        # left = i+j right = j-i
        left ,right,col= [False]*(2*n-1),[False]*(2*n-1),[False]*n

        def putQueen(index=0,nowans=[]):
            if index == n :
                ans.append(nowans[:])
                return
            i , put = index,['.']*n
            for j in range(n):
                if not left[i+j] and not right[j-i] and not col[j] :
                    left[i+j] , right[j-i] , col[j] = True,True,True
                    put[j]='Q'
                    putstr = ""
                    for c in put : putstr += c
                    nowans.append(putstr)
                    putQueen(index+1,nowans)
                    nowans.pop()
                    put[j]='.'
                    left[i+j] , right[j-i] , col[j] = False,False,False

        ans=[]
        putQueen()
        return ans

35. 搜索插入位置

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        n = len(nums)
        def half(left=0 ,right=n-1):    
            if target > nums[right] : return right+1
            elif target < nums[left] : return left
            else :
                mid = (right + left)//2
                if nums[mid] == target :
                    return mid
                elif nums[mid] < target :
                    return half(mid+1,right)
                else :
                    return half(left,mid-1)
        return half()

74. 搜索二维矩阵

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        if not matrix : return False
        m ,n = len(matrix) , len(matrix[0])
        i , j = 0 , 0
        while i < m:
            if target == matrix[i][0] : return True
            if target < matrix[i][0] : 
                break
            else : i += 1
        i -= 1
        if i<0 : return False
        while j < n:
            if target == matrix[i][j] : return True
            if target > matrix[i][j] : 
                j += 1
            else : return False
        return False

34. 在排序数组中查找元素的第一个和最后一个位置

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        
        def half(left,right):
            if left>right : return [-1,-1]
            if nums[left]==target and nums[right]==target:
                return (left,right)
            
            mid = (left+right) // 2
            if nums[mid]==target:
                a = half(left,mid-1)
                b = half(mid+1,right)
                c = [mid,mid]
                if a[0] != -1 : c[0]=a[0]
                if b[1]!= -1 : c[1]=b[1]
                return c
            elif nums[mid] < target:
                return half(mid+1,right)
            else : return half(left,mid-1)

        n = len(nums)

        return half(0,n-1)

33. 搜索旋转排序数组

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        
        def half(left,right):
            if left>right: return -1

            mid = (left+right)//2
            if nums[mid]==target:
                return mid
            else :
                if nums[left]<=nums[mid]: # 左有序
                    if nums[left]<=target<=nums[mid] :
                        return half(left,mid-1)
                    else: return half(mid+1,right)
                else: # 右 有序
                    if nums[mid]<=target<=nums[right]:
                        return half(mid+1,right)
                    else: return half(left,mid-1)
        
        return half(0,len(nums)-1)

153. 寻找旋转排序数组中的最小值

class Solution:
    def findMin(self, nums: List[int]) -> int:
        
        def half(left,right):
            if nums[left]<=nums[right] : 
                return nums[left]
            mid = (left+right)//2
            if nums[left]<= nums[mid] : # 左 有序
                return half(mid+1,right)
            else :
                if mid>0 and nums[mid]>nums[mid-1] :# 右增 left > right mid > mid-1
                    return half(left+1,mid-1)
                else : return nums[mid]
        n = len(nums)
        return half(0,n-1)

4. 寻找两个正序数组的中位数

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        # 从 0 开始 index 0,1//2 ==0
        # 从 1 开始 index 1 直接min 2 //2 ==1 
        # 需要重做
        def half(l1,l2,index):
            if l1==n1 :
                return nums2[l2+index-1]
            if l2==n2 :
                return nums1[l1+index-1]
            if index == 1 : 
                return min(nums1[l1],nums2[l2])
            
            hf = index//2
            mid1 , mid2= min(l1+hf-1 , n1-1),min(l2+hf-1 , n2-1)
            if nums1[mid1] > nums2[mid2] :
                return half(l1,mid2+1,index-(mid2+1-l2))
            else : 
                return half(mid1+1,l2,index-(mid1+1-l1))
        
        n1,n2 =len(nums1),len(nums2)
        if (n1+n2)%2 == 1:
            return half(0,0,(n1+n2+1)//2)
        else :
            return ( half(0,0,(n1+n2)//2) + half(0,0,(n1+n2)//2+1) ) /2

20. 有效的括号

class Solution:
    def isValid(self, s: str) -> bool:
        stack =[]
        for char in s :
            if not stack :
                if char in "}])"  : return False
                stack.append(char)
            else:
                if char in "{(["  :
                    stack.append(char)
                elif char==')' and stack[-1]=='(' :
                    stack.pop()
                elif char==']' and stack[-1]=='[' :
                    stack.pop()
                elif char=='}' and stack[-1]=='{' :
                    stack.pop()
                else : stack.append(char)
        if stack : return False
        return True 

155. 最小栈

class MinStack:

    def __init__(self):
        self.nums = []
        self.nummap ,self.minstack = {} ,[]

    def push(self, val: int) -> None:
        self.nums.append(val)
        self.nummap[val] = self.nummap.get(val,0) + 1
        # 有最小值 可能已经被删除了
        # erro {}中查找没有的值 会报错 KeyError! 直接用get
        # while self.minstack and not self.nummap[self.minstack[-1]] : self.minstack.pop()
        while self.minstack and self.nummap.get(self.minstack[-1],0)==0 : self.minstack.pop()
        if not self.minstack :
            self.minstack.append(val)
        else : # 单向的push pop 维护一个以进队顺序的递减最小值
            # 还有最小值
            if val < self.minstack[-1] :
                self.minstack.append(val)

    def pop(self) -> None:
        num = self.nums.pop()
        self.nummap[num] -= 1
        # 归0 即可 删除多一步操作 浪费时间
        # if self.nummap[num] == 0 : del self.nummap[num]

    def top(self) -> int:
        return self.nums[-1]

    def getMin(self) -> int:
        # 有最小值 可能已经被删除了
        while self.minstack and self.nummap.get(self.minstack[-1],0)==0 : self.minstack.pop()
        if not self.minstack : return None
        return self.minstack[-1]


# leetcode 标答 确实没必要存之前比来比去的 维护最小值stack 
#       val > stack[-1] : stack.append(stack[-1])
#       val <= stack[-1] : stack.append(val)
class MinStack:
    def __init__(self):
        self.stack = []
        self.min_stack = [math.inf]

    def push(self, x: int) -> None:
        self.stack.append(x)
        self.min_stack.append(min(x, self.min_stack[-1]))

    def pop(self) -> None:
        self.stack.pop()
        self.min_stack.pop()

    def top(self) -> int:
        return self.stack[-1]

    def getMin(self) -> int:
        return self.min_stack[-1]

394. 字符串解码

class Solution:
    def decodeString(self, s: str) -> str:
        ans = ""
        numstack,charstack = [] ,[]
        i = 0
        while i < len(s) :
            char = s[i]
            if "0"<= char <= "9" :
                num = char
                while i+1 < len(s) and "0"<= s[i+1] <= "9" : 
                    i += 1
                    num += s[i]
                numstack.append(int(num))
            elif char == "]":
                nowstr = ""
                while charstack[-1] != "[" : nowstr = charstack.pop() + nowstr
                charstack.pop()
                num = numstack.pop()
                endstr = nowstr*num
                charstack.append(endstr)
            else :
                charstack.append(char)
            i += 1
        while charstack : ans = charstack.pop() + ans
        return ans

739. 每日温度

class Solution:
    def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
        premax , i= len(temperatures)-1, len(temperatures)-1
        ans = [0]*len(temperatures)
        # 单调栈 每次入栈时pop出小于当前的所有元素并更新answer[i] = new - old
        while i >= 0 :
            if temperatures[i] < temperatures[premax] :
                j = i + 1
                while j < premax and temperatures[i] >= temperatures[j] :
                    j += ans[j] 
                ans[i] = j-i
            else :
                ans[i] = 0
                premax = i
            i -= 1 
        return ans

84. 柱状图中最大的矩形

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        # 计算前后小于它的位置 及可算出以该点为高的最大面积
        n = len(heights)
        premin , nextmin = [-1]*n , [n]*n 
        stack = []
        for i in range(n):
            height = heights[i]
            if not stack :
                stack.append(i)
            else :
                if height >= heights[stack[-1]]:
                    stack.append(i)
                else :
                    while stack and height < heights[stack[-1]] :
                        index = stack.pop()
                        nextmin[index] = i
                    stack.append(i)
        stack.clear()
        for i in range(n-1, -1, -1):
            height = heights[i]
            if not stack :
                stack.append(i)
            else :
                if height >= heights[stack[-1]] :
                    stack.append(i)
                else :
                    while stack and height < heights[stack[-1]] :
                        index = stack.pop()
                        premin[index] = i
                    stack.append(i)
        stack.clear()
        maxarr = 0
        for i in range(n):
            nowarr = heights[i]*(nextmin[i]-premin[i]-1)
            maxarr = max(maxarr,nowarr)
        return maxarr
        # 暴力超时
        # ans , n = 0 , len(heights)
        # for star in range(n) :
        #     nowarr , end , minh =heights[star] , star+1 , heights[star] 
        #     while end < n :
        #         minh = min(minh,heights[end])
        #         nowarr = max(nowarr, minh*(end-star+1))
        #         ans = max(ans,nowarr)
        #         end += 1
        #     ans = max(ans,nowarr)
        # return ans

215. 数组中的第K个最大元素

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        n = len(nums)
        def halffind(star,end,index):
            if star == end :
                return nums[star]
            sig = nums[random.randint(star,end)]
            p , q = star-1, end+1
            while True:
                p += 1
                while nums[p] < sig :
                    p += 1
                q -= 1
                while nums[q] > sig :
                    q -= 1
                if p >= q: break

                nums[p],nums[q] = nums[q],nums[p]
            if q < index:
                return halffind(q+1,end,index)
            else :
                return halffind(star,q,index)
        return halffind(0,n-1,n-k)

347. 前 K 个高频元素

class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        if k == 0 : return []

        nummap = {}
        for num in nums:
            nummap[num] = nummap.get(num,0) + 1
        heap = []
        for nownum in nummap :
            if not heap or len(heap)<k :
                heapq.heappush(heap,(nummap[nownum],nownum))
            else :
                if heap[0][0] < nummap[nownum] :
                    heapq.heappop(heap)
                    heapq.heappush(heap,(nummap[nownum],nownum))

        ans = []
        while heap:
            ans.append(heapq.heappop(heap)[1])
        return ans

295. 数据流的中位数

class MedianFinder:
    # 双队列 左右分别存储较小和较大的数,保持平衡
    def __init__(self):
        self.minpq , self.maxpq = [] , []

    def addNum(self, num: int) -> None:
        qmin , qmax = self.minpq , self.maxpq
        if not qmin or num <= -qmin[0] :
            heapq.heappush(qmin,-num) 
            if len(qmax)+1 < len(qmin):
                heapq.heappush(qmax,-heapq.heappop(qmin))
        else :
            heapq.heappush(qmax,num)
            if len(qmin) < len(qmax):
                heapq.heappush(qmin,-heapq.heappop(qmax))            

    def findMedian(self) -> float:
        if len(self.maxpq) == len(self.minpq) :
            return (self.maxpq[0] - self.minpq[0])/2
        else : 
            return -self.minpq[0]


# Your MedianFinder object will be instantiated and called as such:
# obj = MedianFinder()
# obj.addNum(num)
# param_2 = obj.findMedian()

121. 买卖股票的最佳时机

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        nex = 0 
        n = len(prices)
        ans = 0
        for i in range(n-1,-1,-1):
            ans = max(ans, nex-prices[i])
            nex = max(prices[i],nex)
        return ans

55. 跳跃游戏

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        maxstep ,nowstep= 0,0
        n = len(nums)
        while nowstep<=maxstep:
            maxstep = max(maxstep , nowstep+nums[nowstep])
            nowstep += 1
            if maxstep >= n-1 :
                break 
        if maxstep >= n-1 :
            return True
        return False

45. 跳跃游戏 II

class Solution:
    def jump(self, nums: List[int]) -> int:
        n = len(nums)
        canjump ,steps= deque() , [-1]*n
        canjump.append(0)
        steps[0] = 0
        while canjump :
            now = canjump.popleft() # 0
            jump = nums[now] # 2
            for i in range(1,jump+1): # 1-2
                nex = now+i # 1
                if nex >= n : break
                if steps[nex]==-1 :
                    steps[nex] = steps[now]+1
                    canjump.append(nex)
                elif steps[nex] > steps[now]+1 :
                    steps[nex] = steps[now]+1
        return steps[n-1]
# 贪心算法 : 每次更新最远距离 超过当前步的最远距离就 增加步数    
class Solution:
    def jump(self, nums: List[int]) -> int:
        step ,maxjump ,nowend= 0 , 0 ,0
        n = len(nums)

        for i in range(n-1):
            if maxjump >= i :
                maxjump = max(maxjump, i+nums[i])
                if i == nowend:
                    nowend = maxjump
                    step += 1
        return step 

763. 划分字母区间

class Solution:
    def partitionLabels(self, s: str) -> List[int]:
        charmap = {}
        for i in range(len(s)) :
            char = s[i]
            charmap[char] = i
        
        ans = []
        nowstar ,nowend = 0 , charmap[s[0]]
        for i in range(len(s)) :
            nowend = max(nowend, charmap[s[i]])
            if i == nowend :
                ans.append(i-nowstar+1)
                nowstar = i+1
        return ans

70. 爬楼梯

class Solution:
    def climbStairs(self, n: int) -> int:
        dp = [1]*(n+1)
        for i in range(2,n+1):
            dp[i] = dp[i-1] + dp[i-2]
        return dp[n]

118. 杨辉三角

class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        if numRows < 1 : return []
        ans = [None]*numRows
        for i in range(1,numRows+1):
            row = [1]*i
            for j in range(i):
                if j == 0 or j == i-1:
                    continue
                row[j] = ans[i-2][j-1]+ans[i-2][j]
            ans[i-1] = row
        return ans

198. 打家劫舍

class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [0]*(n+1)
        dp[1] = nums[0]
        for i in range(2,n+1):
            dp[i] = max(dp[i-1],dp[i-2]+nums[i-1])
        return dp[n]

279. 完全平方数

class Solution:
    def numSquares(self, n: int) -> int:
        dp = [n]*(n+1)
        dp[0] = 0
        for i in range(1,int(sqrt(n))+1):
            add = i**2
            for j in range(add,n+1):
                dp[j] = min(dp[j],dp[j-add]+1)
        return dp[n]

322. 零钱兑换

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        dp = [-1]*(amount+1)
        dp[0] = 0
        coins.sort()
        for coin in coins:
            for i in range(coin,amount+1):
                if dp[i-coin] != -1 : # 可以通过 + i获得
                    if dp[i] == -1 :
                        dp[i] = dp[i-coin]+1
                    else : 
                        dp[i] = min(dp[i] , dp[i-coin]+1)
        return dp[amount]
        

139. 单词拆分

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        lens= len(s)
        dp = [False]*(lens+1)
        dp[0] = True
        for end in range(1,len(s)+1):
            for star in range(0,end):
                if dp[star] and s[star:end] in wordDict :
                    dp[end] = True 
                    break
        return dp[lens]

300. 最长递增子序列

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        stack = []
        for num in nums:
            if not stack : 
                stack.append(num)
            else :
                if num > stack[-1]:
                    stack.append(num)
                else : # 小于当前最大
                    # 替换 里面第一个大于它的
                    index = len(stack)-1 
                    while index >= 0 and stack[index] >= num :
                        index -= 1
                    stack[index+1] = num
        return len(stack)

152. 乘积最大子数组

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        maxsun , minsun ,ans= nums[0] , nums[0] , nums[0]
        for num in nums[1:] :
            newnim = min(maxsun*num , minsun*num , num)
            newmax = max(maxsun*num , minsun*num , num)
            ans = max(ans , newmax)
            maxsun , minsun = newmax ,newnim
        return ans

416. 分割等和子集

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        numsum = sum(nums)
        if numsum % 2 != 0 : return False
        target = numsum//2
        canto = set()
        canto.add(0)
        nums.sort()
        for num in nums:
            newcanto = set()
            for i in range(num,target+1):
                if i not in canto and i-num in canto :
                    newcanto.add(i)
            canto.update(newcanto)
            if target in canto :
                return True
        return False

32. 最长有效括号

class Solution:
    def longestValidParentheses(self, s: str) -> int:
        if not s : return 0
        stack = []
        for i in range(len(s)):
            if not stack :
                stack.append(i)
            else :
                if s[i] == ')' and s[stack[-1]] == '('  :
                    stack.pop()
                else :
                    stack.append(i)
        
        end , ans = len(s)-1 ,0
        while stack :
            sun = end - stack[-1]
            end = stack.pop() - 1
            ans = max(ans , sun)
        ans = max(ans , end + 1)
        return ans

62. 不同路径

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        dp = [None]*(m+1)
        for i in range(m+1) : dp[i] = [0]*(n+1)
        for i in range(1,m+1) :
            for j in range(1,n+1):
                if i == 1 and j == 1: 
                    dp[i][j] = 1
                else :
                    dp[i][j] = dp[i-1][j] + dp[i][j-1]
        return dp[m][n]

64. 最小路径和

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        m , n = len(grid),len(grid[0])
        dp = [None]*m
        for i in range(m) : dp[i] = [-1]*n
        for i in range(m):
            for j in range(n):
                if i == 0 and j == 0:
                    dp[i][j] = grid[i][j]
                else :
                    if i>0 and j>0 :
                        dp[i][j] = min(dp[i-1][j],dp[i][j-1]) + grid[i][j]
                    elif i>0 :
                        dp[i][j] =dp[i-1][j] + grid[i][j]
                    else :
                        dp[i][j] =dp[i][j-1] + grid[i][j]
        return dp[m-1][n-1]

5. 最长回文子串

class Solution:
    def longestPalindrome(self, s: str) -> str:
        # dp[i][j] = str[i:j+1] is hui ? 
        n = len(s)
        dp= [None]*n
        for i in range(n):
            dp[i] = [None]*(n)
            for j in range(n):
                if j<=i : dp[i][j] = True
                else : dp[i][j] = False
        maxlength , maxstar = 1 , 0
        for length in range(2,n+1) :
            for star in range(n-length+1) :
                end = star+length-1
                if s[star] == s[end] and dp[star+1][end-1] :
                    dp[star][end] = True
                    if length > maxlength :
                        maxlength = length
                        maxstar = star
        return s[maxstar:maxstar+maxlength]

1143. 最长公共子序列

class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        l1 ,l2 = len(text1), len(text2)
        dp = [None]*(l1+1)
        for i in range(l1+1): dp[i] = [0]*(l2+1)
        for i in range(1,l1+1):
            for j in range(1,l2+1):
                c1 ,c2 = text1[i-1],text2[j-1]
                if c1 == c2 :
                    dp[i][j] = dp[i-1][j-1]+1
                else :
                    dp[i][j] = max(dp[i-1][j],dp[i][j-1])
        return dp[l1][l2]         

72. 编辑距离

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        l1 ,l2 = len(word1), len(word2)
        dp = [None]*(l1+1)
        for i in range(l1+1): 
            dp[i] = [0]*(l2+1)
            dp[i][0] = i
        for j in range(l2+1):
            dp[0][j] = j
        '''  x r o s
        null 0 1 2 3
        h    1 1 2 3
        o    2 2 1
        r    3
        s    4
        e    5
        '''
        for i in range(1,l1+1):
            for j in range(1,l2+1):
                c1 ,c2 = word1[i-1],word2[j-1]
                if c1 == c2 :
                    dp[i][j] = dp[i-1][j-1]
                else :
                    dp[i][j] = min(dp[i][j-1],dp[i-1][j],dp[i-1][j-1])+1
        return dp[l1][l2]         

136. 只出现一次的数字

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        ans = 0
        for num in nums:
            ans ^= num
        return ans

169. 多数元素

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        n = len(nums)
        mp = {}
        for num in nums :
            mp[num] = mp.get(num,0) + 1
            if mp[num] > n/2 :
                return num
        return -1
    # 投票法 每次票数为0时 将当前的数作为候选人
    # 票数为1 继续投票 如果遇到相同的数 
    # 票数加1 否则减1 最后剩下的数就是众数

75. 颜色分类

31. 下一个排列

class Solution:
    def nextPermutation(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        n = len(nums)
        index = n-2
        while index >= 0 and nums[index] >= nums[index+1] :
            index -= 1
        if index == -1 : 
            nums.reverse()
            return
        exchange_index = n - 1
        while nums[exchange_index] <= nums[index]:
            exchange_index -= 1
        nums[index] ,nums[exchange_index] = nums[exchange_index] ,nums[index]
        p , q = index+1 ,n-1
        while p<q :
            nums[p] , nums[q] = nums[q],nums[p]
            p+=1
            q-=1

287. 寻找重复数

class Solution:
    def findDuplicate(self, nums: List[int]) -> int:
        for index in range(len(nums)):
            while index+1 != nums[index] :
                target_index = nums[index]-1
                if nums[target_index] != target_index+1 :
                    nums[index] ,nums[target_index]= nums[target_index] , nums[index]
                else :
                    return  nums[index]

        return -1

记录方式

  • 将道题结果 .py 文件存入hoot100笔记统计目录下,扫描全部py文件自动添加显示
  • 代码都是 leetcode 过了提交测试的,但是思路并不一定是最佳思路,仅为自己过程记录
  • 如果你发现了某个代码有问题,可以在背地里偷偷笑我,因为我的博客里没有添加评论功能