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 过了提交测试的,但是思路并不一定是最佳思路,仅为自己过程记录
  • 如果你发现了某个代码有问题,可以在背地里偷偷笑我,因为我的博客里没有添加评论功能