Leetcode 2021-11-05

41. First Missing Positive (Hard)

Given an unsorted integer array nums, return the smallest missing positive integer.
You must implement an algorithm that runs in O(n) time and uses constant extra space.

class Solution:
    def firstMissingPositive(self, nums: List[int]) -> int:
        
        # full [1,2,3...len]
        # missing due to -1 , gap ..
        # e.g [3,4,-1,1]
        #     [-3,4,-5,-1]
        #      
        
        length = len(nums)
        
        for i,n in enumerate(nums):
            if n<=0:
                nums[i]=length+1
                #length+1  means mums[i] invalid
                
        for i,n in enumerate(nums):
            real_n = abs(n)
            pos_n = real_n-1
            if pos_n<=length-1:
                nums[pos_n] = -abs(nums[pos_n])
        
        for i,n in enumerate(nums):
            if n>0:
                return i+1
        
        return length+1

用 -abs(val)符号来判断是否已经扫过,注意0和负数的处理。

42. Trapping Rain Water (Hard)

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.
Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6

class Solution:
    def trap(self, height: List[int]) -> int:
        
        # 当入栈时候左边界确定
        # 当入的元素比栈顶大出栈,出栈右边界确定,计算,入栈当前值
        # 边界情况, 第一个元素入栈左边界为空
        # 
        stack = []
        res = 0
        for i,h in enumerate(height):
            while stack and h>height[stack[-1]]:
                #calculate
                cur = stack.pop()
                if stack:
                    left= stack[-1]  
                    right = i
                  
                    width = right-left-1  
                     
                    height_ = min(height[left],height[right])-height[cur]  
                    val = width*height_
                    res+=val
            
            stack.append(i)
        
        return res
        

虽然做出来了, 但花了很长时间。。。。。

43. Multiply Strings (Medium)

Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2, also represented as a string.
Note: You must not use any built-in BigInteger library or convert the inputs to integer directly.

        # 1 2 3 j
        # 4 5 6 i
        #-------
        # 7 3 8
     #  6 1 5
    # 4 9 2
    #  5 6 0 8 8
   
## answer
class Solution(object):
    def multiply(self, num1, num2):
        """
        :type num1: str
        :type num2: str
        :rtype: str
        """
        res = [0]*(len(num1)+len(num2))
        for i in range(len(num1)-1,-1,-1):
            carry = 0
            for j in range(len(num2)-1,-1,-1):
                temp = int(num1[i])*int(num2[j]) + carry
                carry = (res[i+j+1] + temp) //10
                res[i+j+1] = (res[i+j+1] + temp) % 10
            res[i] += carry
        return ''.join(list(map(str,res))).lstrip('0') if ''.join(list(map(str,res))).lstrip('0') else "0"

成功做出来,但是得很细心。
答案写的很精简,思路一样
第二次做不会的。。。。醉了

44. Wildcard Matching (Hard)

# 遇到 time limit exceeded 问题
class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        
        # ? any single
        # * any sequence
        
        if not p:
            return not s
        if not s:
            if len(set(p))==1 and p[0]=='*':
                return True
            return False
#       first block  way of writing           
        if p[0] in {s[0],'?'}:
            #match single
            return self.isMatch(s[1:],p[1:])
        elif p[0]=='*':
            #match sequence     match 0 s,      match 1 s,p not change
            return self.isMatch(s,p[1:]) or self.isMatch(s[1:],p)
        elif p[0]!=s[0]:
            return False
        
#         second block way of writting   using var firstmatch     
#         firstmatch=  p[0] in {'?',s[0]}              
#         if p[0]=='*':
#             if len(p)==1:
#                 return True
#             else:
#                 #                 0 s                     1 s
#                 return self.isMatch(s,p[1:]) or  self.isMatch(s[1:],p)
#         else:
#             return firstmatch and self.isMatch(s[1:],p[1:])
    
            
''' time limit exceeded   1) remove dup*  2) using memorization of (s,p) results   '''  
class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        def removedup(p):
            res=[]
            pre=None
            for e in p:
                if pre=='*' and e=='*':
                    continue
                res.append(e)
                pre=e
            return "".join(res)
                
        dic=dict()
        
        def M(s,p):
            if (s,p) in dic: return dic[(s,p)]
            if not p: return not s
            if not s: 
                if p=='*':
                    dic[(s,p)]=True
                    return True
                else:
                    dic[(s,p)]=False
                    return False
            firstmatch= p[0] in {s[0],'?'}
            
            if p[0]=='*':
                res=M(s,p[1:]) or M(s[1:],p)
                dic[(s,p)]=res
                return res
            else:
                res=firstmatch and M(s[1:],p[1:])
                dic[(s,p)]=res
                return res
        
        return M(s,removedup(p))

还有dynamic programming 解法, 比较不熟悉, 暂时放弃。

45. Jump Game II (Medium)

Given an array of non-negative integers nums, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Your goal is to reach the last index in the minimum number of jumps.
You can assume that you can always reach the last index.

class Solution:
    def jump(self, nums: List[int]) -> int:
        # i,
        # i+nums[i] is max can just at this step
        # search prev to i+nums[i], which can just further
        if len(nums)==1: return 0
        
        pos = 0 
        step = 0
        while pos<len(nums)-1:
            step+=1
            move_to = None
            max_can_reach = -float('inf')
            for i in range(pos,pos+nums[pos]+1):
                if i>=len(nums)-1: return step
                reach = i+nums[i]
                if reach> max_can_reach:
                    max_can_reach = reach
                    move_to = i
            pos = move_to
               
        return step

#anser way of writing
class Solution(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n = len(nums)
        if n < 2:
            return 0 
        
        # max position one could reach 
        # starting from index <= i 
        right = nums[0]
        # max number of steps one could do
        # inside this jump
        cur = nums[0]
        
        jumps = 1
        for i in range(1, n):
            # if to reach this point 
            # one needs one more jump
            if cur < i:
                jumps += 1
                cur = right
            right = max(right, nums[i] + i)
                
        return jumps


class Solution:
    def jump(self, nums: List[int]) -> int:
        if len(nums)==1: return 0

        cur = 0
        maxright = nums[0]
        jump = 0
        for i in range(1,len(nums)):
            if cur<i:
                jump+=1
                cur=maxright
            maxright = max(maxright, nums[i]+i)
            
        
        return jump

费了点力气写出来了,思路, 如果pos不到最后一位,需要移动,step+=1, 确定移动到哪里,移动到可以使下次移动更远的index位置。 从【pos,pos+nums【pos】】中选出能达到最远的index,那个index就当前步会移动的地方。 注意再扫能移动到最远的地方时候, 如果【pos,pos+nums【pos】】已经大于等于了最后的位置,再当前步就可提前结束了,return step就行。
答案直接扫从1到LEN(nums)的位置,right能到位置为 right = max(right, nums[i] + i), 如果在right更新前, cur小于i, 则需要jump,jump后 cur=right。

46. Permutations (Medium)

Blue because can not write the switch postion solution.
Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order.

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        res =[]
        def bt(tmp):
            if len(tmp)==len(nums):
                res.append(tmp[:])
            for n in nums:
                if n not in tmp:   
                    tmp.append(n)
                    bt(tmp)
                    tmp.pop()
        
        bt([])
        return res

# aswer way of writing 用了swap 比较省检查是否在tmp那步。
class Solution:
    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        def backtrack(first = 0):
            # if all integers are used up
            if first == n:  
                output.append(nums[:])
            for i in range(first, n):
                # place i-th integer first 
                # in the current permutation
                nums[first], nums[i] = nums[i], nums[first]
                # use next integers to complete the permutations
                backtrack(first + 1)
                # backtrack
                nums[first], nums[i] = nums[i], nums[first]
        
        n = len(nums)
        output = []
        backtrack()
        return output

backtracking 应用, swap方法很巧妙。

47. Permutations II (Medium)

Given a collection of numbers, nums, that might contain duplicates, return all possible unique permutations in any order.

class Solution(object):
    def permuteUnique(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        
        visited = [False]*len(nums)
        
        res = []
        def bt(temp,visited):
            if len(temp)==len(nums):
                res.append(temp[:])
            
            else:
                for i in range(len(nums)):
                    
                    if visited[i] or (i>0 and nums[i]==nums[i-1] and not visited[i-1]) : continue 
         
                    visited[i]=True
                    temp.append(nums[i])
                    bt(temp,visited[:])
                    temp.pop()
                    visited[i]=False
                     
        
        nums.sort()
        bt([],visited)
        return res

试着用 Permutations swap方法+if条件去重,失败, 没想到得开一个visited来记录是否访问过。 如果访问过或者提前访问(i-1 没访问但开始访问i)则continue。

#无奈做法用set去重
class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:

        nums.sort()
        n=len(nums)
        res = []
        def bt(tmp,first):
            if first==n:
                res.append(tmp[:])
                return
            
            for j in range(first,n):
                if j-1>=first and nums[j] == nums[j-1]: 
                    continue
                tmp[j],tmp[first] = tmp[first],tmp[j]
                bt(tmp,first+1)
                tmp[j],tmp[first] = tmp[first],tmp[j]
        
        bt(nums,0)
        return list(set( [tuple(e) for e in res]))

48. Rotate Image (Medium)

class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        
        n = len(matrix)
        
        for level in range(n//2):
            len_level = n-level*2
            
            for i in range(len_level-1):
                lefttop = matrix[level][level+i]
                righttop =matrix[level+i][level+len_level-1]
                rightbot = matrix[n-level-1][level+len_level-i-1]
                leftbot = matrix[level+len_level-i-1][level]
                
                print(lefttop,righttop,rightbot,leftbot)
                
                matrix[level+i][level+len_level-1] = lefttop
                matrix[n-level-1][level+len_level-i-1] = righttop
                matrix[level+len_level-i-1][level] = rightbot
                matrix[level][level+i] = leftbot

49. Group Anagrams (Medium)

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        
        if len(strs)==1: return [strs]
        res = []
        dic = dict()
        for str in strs:
            key = ''.join(sorted([e for e in str]))
            if key not in dic:
                          dic[key] = []
            dic[key].append(str)
        for k,v in dic.items():
                          res.append(v)
        return res

50. Pow(x, n) Medium

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if n==0: return 1.0
        if n<0:
            x=1.0/x
            n=-n
        
        if n%2==1:
            return x*self.myPow(x,n//2)**2
        else:
            return self.myPow(x,n//2)**2