Leetcode 2021-11-10

81. Search in Rotated Sorted Array II (Medium)

There is an integer array nums sorted in non-decreasing order (not necessarily with distinct values).

Before being passed to your function, nums is rotated at an unknown pivot index k (0 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] (0-indexed). For example, [0,1,2,4,4,4,5,6,6,7] might be rotated at pivot index 5 and become [4,5,6,6,7,0,1,2,4,4].

Given the array nums after the rotation and an integer target, return true if target is in nums, or false if it is not in nums.

You must decrease the overall operation steps as much as possible.

class Solution:
    def search(self, nums: List[int], target: int) -> bool:
        #still binary search
        l=0
        r=len(nums)-1
        
        while l<=r:
            m=(l+r)//2
            if target==nums[m]:return True
            
            while nums[l]==nums[r] and l<r:
                if nums[l]==target:
                    return True
                l+=1
                r-=1
               
            
            if nums[m] >= nums[l]:
                #left increase
                if nums[m]>=target>=nums[l]:
                    r=m-1
                else:
                    l=m+1
            else:
                #right increase
                if   nums[r]>=target>=nums[m]:
                    l=m+1
                else:
                    r=m-1
        
        return False

需要注意特别处理 nums[l]==nums[r] 情况 而且要确保 l小于r 也就是aba情形。 这样才能l+1 , r-1。

82. Remove Duplicates from Sorted List II (Medium)

Given the head of a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list. Return the linked list sorted as well.

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
        
        dummyhead = ListNode(val='NULL',next=head)
        
        pre = dummyhead
        cur = head

        while cur and cur.next:
            
            if cur.val==cur.next.val:
                #find dup, do while loop til end, update pre and cur
                while cur and cur.next and cur.val==cur.next.val:
                    cur = cur.next

                pre.next = cur.next if cur.next else None
                cur = cur.next if cur.next else None
            else:
                #normal update
                pre=cur
                cur=cur.next
        
        return dummyhead.next


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:

        # a  b  c  c  d  d  e
        # P  C
        #    P        C
        #  a  a c  c d 
        # P means previous C means current

             
        dummyhead = ListNode(val='NULL',next=head)
        pre=dummyhead
        cur = head
        while cur and cur.next:
            #print(cur.val)
            if cur.next and cur.next.val!=cur.val:
                pre = cur
                cur = cur.next
            elif cur.next and cur.next.val==cur.val:
                while cur.next and cur.next.val==cur.val:
                    cur = cur.next
                cur = cur.next
                if pre:
                    pre.next = cur
                
        return dummyhead.next

83. Remove Duplicates from Sorted List (Easy)

Given the head of a sorted linked list, delete all duplicates such that each element appears only once. Return the linked list sorted as well.

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
        
        dummyhead = ListNode(val='NULL',next=head)
        pre=dummyhead
        cur=head
        while cur:
            if pre.val==cur.val:
                #find dup
                while cur and pre.val==cur.val:
                    cur=cur.next
                pre.next=cur
                
            else:
                #normal update
                pre=cur
                cur=cur.next
                
        return dummyhead.next

#answer way of writting
class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        cur=head
        while cur and cur.next:
            if cur.val==cur.next.val:
                cur.next=cur.next.next
            else:
                cur=cur.next
        
        return head

答案写法更优雅。。。

84. Largest Rectangle in Histogram (Hard)

重点记忆,遇到当前小于等于栈顶元素确定了右边界。开始计算,高度是stack.pop()左边界是stack【-1】,注意起始stack = 【-1】
Given an array of integers heights representing the histogram's bar height where the width of each bar is 1, return the area of the largest rectangle in the histogram.

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        stack=[-1]
        res=0
        for i in range(len(heights)):
            while stack[-1]!=-1 and heights[stack[-1]]>=heights[i]:
                res=max(res, heights[stack.pop()]*(i-stack[-1]-1)
            stack.append(i)
        
        while stack[-1]!=-1 and stack:
            res=max(res,heights[stack.pop()]*(len(heights)-stack[-1]-1))
        return res

没思路, 似乎是用stack 。。。但如何知道哪块板是需要的?
思路: 如果当前高度小于等于栈顶,说明找到了栈顶的右边界,开始计算。pop栈顶元素的高度为高度,宽度为目前位置到已经pop过的栈顶位置减一。 过完一遍后,如果栈里还有元素, 开始计算, pop栈顶元素的高度为高度, 宽度为目前位置(已经是len(heights)了)到已经pop过的栈顶位置减一。注意初始栈为-1, 方便计算面积公式再edge case 下成立。

85. Maximal Rectangle (Hard)

Given a rows x cols binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area.

class Solution:
    def maximalRectangle(self, matrix: List[List[str]]) -> int:
        
        # 似乎能转化成上一题,板子面积最大问题。
        
        def maxarea(nums):
            res = 0
            stack = [-1]
            for i, n in enumerate(nums):
                while stack[-1]!=-1 and nums[stack[-1]] >= n:
                    #calculate
                    res = max(res, nums[stack.pop()]*(i-stack[-1]-1))
                
                stack.append(i)
                
            while stack and stack[-1]!=-1:
                res = max(res, nums[stack.pop()]*(len(nums)-stack[-1]-1))
            return res  
        
        res = 0
        for rowid in range(len(matrix)):
            if rowid==0:
                row = [int(e) for e in matrix[0]]
                #print(row)
                res = max(res,maxarea(row[:]))
            else:
                currow = [int(e) for e in matrix[rowid]]
                row = [ cr+cr*r for (cr,r) in zip(currow,row)]
                #print(row)
                res = max(res,maxarea(row[:]))
        
         
        return res

直接用了上一题求解。。。。

86. Partition List (Medium)

Given the head of a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]:
        
        smallhead = ListNode(val='NULL')
        largehead = ListNode(val='NULL')
        small = smallhead
        large = largehead
        while head:
            if head.val<x:
                small.next = head
                small = small.next
            else:
                large.next = head
                large = large.next
                
            head = head.next
        
        #makde ends clean
        if small:
            small.next = None
        if large:
            large.next = None
        
        small.next = largehead.next
        
        return smallhead.next

class Solution:
    def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]:
        dummyheadA = ListNode(val='NULL')
        dummyheadB = ListNode(val='NULL')
        curA = dummyheadA
        curB = dummyheadB
        while head:
            headnext = head.next
            if head.val<x:
                curA.next = head
                curA = curA.next
                curA.next = None
            else:
                curB.next = head
                curB = curB.next
                curB.next = None
                
            head = headnext
        
        #print(dummyheadA.next)
        #print(dummyheadB.next)
        
        curA.next = dummyheadB.next

        return dummyheadA.next

87. Scramble String (Hard)

We can scramble a string s to get a string t using the following algorithm:
If the length of the string is 1, stop.
If the length of the string is > 1, do the following:
Split the string into two non-empty substrings at a random index, i.e., if the string is s, divide it to x and y where s = x + y.
Randomly decide to swap the two substrings or to keep them in the same order. i.e., after this step, s may become s = x + y or s = y + x.
Apply step 1 recursively on each of the two substrings x and y.
Given two strings s1 and s2 of the same length, return true if s2 is a scrambled string of s1, otherwise, return false.

# mem limit exceeded
class Solution:
    def isScramble(self, s1: str, s2: str) -> bool:

        @lru_cache(None)
        def scr(s):
            if len(s)==1: return [s]
            res = set()
            for i in range(1,len(s)):
                x =s[:i]
                y =s[i:]
                for left in scr(x):
                    for right in scr(y):
                        res.add(left+right)
                        res.add(right+left)
            res.add(s)
            return list(res)
        return s2 in scr(s1)

class Solution:
    @lru_cache(None)
    def isScramble(self, s1: str, s2: str) -> bool:
        m =len(s1)
        n=len(s2)
        if m!=n or sorted(s1)!=sorted(s2): return False
        if m<=3 or s1==s2: return True
        f = self.isScramble
        for i in range(1,len(s1)):
            if f(s1[:i],s2[:i]) and f(s1[i:],s2[i:]) or f(s1[:i],s2[-i:]) and f(s1[i:],s2[:-i]):
                return True
        return False


backtraking MLE TLE,重新想办法。。
答案很优雅,用了递归和mem

88. Merge Sorted Array (Easy)

You are given two integer arrays nums1 and nums2, sorted in non-decreasing order, and two integers m and n, representing the number of elements in nums1 and nums2 respectively.
Merge nums1 and nums2 into a single array sorted in non-decreasing order.

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        """
        
        # fill nums1 from end pos to head pos
        cur=len(nums1)-1
        while m>0 and n>0:
            if nums1[m-1]>nums2[n-1]:
                nums1[cur]=nums1[m-1]
                m-=1
            else:
                nums1[cur]=nums2[n-1]
                n-=1
            cur-=1
        
        while m>0:
            nums1[cur]=nums1[m-1]
            m-=1
            cur-=1
        while n>0:
            nums1[cur]=nums2[n-1]
            n-=1
            cur-=1

从后向前覆盖,避免overwrite。

89. Gray Code (Medium)

class Solution:
    def grayCode(self, n: int) -> List[int]:
        
        #  0      0
        #  1     [0  1]
        #  2     [00 01 11 10]
        
        level = [0,1]
        if n==1: return level
        for i in range(n-1):
            level_res  = []
            mask1 = 1<<(i+1)
            mask0 = 0
            for n in level:
                level_res.append(n|mask0)
            for n in level[::-1]:
                level_res.append(n|mask1)
            
            level=level_res
        
        return level

在每个level下,用0/1 mask遍历前一个level的结果就行了,注意mask1时候reverse遍历顺序。

90. Subsets II (Medium)

Given an integer array nums that may contain duplicates, return all possible subsets (the power set).
The solution set must not contain duplicate subsets. Return the solution in any order.

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        
        res = []
        def bt(temp,start):
            res.append(temp[:])
            
            for i in range(start,len(nums)):
                if i>start and nums[i]==nums[i-1]: continue
                temp.append(nums[i])
                bt(temp,i+1)
                temp.pop()
        
        nums.sort()
        bt([],0)
        return res

已经在backtrakcing总结篇写过,注意2点,去重,下一次bt起始位置为i+1,不look back。