Leetcode 2021-11-25

感恩节假期中断了刷题,沉迷于半小时漫画系列... 补上月25进度。

221. Maximal Square (Medium)

Given an m x n binary matrix filled with 0's and 1's, find the largest square containing only 1's and return its area.

class Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        rows=len(matrix)
        cols=len(matrix[0])
        maxqlen=0
        for i in range(rows):
            for j in range(cols):
                if matrix[i][j]=='1':
                    sqlen=1
                    flag=True
                    while sqlen+i<rows and sqlen+j< cols and flag:
                        for k in range(j,sqlen+j+1):
                            if matrix[i+sqlen][k]=='0':
                                flag=False
                                break
                        for k in range(i,i+sqlen+1):
                            if matrix[k][j+sqlen]=='0':
                                flag=False
                                break
                        if flag:
                            sqlen+=1
                    
                    if maxqlen<sqlen:
                        maxqlen=sqlen
                        
                        
        return maxqlen**2

class Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        # dp[i][j]  size of box which bottom right in pos[i][j]
        # if matrix[i][j]==1
        #    dp[i][j]=   min(dp[i-1][j],dp[i-1][j-1],dp[i][j-1])+1 
        
        m = len(matrix)
        n = len(matrix[0])
        dp = [[0]*(n+1) for _ in range(m+1)]
        res=0
        for i in range(1,m+1):
            for j in range(1,n+1):
                if matrix[i-1][j-1]=='1':
                    dp[i][j]=min(dp[i-1][j],dp[i-1][j-1],dp[i][j-1])+1
                    res=max(res,dp[i][j])
        return res**2

试着用cumsum去解但失败了, 方法1,暴力解。 每次发现是“1”就以它作为正方形左上角起始点, 检查 row: i,i+sqlen col: j, j+sqlen 是否有‘0’.
方法2:dp: dp【i】【j】保存右下角位置在i,j的盒子大小。

222. Count Complete Tree Nodes (Medium)

# 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 countNodes(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0
        if not root.left and not root.right:
            return 1
        if not root.right:
            return 1+ self.countNodes(root.left)
        else:
            return  self.countNodes(root.left)+self.countNodes(root.right)+1


# 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 countNodes(self, root: Optional[TreeNode]) -> int:
        
        def depth(node):
            d=0
            while node.left:
                node=node.left
                d+=1
            return d
        
        def exists(idx,d,node):
            left=0
            right=2**d-1
            for _ in range(d):
                pivot = (left+right)//2
                if idx<=pivot:
                    node=node.left
                    right=pivot
                else:
                    node=node.right
                    left=pivot +1
            return node is not None
        
        if not root: return 0
        d = depth(root)
        if d==0: return 1
        
        l=1
        r=2**d-1
        while l<=r:
            mid = (l+r)//2
            if exists(mid,d,root):
                l=mid+1
            else:
                r=mid-1
        
        return (2**d-1) +l 
        

给出了个O(n)解法,但题目要求小于O(n)...
思路: 完全二叉树,第0层20个node,第一层,21个node,第n层2^n个node,所以假设这个树深度为d=n, 不包含最后一层20+21+..+2(n-1)=2n - 1 的所有node总和为2^d-1 ,问题转化成求最后一层有多少node。 范围在1~2^n. 因为d=n所以肯定有第一个node。 可以用binary search 求。

223. Rectangle Area (Medium)

class Solution:
    def computeArea(self, ax1: int, ay1: int, ax2: int, ay2: int, bx1: int, by1: int, bx2: int, by2: int) -> int:
        
        # intersect of 1d line
        
        def intersect(a1,a2,b1,b2):
            if a1>b1:
                a1,a2,b1,b2=b1,b2,a1,a2
            
            #print(a1,a2,b1,b2)
            #case 1  --
            #            --
            if a2<b1:
                return 0
            
            #case 2   a1---a2
            #            b1---b2
            if b1<=a2 and a2<=b2:
                return a2-b1
            # case 3  a1------a2
            #            b1-b2
            if b1<a2 and b2<a2:
                return b2-b1
            
            return 'ERROR'
        
        width = intersect(ax1,ax2,bx1,bx2)
        height = intersect(by1,by2,ay1,ay2)
        print(width,height)
        return (ay2-ay1)*(ax2-ax1)+ (by2-by1)*(bx2-bx1)    -width*height

224. Basic Calculator (Hard)

#通解
class Solution:
    def calculate(self, s: str) -> int:
        
        # 转换为 后缀表达式
        # 运算符优先级
        prec = {}
        prec["*"] = 3
        prec["/"] = 3
        prec["+"] = 2
        prec["-"] = 2
        prec["("] = 1

        res = []
        stack = []
        i = 0
        while i < len(s):
            # 数字 直接 接到后缀表达式上
            if s[i] == " ":
                i += 1
                
            elif s[i].isdigit():
                temp = ""
                while i < len(s) and s[i].isdigit():
                    temp += s[i]
                    i += 1
                res.append(temp)

            # 左括号直接入栈
            elif s[i] == "(":
                stack.append(s[i])
                i += 1

            # 右括号,开始弹栈,直达遇到左括号 左括号出栈 但不输出
            elif s[i] == ")":
                while stack and stack[-1] != "(":
                    res.append(stack.pop())
                stack.pop() # 左括号出战, 但是不输出
                i += 1

            # 遇到运算符
            elif s[i] in ["+", "-", "*", "/"]:
                #  对 "-2 + 2" 或者 "1-(-2)" 进行特殊处理
                if s[i] == "-" and (i == 0 or s[i-1] == "(" ):
                    res.append('0')
                # 只要栈顶符号不低于当前符号,就一直输出。最后把当前符号入栈
                while stack and prec[s[i]]<=prec[stack[-1]]:
                    res.append(stack.pop())
                stack.append(s[i])
                i += 1
        
        # 最后把栈里面的元素均 放到后缀表达式后面
        while stack:
            res.append(stack.pop())


        # 计算后缀表达式
        stack = []
        
        for char in res:
            if char.isdigit():
                stack.append(int(char))
            else:
                x = stack.pop()
                y = stack.pop() 
                if char == "+":
                    stack.append(x + y)
                elif char == "-":
                    stack.append(y-x)
                elif char == "*":
                    stack.append(y*x)
                elif char == "/":
                    stack.append(x/y)

        return stack.pop()

" 2-1 + 2 " 直接用stack解出现-1时候符号和1是合体的,所以换思路把表达式变成前缀/后坠表达。 又遇到后缀表达如何去括号问题。
1 + (( 2 + 3)* 4 ) – 5 方法: 当读到数时,立即输出, 若读到操作符,判断符号与栈顶符号的优先级,若该符号优先级高于栈顶元素,则将该操作符入栈,否则就依次把栈中运算符弹出并加到后缀表达式尾端,但又遇到 "1-(-2)" 无法pass。 同理 "- (3 - (- (4 + 5) ) )" 无法pass。 负号不作为减法,作为符号。 需要特殊处理: 方法:

if e == "-" and (i == 0 or s[i-1] == "(" ):
    s_res.append(0)

答案很简单,问题根源在-号不能互相换 比如(A-B)+C != A-(B+C) , 所以把-看作数字的符号。

class Solution:
    def calculate(self, s: str) -> int:

        stack = []
        operand = 0
        res = 0 # For the on-going result
        sign = 1 # 1 means positive, -1 means negative  

        for ch in s:
            if ch.isdigit():
                # Forming operand, since it could be more than one digit
                operand = (operand * 10) + int(ch)

            elif ch == '+':
                # Evaluate the expression to the left,
                # with result, sign, operand
                res += sign * operand

                # Save the recently encountered '+' sign
                sign = 1
                # Reset operand
                operand = 0

            elif ch == '-':

                res += sign * operand
                sign = -1
                operand = 0

            elif ch == '(':

                # Push the result and sign on to the stack, for later
                # We push the result first, then sign
                stack.append(res)
                stack.append(sign)

                # Reset operand and result, as if new evaluation begins for the new sub-expression
                sign = 1
                res = 0

            elif ch == ')':

                # Evaluate the expression to the left
                # with result, sign and operand
                res += sign * operand

                # ')' marks end of expression within a set of parenthesis
                # Its result is multiplied with sign on top of stack
                # as stack.pop() is the sign before the parenthesis
                res *= stack.pop() # stack pop 1, sign

                # Then add to the next operand on the top.
                # as stack.pop() is the result calculated before this parenthesis
                # (operand on stack) + (sign on stack * (result from parenthesis))
                res += stack.pop() # stack pop 2, operand

                # Reset the operand
                operand = 0

        return res + sign * operand

225. Implement Stack using Queues (Easy)

class MyStack(object):
    def __init__(self):
        self._queue = collections.deque()

    def push(self, x):
        q = self._queue
        q.append(x)
        for _ in range(len(q) - 1):
            q.append(q.popleft())
 
    def pop(self):
        return self._queue.popleft()

    def top(self):
        return self._queue[0]
    
    def empty(self):
        return not len(self._queue)

三种方法

226. Invert Binary Tree (Easy)

# 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 root
        root.left,root.right = root.right,root.left
        root.left = self.invertTree(root.left)
        root.right=self.invertTree(root.right)
        return root

227. Basic Calculator II (Medium)

class Solution:
    def calculate(self, s: str) -> int:
        
        #convert to 后缀表达
        priority = {'+':1,'-':1,'*':2,'/':2,'(':0}
        res = [] #保存后缀表达式
        stack=[] #保存符号
        i=0
        while i<len(s):
            ch=s[i]
            if ch.isdigit():
                tmp=ch
                while i+1<len(s) and s[i+1].isdigit():
                    tmp+=s[i+1]
                    i+=1
                res.append(int(tmp))
            
            elif ch=='(':
                stack.append(ch)
            elif ch==')':
                while stack and stack[-1] != "(":
                    res.append(stack.pop())
                stack.pop() 
            elif ch in  ["+", "-", "*", "/"]:
                 if s[i]=='-' and (i==0 or s[i-1]=='('):
                    res.append(0)
                while stack and priority[ch] <= priority[stack[-1]]:
                    res.append(stack.pop())

                stack.append(ch)
            
            i+=1
                
        while stack:
            res.append(stack.pop())
        
        # 计算后缀表达式
        stack = []
        
        for char in res:
            if char not in  ["+", "-", "*", "/"]:
                #char is number
                stack.append(char)
            else:
                x = stack.pop()
                y = stack.pop() 
                if char == "+":
                    stack.append(x + y)
                elif char == "-":
                    stack.append(y-x)
                elif char == "*":
                    stack.append(y*x)
                elif char == "/":
                    stack.append(y//x)

        return stack.pop()


#ANSWER
class Solution:
    def calculate(self, s: str) -> int:
        
        if not s: return 0
        s = s + '+'
        stack = []
        val = 0
        op = '+'
        for n in s:
            if n==' ':  continue
            
            if n.isdigit():
                val=val*10+int(n)
            else:
                if op=='+':
                    stack.append(val)
                elif op=='-':
                    stack.append(-val)
                elif op=='*':
                    stack.append(stack.pop()*val)
                elif op=='/':
                    stack.append(int(stack.pop()/val))

                op = n
                val = 0 
            
        print(stack)
        return sum(stack)


直接上通杀法。转成后缀表达然后求结果。
为了能延时evaluate,所以先给op一个default值+, 然后当遇到下一个符号时候,再去eval之前的op结果,遇到+-要push到stack,遇到*/要从stack取值做计算, 要注意因为是遇到符号才会触发计算,所以s = s+‘+’ 来做最后一位的触发计算。

228. Summary Ranges (Easy)

class Solution:
    def summaryRanges(self, nums: List[int]) -> List[str]:
        # [0]
        # [0,1]
        # [0,2]
        # [0-2,4]
        # [0-2,4,5]
        
        res = []
        stack=[]
        for n in nums:
            if not stack:
                stack.append(n)
            elif len(stack)==1:
                if n==stack[-1]+1:
                    stack.append(n)
                else:
                    res.append(str(stack[-1]))
                    stack=[n]
            else:
                if n==stack[-1]+1:
                    stack[-1]=n
                else:
                    res.append(str(stack[0])+'->'+str(stack[1]))
                    stack=[n]
 
        if len(stack)==1:
            res.append(str(stack[0]))
        elif len(stack)==2:
            res.append(str(stack[0])+'->'+str(stack[1]))
        
        return res
#answer way of writting
class Solution:
    def summaryRanges(self, nums: List[int]) -> List[str]:
        res = []
        i=0
        for j in range(len(nums)):
            if j+1<len(nums) and nums[j+1]==nums[j]+1:
                continue
            if i==j:
                res.append(str(nums[i]))
            else:
                res.append(str(nums[i])+'->'+str(nums[j]))
            i=j+1
        return res

答案更简单

229. Majority Element II (Medium)

class Solution:
    def majorityElement(self, nums: List[int]) -> List[int]:
        
        maj1=nums[0]
        maj2=nums[0]
        c1=0
        c2=0

        for n in nums:
            if n==maj1:
                c1+=1
            elif n==maj2:
                c2+=1
            elif c1==0:
                c1=1
                maj1=n
            elif c2==0:
                c2=1
                maj2=n
            else:
                c1-=1
                c2-=1
        #recalce make sure        
        c1=c2=0
        for n in nums:
            if n==maj1:c1+=1
            if n==maj2:c2+=1
        res=[]
        if c1>len(nums)//3:
            res.append(maj1)
        if c2>len(nums)//3 and maj1!=maj2:
            res.append(maj2)
        return res


经典算法,在做majorelement 1时候写过,需要记住。

230. Kth Smallest Element in a BST (Medium)

# 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:
        ind=0
        stack=[]
        while root or stack:
            while root:
                stack.append(root)
                root=root.left
            
            node=stack.pop()
            ind+=1
            if ind==k:
                return node.val
            
            root=node.right