Summary of Leetcode 1-100 Media Difficulty Topics

Posted by Entire on Sat, 07 Sep 2019 07:00:25 +0200

Write in front

After nearly half a month's arrangement, I finally finished the analysis of easy and media topics of the first 100 questions. (The autumn tips have already begun. I wish myself good luck. (Later, I will gradually make up hard in my spare time.)

Articles Catalogue

2. Add Two Numbers (Medium)

Topic Description

Add two linked lists

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.

Thoughts on Problem Solving

"""
//Similar to merging two linked lists
1. In order l2 The addition of the element of the ___________ to l1 in
2. When a list has been completed, The next thing to do is add up the carry and the rest of the list.
3. When the length of two linked lists is equal, To determine whether the last node value is greater than 10, Possible carry value
4. After traversing all nodes, If carry value still exists, Add a new node
"""
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        head = l1
        carry = 0
        while l1 or l2:
            
            if l1 and l2:
                s = l1.val + l2.val + carry
                l1.val = s%10 
                carry = s//10
                last = l1 # If l1 is empty, refer to l2 as the last node.
                l1 = l1.next
                l2 = l2.next
                
            elif l1: # l1 is longer than l2
                s = l1.val + carry # Completion carry
                l1.val = s%10 
                carry = s//10
                if carry == 0: # If there is no more carry, the sum is terminated ahead of time.
                    break
                last = l1
                l1 = l1.next
                
            elif l2: # l1 is shorter than l2
                last.next = l2
                s = l2.val + carry
                l2.val = s%10 
                carry = s//10
                if carry == 0:
                    break
                last = l2
                l2 = l2.next
                
        if last.val >= 10:
            last.val = last.val % 10
            carry = 1
        if carry: #If carry has value, a new node needs to be added.
            last.next = ListNode(1)
        return head
                

3. Longest Substring Without Repeating Characters (Medium)

https://leetcode.com/problems/longest-substring-without-repeating-characters/
Topic Description

Give a string and return the longest substring without duplicate elements.

Input: "abcabcbb"
Output: 3 
Explanation: The answer is "abc", with the length of 3.

Thoughts on Problem Solving

"""
//Set up a sliding window.
//Whether the left boundary will repeat is check ed every time the right boundary slides a position. If the left boundary is repeated, the left boundary slides to the right until the character on the left boundary is not equal to the character on the right boundary position is unknown.
//At the end of each move, check the current window length.
"""
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        if s == '':
            return 0
        start = end = result = 0
        while end < len(s):
            if s[end] not in s[start:end]:
                end += 1
                result = max(result, end-start)
            else:
                start = start + s[start:end].find(s[end]) + 1 #return the index of s[end] in s[start:end]
                end += 1
        return result

5. Longest Palindromic Substring (Medium)

Topic Description

Give a string and find the longest palindrome substring.

Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.

Thoughts on Problem Solving

"""
//Traverse all nodes.
	1. From the current node, Traveling to both sides, Until the elements are unequal. Get a palindrome string.
	2. check Current palindrome string
//Notice the parity length of the original string
"""
class Solution:
    def longestPalindrome(self, s: str) -> str:
        Max = 0
        longest = ''
        for i in range(len(s)):

            #odd case, like'aba'
            subStr = self.helper(s, i, i)
            if len(subStr) >= Max:
                Max = len(subStr)
                longest = subStr
                
            #even case, like'abba'
            subStr = self.helper(s, i, i+1)
            if len(subStr) >= Max:
                Max = len(subStr)
                longest = subStr 
                
        return longest

    def helper(self, s, start, end):   
        subStr = ''
        while start >= 0 and end <len(s) and s[start] == s[end]:
            subStr = s[start:end+1]
            start -= 1
            end += 1
        return subStr

6. ZigZag Conversion (Medium)

Topic Description

The string "PAYPALISHIRING" is written in Z-shaped walk and the output is "PAHNAPLSIIGYIR" line by line.

P   A   H   N
A P L S I I G
Y   I   R

Design the conversion function.

Thoughts on Problem Solving

# The inverted Z word is stitched together, and the rule of forming Z word is found first.
'''
(*      *) Although yes z The pattern looks complex, but it's actually simple. The trend is in the order of straight down and inclined upward.
*     * *  Create five storage spaces to store the letters that you walk through each time.
*   *   *
* *     *
*       * 
'''
class Solution:
    def convert(self, s: str, numRows: int) -> str:
        # In special cases, the characters are only enough to set the first vertical column.
        if numRows == 1 or numRows >= len(s):
            return s
        L = [''] * numRows
        index = 0
        # Step down, when step=-1, turn back and go up
        for x in s:
            L[index] += x
            if index == 0: step = 1
            if index == numRows - 1: step = -1
            index += step
        return ''.join(L)

8. String to Integer (atoi) (Medium)

https://leetcode.com/problems/string-to-integer-atoi/
Topic Description

Thoughts on Problem Solving

class Solution:
    def myAtoi(self, s: str) -> int:
        if s == '':
            return 0
        # Remove the space from the string and save it in the list as long as you study the first element of the list.
        s2 = s.strip().split(' ')[0]
        # It still needs to be judged once, or it will be wrong.
        if s2 == '':
            return 0
        
        flag = 1
        num = {'1','2','3','4','5','6','7','8','9','0'}
        
        #Save symbols
        if s2[0] == '-':
            flag = -1
            s2 = s2[1:]
        elif s2[0] == '+':
            s2 = s2[1:]
        # Critical judgment, too important! A single character'+'or'-'
        if s2 == '':
            return 0
            
        # The first character is the letter returning 0
        if s2[0] not in num:
            return 0
        # If you follow the letters, try to get rid of them.
        for i in s2:
            if i not in num:
                index = s2.index(i)
                s2 = s2[:index]
                break
        
        s2 = flag * int(s2)
        
        if s2 > 2**31 - 1:
            return 2**31 - 1
        elif s2 < -(2**31):
            return -(2**31)
        
        return s2

11. Container With Most Water (Medium)

https://leetcode.com/problems/container-with-most-water/
Topic Description

Given an array, each number represents the length of the partition to determine the maximum volume that can hold water.

Input: [1,8,6,2,5,4,8,3,7]
Output: 49

Thoughts on Problem Solving

"""
//Short partitions determine the height of the container.
//Set up two pointers and move them from the beginning to the middle.
	1.If the head pointer is larger than the tail pointer, Then the tail pointer moves to the head.
	2.If the head pointer is less than the tail pointer, Then the head pointer moves to the tail..
	3.Every move, check Current volume.
"""
class Solution:
    def maxArea(self, height: List[int]) -> int:
        result = 0
        start = 0
        end = len(height)-1
        while start < end:
            result = max(result, min(height[start], height[end]) * (end - start))
            #Take the two lines in the opposite direction.
            if height[start] < height[end]:
                start += 1
            else:
                end -= 1
        return result

12. Integer to Roman (Medium)

https://leetcode.com/problems/integer-to-roman/
Topic Description

Convert Roman numerals to decimal numerals.

Thoughts on Problem Solving

class Solution:
    def intToRoman(self, num: int) -> str:
        value_roman = {1000:"M", 900:"CM", 500:"D", 400:"CD",
                       100:"C", 90:"XC", 50:"L", 40:"XL",
                       10:"X", 9:"IX", 5:"V", 4:"IV", 1:"I"}
        roman = ""
        for v in [1000,900,500,400,100,90,50,40,10,9,5,4,1]:
            roman += value_roman[v] * (num//v)
            num %= v
        return roman

15. 3Sum (Medium) **

https://leetcode.com/problems/3sum/
Topic Description

Given an array, find combinations that make sum zero. Combinations cannot be repeated.

Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[ [-1, 0, 1], [-1, -1, 2] ]

Thoughts on Problem Solving

"""
//dynamic programming
//Sort the arrays first. 
//From scratch, iterate through the elements one by one, with the position i, the left pointer pointing to i+1, and the right pointer pointing to tail.
//When the left pointer < the right pointer:
	1. Add the values pointed by three pointers.
	2. And greater than 0, Explanation and need reduction, Move the right pointer to the left(Because arrays are ordered, The number on the right side is greater than that on the left.)
	3. And less than 0, Explanation and need increase. Move the left pointer to the right
	4. When sum equals zero, Continue moving the left and right pointers to remove elements that are the same as the current value
"""
class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:        
        if len(nums) <3: # deal with special input
            return []
        elif len(nums) == 3:
            if sum(nums) == 0:
                return [sorted(nums)]
            
        res = []
        nums.sort()
        for i in range(len(nums)-2):
            if i > 0 and nums[i] == nums[i-1]:
                continue
            l, r = i+1, len(nums)-1            
            while l < r:
                s = nums[i] + nums[l] + nums[r]
                if s < 0:
                    l +=1 
                elif s > 0:
                    r -= 1
                else:
                    res.append((nums[i], nums[l], nums[r]))
                    while l < r and nums[l] == nums[l+1]:
                        l += 1
                    while l < r and nums[r] == nums[r-1]:
                        r -= 1
                    l += 1; r -= 1
        return res

16. 3Sum Closest (Medium)

https://leetcode.com/problems/3sum-closest/
Topic Description

In the same question, just give a target and find the closest value to the target.

Thoughts on Problem Solving

"""
//Same question, three pointers.
"""
class Solution:
    def threeSumClosest(self, nums, target):
        nums.sort()
        res = sum(nums[:3])
        for i in range(len(nums)):
            l, r = i+1, len(nums)-1
            while l < r:
                s = sum((nums[i], nums[l], nums[r]))
                if abs(s-target) < abs(res-target):
                    res = s
                if s < target:
                    l += 1
                elif s > target:
                    r -= 1
                else: # break early 
                    return res
        return res  

17. Letter Combinations of a Phone Number (Medium)

https://leetcode.com/problems/letter-combinations-of-a-phone-number/
Topic Description

Input numeric strings, output possible combinations of letters. (Nine Palace keys)

Input: "23"
Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

Thoughts on Problem Solving
recursion

"""

"""
class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        if digits == "":
            return []
        mapp = {'2': 'abc', 
                '3': 'def', 
                '4': 'ghi', 
                '5': 'jkl', 
                '6': 'mno', 
                '7': 'pqrs', 
                '8': 'tuv', 
                '9': 'wxyz'}
        res = []
        self.combinate(digits, mapp, 0, len(digits), '', res)
        return res
    
    def combinate(self, s, mapp, n, m, path, res):
        if n == m:
            res.append(path)
            return 
        for i in mapp[s[n]]:
            self.combinate(s, mapp, n+1, m, path+i, res) 

Non-recursive approach

class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        pad = {
            '2': 'abc',
            '3': 'def',
            '4': 'ghi',
            '5': 'jkl',
            '6': 'mno',
            '7': 'pqrs',
            '8': 'tuv',
            '9': 'wxyz'
        }
        if not digits:
            return []
        output = ['']
        for digit in digits:
            temp = output
            output = []
            for s in temp:
                output.extend([s + pad[digit][0], s + pad[digit][1], s+ pad[digit][2]])
                if digit == '7' or digit == '9':
                    output.append(s + pad[digit][3])
                    
        return output

18. 4Sum (Medium)

https://leetcode.com/problems/4sum/
Topic Description

With 3Sum, it's just four numbers and zero.

Thoughts on Problem Solving

"""
3Sum Expansion
//Pass 0-current number as target into 3Sum function in 4Sum
"""
class Solution:
    def fourSum(self, nums, target):
        results = []
        nums.sort()
        for i in range(len(nums)-3):
            if i == 0 or nums[i] != nums[i-1]:
                threeResult = self.threeSum(nums[i+1:], target-nums[i])
            for item in threeResult:
                results.append([nums[i]] + item)
        return results

    def threeSum(self, nums, target):
        results = []
        nums.sort()
        for i in range(len(nums)-2):
            l = i + 1; r = len(nums) - 1
            t = target - nums[i]
            if i == 0 or nums[i] != nums[i-1]:
                while l < r:
                    s = nums[l] + nums[r]
                    if s == t:
                        results.append([nums[i], nums[l], nums[r]])
                        while l < r and nums[l] == nums[l+1]: l += 1
                        while l < r and nums[r] == nums[r-1]: r -= 1
                        l += 1; r -=1
                    elif s < t:
                        l += 1
                    else:
                        r -= 1
        return results
==

19. Remove Nth Node From End of List (Medium)

https://leetcode.com/problems/remove-nth-node-from-end-of-list/
Topic Description

Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes 1->2->3->5.

Thoughts on Problem Solving

"""
//Creating one or two pointers can solve the problem of finding reciprocal nodes.
"""
class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        dummy = ListNode(0)
        dummy.next = head
        fast, slow = dummy, dummy
        for i in range(n+1):
            fast = fast.next
        while fast:
            fast, slow = fast.next, slow.next
        slow.next = slow.next.next
        return dummy.next

22. Generate Parentheses (Medium)

https://leetcode.com/problems/generate-parentheses/
Topic Description

Given n n n pairs of parentheses, output all possible legitimate combinations.
For example, given n = 3, a solution set is:

[
  "((()))",
  "(()())",
  "(())()",
  "()(())",
  "()()()"
]

Thoughts on Problem Solving
recursion

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        combos = []
        left = n
        right = n
        path = ''
        self.formParen(left,right,path,combos)
        return combos

    def formParen(self,left,right,path,combos):
    	# The left and right parentheses are used up at the same time, and the currently generated path is added to combos.
        if left == 0 and right == 0:
            combos.append(path)
        # When the left parentheses are exhausted, complete all the right parentheses.
        elif left == 0:
            combos.append(path+')'*right)
        # The left and right parentheses in front are paired, only the left parentheses can be used.
        elif right == left:
            self.formParen(left-1,right,path+'(',combos)
        # 
        else:
            self.formParen(left-1,right,path+'(',combos)
            self.formParen(left,right-1,path+')',combos)

24. Swap Nodes in Pairs (Medium)

https://leetcode.com/problems/swap-nodes-in-pairs/
Topic Description

Given a linked list, swap every two adjacent nodes and return its head.
Given 1->2->3->4, you should return the list as 2->1->4->3.

Thoughts on Problem Solving

"""
You need to be familiar with what the pointer points to.
	   last     p1   p2
 Before moving: dummy - > 1 - > 2 - > 3 - > 4 - > None
	   			               last    p1   p2
 After moving: dummy (last) - > 2 (p2) - > 1 (p1) - > 3 - > 4 - > None
 (Brackets indicate the last position of the pointer)
Each operation needs to move three pointers, temp is the original P2 pointing to content, P2 pointing to p1, p1 pointing to temp, last pointing to p2.
Each time the node is moved, it needs to update p1, p2, last
"""
class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:
        if head == None:
            return 
        if head.next == None:
            return head
        
        cur1, cur2 = head, head.next
        dummy = ListNode(0)
        last = dummy
        last.next = cur1
        while cur1:
            temp = cur2.next
            cur2.next = cur1
            cur1.next = temp
            last.next = cur2
            
            last = cur1
            cur1 = cur1.next
            if not cur1 or not cur1.next:
                break
            else:
                cur2 = cur1.next
        return dummy.next

29. Divide Two Integers (Medium) X

https://leetcode.com/problems/divide-two-integers/
Topic Description

Divide two numbers, you can't use multiplication, division, modulus.

Thoughts on Problem Solving

31. Next Permutation (Medium)

https://leetcode.com/problems/next-permutation/
Topic Description

The next permutation is that there can be no other number between the current number and the next number.

Thoughts on Problem Solving

"""
//Primary arrangement: 7 8 6 9 8 7 2
//Next: 7 8 7 2 6 8 9
//No arrangement between the two permutations can be found.

//Assume that the array size is n
1.From back to front, Find the first A[i-1] < A[i]Of. That's the position of six in the first permutation, and you can see it. A[i]reach A[tail]These are monotonic decreasing sequences..
2.stay A[i:tail]Find the ratio in the middle A[i-1]The smallest of the largest values. such as[9 8 7 2]7..
3.Exchange these two values, And A[i:tail]sort, From small to large.
"""
class Solution:
    def nextPermutation(self, nums: List[int]) -> None:
        for i in range(len(nums)-1, 0, -1):
            if nums[i] > nums[i-1]:
                nums[i:] = sorted(nums[i:])
                for j in range(i, len(nums)):
                    if nums[j] > nums[i-1]:
                        temp = nums[j]
                        nums[j] = nums[i-1]
                        nums[i-1] = temp
                        return
        nums.sort()

33. Search in Rotated Sorted Array (Medium)

https://leetcode.com/problems/search-in-rotated-sorted-array/
Topic Description

A non-repetitive incremental array rotates at a certain position, returns its index value given a number.
Time complexity O(logn) is required.
Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4

Thoughts on Problem Solving

"""
//Binary search finds the minimum. The minimum is the rotation point. An offset is obtained.
//Reuse binary lookup. Each mid needs offset correction to get realMid and compare it with target.
 
"""
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left, right = 0, len(nums)-1
        while left < right:
            mid = (left + right)//2
            if nums[mid] > nums[right]: left = mid + 1
            else: right = mid
        # when finish the while, we get left == right
        offset = left
        
        left, right = 0, len(nums)-1
        while left <= right:
            mid = (left + right)//2
            realMid = (mid + offset)%len(nums)
            if nums[realMid] == target:
                return realMid
            if nums[realMid] < target:
                left = mid + 1
            else:
                right = mid - 1
        return -1   

81. Search in Rotated Sorted Array II (Medium)

https://leetcode.com/problems/search-in-rotated-sorted-array-ii/
Topic Description

With the expansion of 30 questions, there may be duplicate numbers in the array.

Thoughts on Problem Solving

The train of thought turns from: Detailed ideas and differences with Search in Rotated Sorted Array I (python code)

The difference between this question and "Search Rotary Sort Array I" is that it needs to be preprocessed when judging the middle position of mid:

while low < high and nums[low] == nums[high]:
	low += 1  

This also causes the worst time complexity of the algorithm to become O(n). Whole or Binary Search

At the same time, I optimize the classification method based on I: first, determine the mid location (high or low), and further determine whether the target location is in a specific range (so-called specific range refers to the binary search range similar to the normal sort) directly into four categories.

python knowledge points: 2 < x < 3 can be written directly in python without disassembly

Code:

class Solution:
    def search(self, nums, target):
        if not nums:
            return False
        low = 0
        high = len(nums) - 1
        while low <= high:
            while low < high and nums[low] == nums[high]:#The aim is to accurately determine the mid position, so the worst time complexity of the algorithm is O(n).
                low += 1                  
            mid = (low+high)//2
            if target == nums[mid]:
                return True         
            elif nums[mid] >= nums[low]: #Patricia Lee Gauch
                if nums[low] <= target < nums[mid]:  
                    high = mid - 1
                else:
                    low = mid + 1
            elif nums[mid] <= nums[high]:  #Low area
                if nums[mid] < target <= nums[high]:
                    low = mid + 1
                else:
                    high = mid - 1
        return False

34. Find First and Last Position of Element in Sorted Array (Medium)

https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/
Topic Description

Given an incremental sequence, find the starting and ending positions of a given target (target repeated and continuous). There is no return [-1,-1]. Require time complexity O(logN)

Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]

Thoughts on Problem Solving

"""
//Both start and end bits use binary lookup. Note here that mid = right, when nums[mid] = nums[right], the final output position is right, right remains unchanged.
//Find the location of the target for the first time.
//The second lookup, target+1, yields two end s	
	target = 1
	1. [0,1,1] target+1 Location does not exist, What you get is the last position 2
	2. [0,1,1,3] target+1 Location does not exist, But the last one exists and is greater than 1., This will return to position 2.
	3. [0,1,1,2] target+1 Location exists, Return 3
"""
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        start = self.binarySearch(nums, target)
        if start == len(nums) or nums[start] != target:
            return [-1,-1]
        end = self.binarySearch(nums,target+1)
        if nums[end] > nums[start]:
            end -= 1
        return [start, end]
         
    def binarySearch(self, nums, target):
        left, right = 0, len(nums)-1
        while left < right:
            mid = (left + right) // 2
            if nums[mid] < target:
                left = mid + 1
            else:
                right = mid
        return left

36. Valid Sudoku (Medium)

https://leetcode.com/problems/valid-sudoku/
Topic Description

Input:
[
  ["5","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
Output: true

Thoughts on Problem Solving

"""
//Effective Sudoku requires three points:
1. Each row contains 1-9 And without repetition: row = set()
2. Each column contains 1-9 And without repetition: col = set()
3. Each 3*3 cube Contains 1-9 And without repetition cube = set()
//Every time you encounter a number, put (cur, i) in row, (j, cur) in col, (i//3, j//3, cur) in cube.

//The location//3 of each cell in a 3*3 nine-grid is the same, so we can get the "nine-grid coordinates" from it. There can be no duplicate numbers in the coordinates.
"""
class Solution:
    def isValidSudoku(self, board: List[List[str]]) -> bool:
        row = set()
        col = set()
        cube = set()
        for i in range(9):
            for j in range(9):
                if board[i][j] != '.':
                    cur = board[i][j]
                    if (i, cur) in row or (cur, j) in col or (i//3, j//3, cur) in cube: #i//3,j//3 so that all 3X3 squares can have their own coordinates. remember!
                        return False
                    row.add((i, cur))
                    col.add((cur, j))
                    cube.add((i//3, j//3, cur))
        return True

39. Combination Sum (Medium)

https://leetcode.com/problems/combination-sum/
Topic Description

Give a collection and find all combinations that are target ed.
ps. All numbers are positive and do not repeat

Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
  [7],
  [2,2,3]
]

Thoughts on Problem Solving
recursion

"""
//recursive thinking 
//Each time the tar value of the incoming helper decreases, when it is 0, put the path that comes all the way into res
"""
class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        res = []
        self.helper(candidates, target, [], res)
        return res
    def helper(self, candi, tar, path, res):
        if tar == 0:
        	# Preventing duplication
            if sorted(path) not in res:
                res.append(sorted(path))
            return 
            # The sum result is less than 0, the path is invalid
        if tar < 0:
            return 
        for i in candi:
            self.helper(candi, tar-i, path+[i], res)

40. Combination Sum II (Medium)

https://leetcode.com/problems/combination-sum-ii/
Topic Description

Give an array and find all the combinations with target.
ps. All numbers are positive and do not repeat

Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:
[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

Thoughts on Problem Solving

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        res = []
        self.helper(candidates, target, [], res)
        return res
    def helper(self, candi, tar, path, res):
        if tar == 0:
        	# Preventing duplication
            if sorted(path) not in res:
                res.append(sorted(path))
            return 
        # The sum result is less than 0, the path is invalid    
        if tar < 0:
            return 
        for i in range(len(candi)):
        	# Save running time, if the element in candidate is larger than the current remaining target, it is not considered directly
            if candi[i] > tar:
                continue
            self.helper(candi[:i]+candi[i+1:], tar-candi[i], path+[candi[i]], res)

42. Trapping Rain Water (Hard)

The stack is used to compare the current bar with the bar at the top of the stack. If the bar is smaller than the top of the stack, the new bar will be put on the stack. Otherwise, the water storage of the current bar and the bar at the top of the stack will be calculated. Then the stack will be pushed out and the comparison will be repeated until the current bar is smaller than the top or empty of the stack. At this time, the current bar will enter the stack. It ends when there is no new current bar.
The algorithm is as follows:

  • Store bar's index with stack (1)
  • Traversal array (2)
    • When stack is not empty or height [cur] > height [stack. top] (2.1)
      • Top the stack out of the stack (2.1.1)
      • Calculate the distance of current index and stack top index (2.1.2)
      • Calculating the water storage between height[height] and height[stack.top] depends on the smaller of the previous bar and current bar of stack.top (2.1.3)
      • Preservation of Water Storage Value (2.1.4)
    • Currbar stacking (2.2)
    • get a new current bar (2.3)
      https://leetcode.com/problems/trapping-rain-water/
class Solution:
    def trap(self, height) -> int:
        ans = 0 
        cur = 0
        stack = []								#(1)
        while cur < len(height):				#(2)
            while stack and height[cur] > height[stack[-1]]:#(2.1)
                top = stack.pop()				#(2.1.1)
                if(not stack):		
                    break
                distance = cur - stack[-1] - 1	#(2.1.2)
                high = min(height[cur], height[stack[-1]])-height[top]	#(2.1.3)
                ans += (distance * high)		#(2.1.4)
            stack.append(cur)	#(2.2)
            cur += 1			#(2.3)
        return ans

43. Multiply Strings (Medium)

https://leetcode.com/problems/multiply-strings/
Topic Description

Multiplication of two strings results in the output of strings

Input: num1 = "2", num2 = "3"
Output: "6"

Thoughts on Problem Solving


Java

""
//Use built-in functions quickly but interview is not recommended.
//Using the most basic vertical multiplication.
""
class Solution {
    public String multiply(String num1, String num2) {
        int len1 = num1.length(), len2 = num2.length();
        int carry = 0;
        int[] pos = new int[len1 + len2];
        
        // num1 is down, num2 is up
        for(int i=len1-1; i >= 0; i--){
            for(int j=len2-1; j>=0; j--){
                int mul = (num1.charAt(i) - '0') * (num2.charAt(j) - '0'); 
                int p1 = i + j, p2 = i + j + 1;
                int sum = mul + pos[p2];
                pos[p2] = sum % 10; // Number position
                pos[p1] += sum / 10;
            }
        }    
        
        StringBuilder sb = new StringBuilder();
        for(int p : pos) 
            if(!(sb.length() == 0 && p == 0)) 
                sb.append(p);
        return sb.length() == 0 ? "0" : sb.toString();
    }
}

46. Permutations (Medium)

https://leetcode.com/problems/permutations/
Topic Description

Given an array, output all possible permutations. There are no duplicate characters in the array.

Input: [1,1,2]
Output:
[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]

Thoughts on Problem Solving
Method 1: Recursion

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        res = []
        self.merge(nums, [], res)
        return res
    
    def merge(self, nums, path, res):
        if nums == []:
            if path not in res:
                res.append(path)
            return 
        
        for i in range(len(nums)):
        	# Remove the number of position i and add path
            self.merge(nums[:i]+nums[i+1:], path+[nums[i]], res)

non-recursive

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        ans = [[]]
        # 
        for n in nums:
            new_ans = []
           	# Remove each list in ans and insert n at all insertible locations in each list
            for arr in ans:
            	# For each arr in ans, there is len(arr)+1 position to fill in n
            	# When len(arr)==0, there is only one position. That is [n].
                for i in range(len(arr)+1):
                    new_ans.append(arr[:i]+[n]+arr[i:])
            ans = new_ans
        return ans

47. Permutations II (Medium)

https://leetcode.com/problems/permutations-ii/
Method 1: Recursion

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        res = []
        self.merge(nums, [], res)
        return res
    
    def merge(self, nums, path, res):
        if nums == []:
            if path not in res:
                res.append(path)
            return 
        
        for i in range(len(nums)):
        	# Remove the number of position i and add path
            self.merge(nums[:i]+nums[i+1:], path+[nums[i]], res)

non-recursive
Just one if I < len (arr) and arr [i]==n: break was added to the previous question.

"""
It should be noted here that there are repetitive elements in the processing of permutation, which causes the problem of getting repetitive permutation. 
The solution is that when you first encounter a duplicate element, place the duplicate element you encounter in front of the existing element, and then jump out of the loop. 
Prevent repetitive elements from rearranging to other positions of existing elements. For example, [1,1,2,1], after one round, [[1],
The second round starts with a 1, which is put at the front, and then break s the loop. 
Then you may encounter a 1 and do the same.

Initialization ans=[[]]
In turn, the elements n in nums are removed:
	In turn, each list in the pre-existing ans is taken out:
		Insert n at insertible locations in each list
		If the current insertible location element equals n, break loops to prevent element duplication
		Add all the resulting permutations to the ans
"""
class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        ans = [[]]
        # 
        for n in nums:
            new_ans = []
           	# Remove each list in ans and insert n at all insertible locations in each list
            for arr in ans:
            	# For each arr in ans, there is len(arr)+1 position to fill in n
            	# When len(arr)==0, there is only one position. That is [n].
                for i in range(len(arr)+1):
                    new_ans.append(arr[:i]+[n]+arr[i:])
                    # handles duplication
                    # If this cycle adds duplicate numbers, place them at the beginning and break them.
                    if i<len(arr) and arr[i]==n: break
            ans = new_ans
        return ans

48. Rotate Image (Medium)

https://leetcode.com/problems/rotate-image/
Topic Description

Given an n*n matrix, the output matrix rotates 90 degrees clockwise.

Given input matrix = 
[
  [1,2,3],
  [4,5,6],
  [7,8,9]],
rotate the input matrix in-place such that it becomes:
[
  [7,4,1],
  [8,5,2],
  [9,6,3]]

Thoughts on Problem Solving

"""
clockwise rotate
first reverse up to down, then swap the symmetry 
1 2 3     7 8 9     7 4 1
4 5 6  => 4 5 6  => 8 5 2
7 8 9     1 2 3     9 6 3
"""
class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        matrix.reverse()
        for i in range(len(matrix)):
            for j in range(i+1, len(matrix[0])):
                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]

49. Group Anagrams (Medium)

https://leetcode.com/problems/group-anagrams/
Topic Description

Given an array containing strings, group all strings containing the same letters.

Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
Output:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]

Thoughts on Problem Solving

"""
//Use dictionaries to improve retrieval efficiency.
//Each word is sorted alphabetically to get string as key.
"""
class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        dic = {}
        for word in strs:
            key = ''.join(sorted(word))
            if key not in dic:
                dic[key] = [word]
            else:
                dic[key].append(word)
        ans = []
        for key in dic.keys():
            ans.append(dic[key])
        return ans

54. Spiral Matrix (Medium)

https://leetcode.com/problems/spiral-matrix/
Topic Description

Give an array of mxn, spiral output.

Input:
[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]
Output: [1,2,3,6,9,8,7,4,5]

Thoughts on Problem Solving

Note:
If you use the string'right'to mark direction, you should pay attention to that strings are immutable objects like tuples, so you can't use direct = left to assign values, but use direct = direct.replace('right','right') to change values. It's troublesome, so you still use integers to represent parties. Xiang.

"""
//The program is mainly divided into three modules:
1. visit Current Point:
	//If the current point is not explored, output to res, mark that point has not been explored.
	//If the current point has been explored, turn and return the coordinates to the previous point.
2. To turn to:
	//There's nothing to tell
3. Go one step ahead, Encounter boundary turning:
	//Change the coordinates according to the current direction. If you encounter a boundary, turn and change the coordinates.
//Exploration termination condition: when res length equals the number of digits in matrix.
"""
class Solution:
    def spiralOrder(self, matrix):
        # four direction right->down->left-> up -> roop
        #                  0  ->  1 ->  2 -> 3  -> roop
        if len(matrix) == 0:
            return []
        if len(matrix) == 1:
            return matrix[0]
        
        direct = 0
        x, y, lastX, lastY= 0, 0, 0, 0
        row, col= len(matrix), len(matrix[0])
        res = []
        
        while len(res) < row * col:
            # The flag'x'indicates that it has passed.
            # Go straight.
            if matrix[x][y] != 'x':
                res.append(matrix[x][y])
                matrix[x][y] = 'x'
            
            elif matrix[x][y] == 'x':
                # turn the direction
                direct = self.turnDirect(direct)
                # Now that the current point has been explored, go back to the previous point
                x, y = lastX, lastY
            
            # Go in one direction.
            # If you go right to the end, y can't + 1, instead go down, x+1
            lastX, lastY = x, y
            x, y, direct = self.walk(x, y, row, col, direct)
            
        return res
 
    def turnDirect(self, direct):
        if direct == 0: return 1
        elif direct == 1: return 2     
        elif direct == 2: return 3      
        elif direct == 3: return 0
        
    def walk(self, x, y, row, col, direct):
        if direct == 0: 
            y += 1
            if y == n:
                y -= 1
                direct = 1
                x += 1
                    
        elif direct == 1: 
            x += 1       
            if x == row:
                x -= 1
                direct = 2
                y -= 1

        elif direct == 2: 
            y -= 1    
            if y < 0:
                y += 1
                direct = 3
                x -= 1

        elif direct == 3: 
            x -= 1
            if x < 0:
                x += 1
                direct = 0
                y += 1
        return x, y, direct

59. Spiral Matrix II (Medium)

https://leetcode.com/problems/spiral-matrix-ii/
Topic Description

Input n, output corresponding N*N spiral array.

Input: 3
Output:
[
 [ 1, 2, 3 ],
 [ 8, 9, 4 ],
 [ 7, 6, 5 ]
]

Thoughts on Problem Solving
Python's two-dimensional group suggests using a list generator: matrix = [[0 for I I N range (n)] for J in range (n)].

"""
//Similar to the previous question.
//Just change the input two-dimensional array into an all-zero array, change the current value when encountering zero, and turn direction when encountering non-zero.
//The rest is no different.
"""
class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        if n == 0:
            return []
        if n == 1:
            return [[1]]
        
        matrix = [[0 for i in range(n)] for j in range(n)]
        self.spiralOrder(matrix)  
        return matrix
    
    def spiralOrder(self, matrix):
        # four direction right->down->left-> up -> roop
        #                  0  ->  1 ->  2 -> 3  -> roop
        direct = 0
        x, y, lastX, lastY= 0, 0, 0, 0
        n = len(matrix)
        res = []
        num = 1
        
        while num <= n * n:
            # The flag'x'indicates that it has passed.
            # Go straight.
            if matrix[x][y] == 0:
                matrix[x][y] = num
                num += 1
            
            elif matrix[x][y] != 0:
                # turn the direction
                direct = self.turnDirect(direct)
                # Now that the current point has been explored, go back to the previous point
                x, y = lastX, lastY
            
            # Go in one direction.
            # If you go right to the end, y can't + 1, instead go down, x+1
            lastX, lastY = x, y
            x, y, direct = self.walk(x, y, n, direct)
            

    def turnDirect(self, direct):
        if direct == 0: return 1
        elif direct == 1: return 2     
        elif direct == 2: return 3      
        elif direct == 3: return 0
        
    def walk(self, x, y, n, direct):
        if direct == 0: 
            y += 1
            if y == n:
                y -= 1
                direct = 1
                x += 1
                    
        elif direct == 1: 
            x += 1       
            if x == n:
                x -= 1
                direct = 2
                y -= 1

        elif direct == 2: 
            y -= 1    
            if y < 0:
                y += 1
                direct = 3
                x -= 1

        elif direct == 3: 
            x -= 1
            if x < 0:
                x += 1
                direct = 0
                y += 1
        return x, y, direct

55. Jump Game (Medium)

https://leetcode.com/problems/jump-game/
Topic Description

Thoughts on Problem Solving
You can use recursion to solve the problem in the same way as before. But here it will be overtime.

"""
//Time complexity O(N), traverse the array once. As long as it can satisfy the need to skip all 0.
//Think of how far you can jump per grid as how much energy you can store up. Reduce energy by 1 per grid, if you can jump before you reach the end.
energy For 0, Represents failure. This reduces the energy and does not increase when you go to zero., 0 If the number of lattices is greater than or equal to
//The energy reserved in the past means that it will be exhausted.
"""
class Solution:
    def canJump(self, nums):
        if len(nums) == 1:
            return True
        if nums[0] == 0:
            return False
        
        energy = nums[0]
        for i in range(1,len(nums)):
            energy -= 1
            if nums[i] != 0 and energy < nums[i]:
                energy= nums[i]
            if energy == 0 and i != len(nums)-1:
                return False
        return True

56. Merge Intervals (Medium)

https://leetcode.com/problems/merge-intervals/

Similar topics

https://blog.csdn.net/bigtree_3721/article/details/89911532

Topic Description

Give a collection containing intervals and merge all duplicate intervals.

Input: [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].

Thoughts on Problem Solving

# Definition for an interval.
# class Interval:
#     def __init__(self, s=0, e=0):
#         self.start = s
#         self.end = e
# Learn to use lambda to sort elements first
class Solution:
    def merge(self, intervals: List[Interval]) -> List[Interval]:
        if len(intervals) == 0: return []
        # Sort by start value
        intervals = sorted(intervals, key = lambda x: x.start)
        res = [intervals[0]]
        for i in intervals[1:]:
            # If the starting point of i is less than the end point of res[-1], the end point of res[-1] is the end point of i and the maximum of itself.
            if i.start <= res[-1].end : 
                res[-1].end = max(res[-1].end, i.end)
            else:
                res.append(i)
        return res

60. Permutation Sequence (Medium)

https://leetcode.com/problems/permutation-sequence/
Topic Description

Thoughts on Problem Solving
Briefly take (n,k) = (4,21) for example, in the first iteration we divide the solution set into 4 groups: "1xxx", "2xxx", "3xxx", and "4xxx", while each group has 3! = 6 members.

From 21/6 = 3...3, we know that the 21th element is the 3rd element in the (3+1)th group. In this group, we can divide it into 3 sub-groups again: "41xx", "42xx" and "43xx", and each group has 2!=2 members.

Then, we calculate 3/2 and get 1...1, so it's the 1st element of (1+1)nd sub-group - "421x", and now it reach the base case with only one possibility - "4213".

Anyone pass the problem with different ideas?

class Solution:
# @return a string
    def getPermutation(self, n, k):

        ll = [str(i) for i in range(1,n+1)] # build a list of ["1","2",..."n"]

        divisor = 1
        for i in range(1,n): # calculate 1*2*3*...*(n-1)
            divisor *= i

        answer = ""
        while k>0 and k<=divisor*n:  # there are only (divisor*n) solutions in total 
            group_num = k//divisor
            k %= divisor

            if k>0: # it's kth element of (group_num+1)th group
                choose = ll.pop(group_num)
                answer += choose
            else: # it's last element of (group_num)th group
                choose = ll.pop(group_num-1) 
                answer += choose
                ll.reverse() # reverse the list to get DESC order for the last element
                to_add = "".join(ll)
                answer += to_add
                break

            divisor //= len(ll)

        return answer

61. Rotate List (Medium)

https://leetcode.com/problems/rotate-list/
Topic Description

Given a linked list, rotate the list to the right by k places, where k is non-negative.

Example 1:

Input: 1->2->3->4->5->NULL, k = 2
Output: 4->5->1->2->3->NULL
Explanation:
rotate 1 steps to the right: 5->1->2->3->4->NULL
rotate 2 steps to the right: 4->5->1->2->3->NULL

Thoughts on Problem Solving

"""
//Inspired by previous 24. Swap Nodes in Pairs.
low, fast Pointer, fast Advance k Location, When fast By the end, Stop traversal.
//At this point [low:fast] is a list that needs to be moved.
//Move to the head of the list. 
"""
class Solution:

    def rotateRight(self, head: ListNode, k: int) -> ListNode:
        if head == None:
            return None
        
        node = head
        lenth = 0
        while node:
            node = node.next
            lenth += 1
            
        dummy = ListNode(0)
        dummy.next = head
        low, fast = head, head
        pre = k % lenth
        if pre == 0:
            return head
        for i in range(pre):
            fast = fast.next
        while fast.next:
            low = low.next
            fast = fast.next
        dummy = ListNode(0)
        dummy.next = low.next
        fast.next = head
        low.next = None
        return dummy.next
        
        

62. Unique Paths (Medium)

https://leetcode.com/problems/unique-paths/
Topic Description

Given an m*n chessboard, robots are only allowed to walk right and down. There are several ways to get to the end.

This is a 7x3 chessboard, m=7, n=3

Example:
Input: m = 3, n = 2
Output: 3
Explanation:
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1. Right -> Right -> Down
2. Right -> Down -> Right
3. Down -> Right -> Right

Thoughts on Problem Solving
The time complexity of recursive violent solution is too high to be compiled. Using a two-dimensional array lab, the values indicate how many ways to reach the current coordinates in the graph.
The walking number of each lattice is equal to the sum of the walking number of one lattice on the left and one lattice on the top. It is similar to frog jumping.

"""

"""
class Solution:
    def uniquePaths(self, m, n):
        if not m or not n: # M x n matrix, m is x column number, n is y row number
            return 0
        # By default, the first column, the first line of the method is 1 (only one way to go).
        lab = [[1 for i in range(m)] for j in range(n)]
        # So traverse the subscripts from 1, skipping the first column of the first row.
        for i in range(1, n):
            for j in range(1, m):
                lab[i][j] = lab[i-1][j] + lab[i][j-1] #The number of methods to reach each lattice is the sum of the first two lattices.
        return lab[-1][-1]

63. Unique Paths II (Medium)

https://leetcode.com/problems/unique-paths-ii/
Topic Description

Given an m*n chessboard, where there is an obstacle somewhere, the robot is only allowed to go right and down. There are several ways to get to the end.

Example:
Input:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
Output: 2
Explanation:
There is one obstacle in the middle of the 3x3 grid above.
There are two ways to reach the bottom-right corner:
1. Right -> Right -> Down -> Down
2. Down -> Down -> Right -> Right

Thoughts on Problem Solving

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

        n = len(obstacleGrid)
        m = len(obstacleGrid[0])
        # Setting the number of all lattice methods to 1 does not mean that the default first row and first column of the previous question is a way of walking.
        # Because obstacles may appear in the first row or column. All lattices are set to zero.
        lab = [[0 for i in range(m)] for j in range(n)]
        
        for i in range(n):
            for j in range(m):
            	# If the first case is not an obstacle, set it to 1.
                if i == 0 and j == 0 and obstacleGrid[i][j] != 1:
                    lab[i][j] = 1
                    continue
                # If the coordinate map is an obstacle, the current method number is set at 0.
                if obstacleGrid[i][j] == 1:
                    lab[i][j] = 0
                    
                else:
                	# Pay attention to boundary conditions.
                    if i - 1 < 0: lab[i][j] = lab[i][j-1]
                    elif j - 1 < 0: lab[i][j] = lab[i-1][j]
                    else: lab[i][j] = lab[i-1][j] + lab[i][j-1] #The number of methods to reach each lattice is the sum of the first two lattices.
        return lab[-1][-1]

64. Minimum Path Sum (Medium)

https://leetcode.com/problems/minimum-path-sum/
Topic Description

It's a bit like a robot walking on a chessboard. Given an m*n chessboard, go from left to right and find the minimum path.

Input:
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
Output: 7
Explanation: Because the path 1→3→1→1→1 minimizes the sum.

Thoughts on Problem Solving

"""
//The way to solve the problem is the same, but lab does not store the total number of methods, but the minimum sum accumulated at the current point.
lab[i][j] = min(lab[i-1][j], lab[i][j-1])
"""
# You can modify it directly at grid without opening up a two-dimensional array of lab.
class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        if not grid:
            return 0

        n = len(grid)
        m = len(grid[0])
        # A two-dimensional array that holds the minimum sum currently available. 
        lab = [[0 for i in range(m)] for j in range(n)]
        
        for i in range(n):
            for j in range(m):
                if i == 0 and j == 0:
                    lab[i][j] = grid[i][j]
                    continue
                    
                # Pay attention to boundary conditions.
                if i - 1 < 0: lab[i][j] = grid[i][j] + lab[i][j-1]
                elif j - 1 < 0: lab[i][j] = grid[i][j] + lab[i-1][j]
                else: lab[i][j] = grid[i][j] + min(lab[i-1][j],lab[i][j-1]) #The number of methods to reach each lattice is the sum of the first two lattices.
        return lab[-1][-1]

71. Simplify Path (Medium)

https://leetcode.com/problems/simplify-path/
Topic Description

Example 1:

Input: "/home/"
Output: "/home"
Explanation: Note that there is no trailing slash after the last directory name.
Example 2:

Input: "/../"
Output: "/"
Explanation: Going one level up from the root directory is a no-op, 
as the root level is the highest level you can go.
Example 3:

Input: "/home//foo/"
Output: "/home/foo"
Explanation: In the canonical path, multiple consecutive slashes are 
replaced by a single one.
Example 4:

Input: "/a/./b/../../c/"
Output: "/c"
Example 5:

Input: "/a/../../b/../c//.//"
Output: "/c"
Example 6:

Input: "/a//b////c/d//././/.."
Output: "/a/b/c"

Thoughts on Problem Solving
Note:
Symbols other than numbers or letters (spaces, semicolons, etc.) are all False.
isalnum() must be a mixture of numbers and letters
isalpha() is case-insensitive

class Solution:
    def simplifyPath(self, path):
   		# Save the file directory with the stack.
        stack = []
        for token in path.split('/'):
        	# The empty character "" appears after split ting the array.
            if token in ('', '.'):
                pass
            elif token == '..':
                if stack: stack.pop()
            else:
                stack.append(token)
        return '/' + '/'.join(stack)

73. Set Matrix Zeroes (Medium)

https://leetcode.com/problems/set-matrix-zeroes/
Topic Description

Given an m*n matrix, if it is at a position of 0, then all rows and columns are set at 0.
Do it in-place.

Thoughts on Problem Solving
Note:
in-place algorithm does not depend on additional resources or a few additional resources, but only on output to cover the input of an algorithm operation.

"""
//Similar to the question of number of islands. If you encounter zero, you can't immediately change the rank to zero, which will affect the follow-up judgment.
//All you need to do is "mark" it. After you finish the first round of traversal, go through the array again, and put everything in it.
//Change the number marked to 0. 
"""
class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        height = len(matrix)
        if(height ==0): return
        width = len(matrix[0])
        for i in range(height):
            for j in range(width):
                if matrix[i][j] == 0:
                    for tmp in range(height):
                        if matrix[tmp][j] != 0:
                            matrix[tmp][j] = None
                    for tmp in range(width):
                        if matrix[i][tmp] != 0: 
                            matrix[i][tmp] = None

        for i in range(height):
            for j in range(width):
                if matrix[i][j] == None:
                    matrix[i][j] = 0   

74. Search a 2D Matrix (Medium)

https://leetcode.com/problems/search-a-2d-matrix/
Topic Description

Find target in an ordered two-dimensional array.

Input:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 3
Output: true

Thoughts on Problem Solving

"""
//Dichotomy is the first method to find + order, which has low time complexity. 
//In a multi-step transformation, mid is converted to index, where m is the number of rows in a two-dimensional array.
midi = mid // m 
midj = mid % m
//The rest is no different.
"""
class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:   
        n = len(matrix)
        if n == 0:  return False
        m = len(matrix[0]) 
        if m == 0:  return False
        
        left, right= 0, m * n - 1
        while left <= right:
            mid = (left + right)//2
            # get the real index of mid in 2D array.
            midi = mid // m 
            midj = mid % m
            
            if matrix[midi][midj] > target:
                right = mid - 1
            elif matrix[midi][midj] < target:
                left = mid + 1
                
            if matrix[midi][midj] == target:
                return True
        return False            

77. Combinations (Medium)

https://leetcode.com/problems/combinations/
Topic Description

Given two integers n and k
return all possible combinations of k numbers out of 1 ... n.

Example:

Input: n = 4, k = 2
Output:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

Thoughts on Problem Solving

"""
//The idea of universal dfs can also be used. But the time efficiency is too low.
"""
class Solution:
    def combine(self, n, k):
        res = []
        self.dfs(range(1,n+1), k, 0, [], res)
        return res
    
    def dfs(self, nums, k, index, path, res):
        #if k < 0:  #backtracking
            #return 
        if k == 0:
            res.append(path)
            return # backtracking 
        for i in range(index, len(nums)):
            self.dfs(nums, k-1, i+1, path+[nums[i]], res)

78. Subsets (Medium)

https://leetcode.com/problems/subsets/
Topic Description

Thoughts on Problem Solving

class Solution:
    def subsets(self, nums):
        nums.sort()
        result = [[]]
        for num in nums:
            result += [i + [num] for i in result]
        return result

90. Subsets II (Medium)

https://leetcode.com/problems/subsets-ii/
Topic Description

In the same question, only repetitive elements may exist in the given array.

Thoughts on Problem Solving
Method 1: The method is the same as the previous one. It is time-consuming to judge whether a list is repeated or not.

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        result = [[]]
        for num in nums:
            for j in [i + [num] for i in result]:
                if j not in result:
                    result.append(j)
        return result

Method 2: Use DFS to do it.

# DFS  
def subsetsWithDup(self, nums):
    res = []
    nums.sort()
    self.dfs(nums, 0, [], res)
    return res
    
def dfs(self, nums, index, path, res):
    res.append(path)
    for i in range(index, len(nums)):
        if i > index and nums[i] == nums[i-1]:
            continue
        self.dfs(nums, i+1, path+[nums[i]], res)

79. Word Search (Medium)

https://leetcode.com/problems/word-search/
Topic Description

Thoughts on Problem Solving

"""
search grid type, dfs Explore multiple directions, Recursive call, When touching the boundary or meeting the requirement, the current recursion ends.
"""
class Solution:
    def exist(self, board, word):
        if not board:
            return False
        for i in range(len(board)):
            for j in range(len(board[0])):
                if self.dfs(board, i, j, word):
                    return True
        return False

    # check whether can find word, start at (i,j) position    
    def dfs(self, board, i, j, word):
        if len(word) == 0: # all the characters are checked
            return True
        if i<0 or i>=len(board) or j<0 or j>=len(board[0]) or word[0]!=board[i][j]:
            return False
        tmp = board[i][j]  # first character is found, check the remaining part
        board[i][j] = "#"  # avoid visit agian 
        # check whether can find "word" along one direction
        res = self.dfs(board, i+1, j, word[1:]) or self.dfs(board, i-1, j, word[1:]) \
        or self.dfs(board, i, j+1, word[1:]) or self.dfs(board, i, j-1, word[1:])
        board[i][j] = tmp
        return res 

80. Remove Duplicates from Sorted Array II (Medium)

https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/
Topic Description

Thoughts on Problem Solving

class Solution:
    def removeDuplicates(self, nums):
        if nums==[]:
            return 0
        i = 0
        count = 1
        while i < len(nums) - 1:
            # If the count is equal to 2 and the next number is still repeated, the next number is removed.
            if count == 2 and nums[i] == nums[i+1]:
                nums.pop(i+1)
                #i -= 1
            # If the count is equal to 2 and the next number is different, the count is zero. Move the pointer down one bit.
            elif count == 2 and nums[i] != nums[i+1]:
                #nums.pop(i)
                i += 1
                count = 1
            elif count != 2 and nums[i] == nums[i+1]:
                if count < 2:
                    i += 1
                count += 1
                # If the count is full of 2, the pointer cannot go any further.
            else:
                i += 1
        # Processing the last number.
        return len(nums)

82. Remove Duplicates from Sorted List II (Medium)

https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/
Topic Description

Delete all duplicate nodes in an ordered list.

Thoughts on Problem Solving

"""
//When a duplicate node is encountered, a pointer is used to point to the parent of the first duplicate node.
//Link it to the next node of the last duplicate node
"""
class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        dummy = ListNode(0)
        dummy.next = head
        # Save the new node.
        pre = dummy
        cur = dummy.next
        while cur:
            if cur.next and cur.val == cur.next.val:
                #Traversing to cur.next value is no longer repeated
                while cur.next and cur.val == cur.next.val:
                    cur = cur.next
                #Link the parent node to the next non-repetitive value
                pre.next = cur.next
                #Pointer moves to next
                cur = pre.next
            else:
                pre = cur
                cur = cur.next
        return dummy.next

86. Partition List (Medium)

https://leetcode.com/problems/partition-list/
Topic Description

Thoughts on Problem Solving

"""
//Simple. Prepare two pointers, one smaller than 3, the other larger than 3, and link them together.
"""
class Solution:
    def partition(self, head: ListNode, x: int) -> ListNode:
        p1, p2 = ListNode(0), ListNode(0)
        head1, head2 = p1, p2
        while head:
            if head.val < x:
                p1.next = head
                p1 = p1.next
            else:
                p2.next = head
                p2 = p2.next
            head = head.next
        p2.next = None
        p1.next = head2.next
        return head1.next

89. Gray Code (Medium)

https://leetcode.com/problems/gray-code/
Topic Description

Given n n n, from 0000 onwards, only one position changes to get a new binary number. Find all the binary numbers available.

Input: 2
Output: [0,1,3,2]
Explanation:
00 - 0
01 - 1
11 - 3
10 - 2

For a given n, a gray code sequence may not be uniquely defined.
For example, [0,2,3,1] is also a valid gray code sequence.

00 - 0
10 - 2
11 - 3
01 - 1

Thoughts on Problem Solving

"""
Not every path leads to the complete combination. eg.
(n = 3) 000 -> 001 -> 011 -> 111 -> 110 -> 100 -> 101 -> X

The goal is to find a path which reaches the level == 2^n
Revert bit one at a time (always from the right most one) and append to the ans list if it is not already.
If the len(ans) == target, stop.
"""
class Solution(object):
    def grayCode(self, n):
        targetLevel = 2**n
        ans = []
        self.dfs(n, ans, 0, 1, targetLevel)   # Start with number = 0 (000), level = 1
        return ans

    def dfs(self, n, ans, num, level, targetLevel):
        if num in ans:
            return
        ans.append(num)
        if level == targetLevel:
            return
        for i in range(0, n):
            self.dfs(n, ans, num ^ (1 << i), level+1, targetLevel)  # num ^ (1 << i): revert a bit at a time
            if len(ans) == targetLevel: return  # result found. Stop.

91. Decode Ways (Medium) **

https://leetcode.com/problems/decode-ways/
Topic Description

A message containing letters from A-Z is being encoded to numbers using the following mapping:

'A' -> 1
'B' -> 2
...
'Z' -> 26
Given a non-empty string containing only digits, determine the total number of ways to decode it.

Example 1:

Input: "12"
Output: 2
Explanation: It could be decoded as "AB" (1 2) or "L" (12).
Example 2:

Input: "226"
Output: 3
Explanation: It could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).

Similar issues

62. Unique Paths
70. Climbing Stairs
93. Restore IP Addresses (Medium)
509. Fibonacci Number

You can practice it together.

Thoughts on Problem Solving

"""
I used a dp array of size n + 1 to save subproblem solutions. 
dp[0] means an empty string will have one way to decode, 
dp[1] means the way to decode a string of size 1.
I then check one digit and two digit combination and save 
the results along the way. In the end, dp[n] will be the end result.
"""
public class Solution {
    public int numDecodings(String s) {
        if(s == null || s.length() == 0) {
            return 0;
        }
        int n = s.length();
        int[] dp = new int[n+1];
        dp[0] = 1;
        dp[1] = s.charAt(0) != '0' ? 1 : 0;
        for(int i = 2; i <= n; i++) {
            int first = Integer.valueOf(s.substring(i-1, i));
            int second = Integer.valueOf(s.substring(i-2, i));
            if(first >= 1 && first <= 9) {
               dp[i] += dp[i-1];  
            }
            if(second >= 10 && second <= 26) {
                dp[i] += dp[i-2];
            }
        }
        return dp[n];
    }
}

92. Reverse Linked List II (Medium)

https://leetcode.com/problems/reverse-linked-list-ii/
Topic Description

Reverse a linked list from position m to n. Do it in one-pass.

Note: 1 ≤ m ≤ n ≤ length of list.

Example:

Input: 1->2->3->4->5->NULL, m = 2, n = 4
Output: 1->4->3->2->5->NULL

Thoughts on Problem Solving

/*

*/
public ListNode reverseBetween(ListNode head, int m, int n) {
    if(head == null) return null;
    ListNode dummy = new ListNode(0); // create a dummy node to mark the head of this list
    dummy.next = head;
    ListNode pre = dummy; // make a pointer pre as a marker for the node before reversing
    for(int i = 0; i<m-1; i++) pre = pre.next;
    
    ListNode start = pre.next; // a pointer to the beginning of a sub-list that will be reversed
    ListNode then = start.next; // a pointer to a node that will be reversed
    
    // 1 - 2 -3 - 4 - 5 ; m=2; n =4 ---> pre = 1, start = 2, then = 3
    // dummy-> 1 -> 2 -> 3 -> 4 -> 5
    
    for(int i=0; i<n-m; i++)
    {
        start.next = then.next;
        then.next = pre.next;
        pre.next = then;
        then = start.next;
    }
    
    // first reversing : dummy->1 - 3 - 2 - 4 - 5; pre = 1, start = 2, then = 4
    // second reversing: dummy->1 - 4 - 3 - 2 - 5; pre = 1, start = 2, then = 5 (finish)
    
    return dummy.next;
    
}

93. Restore IP Addresses (Medium)

https://leetcode.com/problems/restore-ip-addresses/
Topic Description

Enter a numeric string and output all possible valid IP.

Example:

Input: "25525511135"
Output: ["255.255.11.135", "255.255.111.35"]

Thoughts on Problem Solving

First, let's look at what a valid definition of ip is:

  1. The length of the ip without '.' should be equal to the length of s;
  2. The digit order of ip should be same as the digit order of s;
  3. Each part separated by the '.' should not start with '0' except only '0';
  4. Each part separared by the '.' should not larger than 255;
    Solve the problem with DFS.
class Solution:
    def restoreIpAddresses(self, s):
        res = []
        self.dfs(s, 0, "", res)
        return res
    
    def dfs(self, s, index, path, res):
        if index == 4:
            if not s:
                res.append(path[:-1])
            return # backtracking
        for i in xrange(1, 4):
            # the digits we choose should no more than the length of s
            if i <= len(s):
                #choose one digit
                if i == 1: 
                    self.dfs(s[i:], index+1, path+s[:i]+".", res)
                #choose two digits, the first one should not be "0"
                elif i == 2 and s[0] != "0": 
                    self.dfs(s[i:], index+1, path+s[:i]+".", res)
                #choose three digits, the first one should not be "0", and should less than 256
                elif i == 3 and s[0] != "0" and int(s[:3]) <= 255:
                    self.dfs(s[i:], index+1, path+s[:i]+".", res)

94. Binary Tree Inorder Traversal (Medium)

https://leetcode.com/problems/binary-tree-inorder-traversal/
Topic Description

Iteratively traverse arrays in order. left - > Middle - > right
Because the node on the left has to output first, and then it's the root node.

  1. All left nodes on the left side of the root node are stacked (until the last node without the left subtree).
  2. Pop up the top of the stack, read the data from the top of the stack (in this case, the top node is the root node without the left node), then put the right node on the top of the stack into the stack, treat the right node as a new root node, repeat 1 until the empty stack.

Thoughts on Problem Solving

"""
//Intermediate traversal is implemented iteratively.
"""
class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        stack, ans = [], []
        while True:
            while root:
                stack.append(root)
                root = root.left
            if not stack:
                return ans
            node = stack.pop()
            ans.append(node.val)
            root = node.right
        return ans

96. Unique Binary Search Trees (Medium)

https://leetcode.com/problems/unique-binary-search-trees/
Topic Description

Input n, output the number of all possible binary lookup trees consisting of N numbers

Input: 3
Output: 5
Explanation:
The above output corresponds to the 5 unique BST's shown below:

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

Thoughts on Problem Solving
Divide and conquer problems.

input root node Left node Right node Number of possible cases
1 1 0 0 1
Total 1
2 1 0 1 1
- 2 1 0 1
Total 2
3 1 0 2 1 x 2
- 2 1 1 1 x 1
- 3 2 0 2 x 1
Total 2 + 1 + 2 = 5
4 1 0 3 1 x 5
- 2 1 2 1 x 2
- 3 2 1 2 x 1
- 4 3 0 5 x 1
Total 5 + 2 + 2 + 5 = 14

Take the case of input 4 as an explanation. When we take the root node as 1, we can put three numbers on the right side. Then when the input is 3, we know that there are five kinds of arrangement, so we can get that when the root node is 1, there are five kinds of arrangement.

When the root node is 2, there can be one number on the left and two numbers on the right. The result is 1 x 2 = 2, so when the root node is 2, there are two kinds of arrangements.

So the equation of state transition is obtained as follows:
f(1) = 1
f(2) = 2
f(n) = Σ0n−1\Sigma_0^{n-1}Σ0n−1​ f(j) * f(n-1-j)

"""
//Instead of recursive writing, you use arrays.
//Each value represents a state. The value of a state is also calculated from the previous state.
"""
class Solution:
    def numTrees(self, n: int) -> int:
        if n == 0 or n == 1: return 1
        if n == 2: return 2
        
        num = [1, 1, 2]
        for i in range(3, n+1):
            s = 0
            for j in range(i):
                s += num[j]*num[i-1-j]
            num.append(s)
        return num[-1]

95. Unique Binary Search Trees II (Medium)

https://leetcode.com/problems/unique-binary-search-trees-ii/
Topic Description

Input n, output a set of all possible binary search trees consisting of n numbers.

Input: 3
Output:
[
  [1,null,3,2],
  [3,2,null,1],
  [3,1,null,null,2],
  [2,1,3],
  [1,null,2,null,3]
]
Explanation:
The above output corresponds to the 5 unique BST's shown below:

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

Thoughts on Problem Solving

class Solution(object):
    def generateTrees(self, n):
        """
        :type n: int
        :rtype: List[TreeNode]
        """
        if n == 0:
            return [[]]
        return self.dfs(1, n+1)
        
    def dfs(self, start, end):
        if start == end:
            return None
        result = []
        for i in xrange(start, end):
            for l in self.dfs(start, i) or [None]:
                for r in self.dfs(i+1, end) or [None]:
                    node = TreeNode(i)
                    node.left, node.right  = l, r
                    result.append(node)
        return result

98. Validate Binary Search Tree (Medium)

https://leetcode.com/problems/validate-binary-search-tree/
Topic Description

Determine whether a tree is a binary search tree.

Thoughts on Problem Solving

1. Recursive method:

class Solution:
    
    def isValidBST(self, root: TreeNode) -> bool:
        if root == None:
            return True
        tree = []
        self.inOrder(root, tree)
        if len(tree) == 1:
            return True
        for i in range(len(tree)-1):
            if tree[i] >= tree[i+1]:
                return False
        return True
        
    def inOrder(self, root, tree):
        if root == None:
            return 
        if root.left:
            self.inOrder(root.left, tree)
        tree.append(root.val)
        if root.right:
            self.inOrder(root.right, tree)

2. Iterative method:

"""
Record the precursor node prev. Record and stack the right node of each visit node.

The order of visiting nodes is left - > Middle - > right, and the numerical value is incremental. Therefore, the order of visiting nodes is left - > Middle - > right.
At each visit, the current value must not be <=prev.

The root node a visit s when there is no left node, and then goes to the right node of the stack. At this time, prev is the root node a.
The right node also cannot visit until it traverses to the leftmost node, and its value is greater than the value of prev. If the right node
 There is no such thing as the root node of a, which should be larger than the value of A.
"""
class Solution:
    def isValidBST(self, root: TreeNode) -> bool:
        if root == None:
            return True
        
        stack, ans = [], []
        prev = None #
        while True:
            while root:
                stack.append(root)
                root = root.left
            if not stack:
                return ans
            node = stack.pop()
            ###
            if prev != None and node.val <= prev.val:
                return False
            prev = node 
            ###
            ans.append(node.val)
            root = node.right
        return True

Topics: less Python REST Lambda