leetcode questions: the second week

Posted by nyy2000 on Sun, 06 Mar 2022 13:39:06 +0100

Catalogue of series articles

leetcode: Week 1
leetcode questions: the second week

Tip: after writing the article, the directory can be generated automatically. For how to generate it, please refer to the help document on the right

preface

leetcode questions: the second week

Day 1 (breadth first search / depth first search)

1. Image rendering: Flood Fill

Example: pandas is a NumPy based tool created to solve data analysis tasks.
There is a picture represented by a two-dimensional integer array. Each integer represents the pixel value of the picture, and the value is between 0 and 65535.

Give you a coordinate (sr, sc) to represent the pixel value (row, column) at the beginning of image rendering and a new color value newColor, so that you can color the image again.

In order to complete the coloring work, starting from the initial coordinates, record the connected pixels with the same pixel value as the initial coordinates in the upper, lower, left and right directions of the initial coordinates, and then record the qualified pixels in these four directions and their corresponding connected pixels with the same pixel value as the initial coordinates in the four directions,... Repeat the process. Change the color value of all recorded pixels to the new color value.

Finally, the color rendered image is returned.

Example 1:

Input:
image = [[1,1,1],[1,1,0],[1,0,1]]
sr = 1, sc = 1, newColor = 2
Output: [[2,2,2], [2,2,0], [2,0,1]]
Resolution:
In the middle of the image, (coordinates (sr,sc)=(1,1)),
The color of all eligible pixels on the path is changed to 2.
Note that the pixel in the lower right corner is not changed to 2,
Because it is not a pixel connected with the initial point in the up, down, left and right directions.

class Solution:
    def __init__(self):
        self.image = [[0,0,0],[0,0,0]]
        self.sr = 0
        self.sc = 0
        self.newColor = 2

    def floodFill(self):
        image = self.image
        sr = self.sr
        sc = self.sc
        newColor = self.newColor
        # Algorithm part
        currColor = image[sr][sc]
        if currColor == newColor:
            return image
        w = len(image[0])
        h = len(image)
        def color(r, c):
            if image[r][c] == currColor:
                image[r][c] = newColor
                if r - 1 >= 0:
                    color(r - 1, c)
                if r + 1 < h:
                    color(r + 1, c)
                if c - 1 >= 0:
                    color(r, c - 1)
                if c + 1 < w:
                    color(r, c + 1)
        color(sr,sc)
        return image

The algorithm adopts dfs depth first traversal

2. Maximum area of island: Max Area of Island gives you a binary matrix grid with the size of m x n.

Islands are a combination of adjacent ones (representing land). The "adjacent" here requires that two ones must be adjacent in four horizontal or vertical directions. You can assume that all four edges of the grid are surrounded by 0 (representing water).

The area of an island is the number of cells on the island with a value of 1.

Calculate and return the largest island area in the grid. If there are no islands, the return area is 0.

Example 1: input: grid = [[0,0,1,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,1,1,0,0,0], [0,1,1,0,0,0,0,0], [0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,
0,0,0,0]] output: 6 explanation: the answer should not be 11, because the island can only contain 1 in the horizontal or vertical directions.

Example 2:
Input: grid = [[0,0,0,0,0,0,0,0]]
Output: 0

class Solution:
    def __init__(self):
        self.grid = [[0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
                     [0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
                     [0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0],
                     [0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0]]

    def maxAreaOfIsland(self):
        grid = self.grid
        # Algorithm part
        w = len(grid[0])
        h = len(grid)

        def DFS(r, c, count):
            grid[r][c] = 0
            count += 1
            if r - 1 >= 0 and grid[r - 1][c] == 1:
                count += DFS(r - 1, c, 0)

            if r + 1 < h and grid[r + 1][c] == 1:
                count += DFS(r + 1, c, 0)

            if c - 1 >= 0 and grid[r][c - 1] == 1:
                count += DFS(r, c - 1, 0)

            if c + 1 < w and grid[r][c + 1] == 1:
                count += DFS(r, c + 1, 0)
            return count

        count = 0
        max = 0
        for i in range(h):
            for j in range(w):
                if grid[i][j] == 1:
                    s = DFS(i, j, count)
                    if max < s:
                        max = s
        return max

The algorithm adopts dfs depth first traversal

Day 2 (breadth first search / depth first search)

1. Merge Two Binary Trees

Here are two binary trees: root1 and root2.

Imagine that when you overlay one tree over the other, some nodes on the two trees will overlap (while others won't). You need to merge the two trees into a new binary tree. The merging rule is: if two nodes overlap, add the values of the two nodes as the new values of the merged nodes; Otherwise, it is not null
The node of will be directly used as the node of the new binary tree.

Returns the merged binary tree.

Note: the merge process must start at the root node of the two trees.

Example 1:
Input: root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
Output: [3,4,5,5,4,null,7]

Example 2:
Input: root1 = [1], root2 = [1,2]
Output: [2,2]

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def mergeTrees(self):
        # python cannot forge binary tree chained storage, only record logic code and cannot run
        # if root1 and root2:
        #     root1.val += root2.val
        #     root1.left = self.mergeTrees(root1.left, root2.left)
        #     root1.right = self.mergeTrees(root1.right, root2.right)
        #     return root1
        # return root1 or root2
        pass

The algorithm adopts dfs depth first traversal

2. Fill in the next right node pointer of each node

Given a perfect binary tree, all leaf nodes are in the same layer, and each parent node has two child nodes. Binary tree is defined as follows:

struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
Fill in each of its next pointers so that this pointer points to its next right node. If the next right node cannot be found, set the next pointer to NULL.

In the initial state, all next pointers are set to NULL.

Example 1:
Input: root = [1,2,3,4,5,6,7]
Output: [1, #, 2,3, #, 4,5,6,7, #]
Explanation: given A binary tree, as shown in figure A, your function should fill in each next pointer to point to its next right node, as shown in Figure B. The serialized output is arranged by sequence traversal, and the nodes of the same layer are connected by the next pointer,'# 'marks the end of each layer.

Example 2:
Input: root = []
Output: []

"""
# Definition for a Node.
class Node:
    def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""


class Solution:
    def connect(self):
        # python cannot forge binary tree chained storage, only record logic code and cannot run
        # if not root:
        #     return root
        # leftchild = root
        # while leftchild.left:
        #     head = leftchild
        #     while head:
        #         head.left.next = head.right
        #         if head.next:
        #             head.right.next = head.next.left
        #         head = head.next
        #     leftchild = leftchild.left
        # return root
        pass

The algorithm adopts bfs breadth first traversal

Day 3 (breadth first search / depth first search)

1. Matrix

Given a matrix mat composed of 0 and 1, please output a matrix of the same size, where each lattice is the distance from the corresponding position element in mat to the nearest 0.

The distance between two adjacent elements is 1

Example 1:
Input: mat = [[0,0,0],[0,1,0],[0,0,0]]
Output: [[0,0,0], [0,1,0], [0,0,0]]

Example 2:
Input: mat = [[0,0,0],[0,1,0],[1,1,1]]
Output: [[0,0,0], [0,1,0], [1,2,1]]

import collections
class Solution:
    def __init__(self):
        self.mat = [[0, 0, 0], [0, 1, 0], [1, 1, 1]]

    def updateMatrix(self):
        mat = self.mat
        # Algorithm part
        m = len(mat)
        n = len(mat[0])
        dist = [[0] * n for _ in range(m)]
        zero_list = []
        for i in range(m):
            for j in range(n):
                if mat[i][j] == 0:
                    zero_list.append((i, j))
        q = collections.deque(zero_list)
        seen = set(zero_list)

        while q:
            i, j = q.popleft()
            for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]:
                if 0 <= ni < m and 0 <= nj < n and (ni, nj) not in seen:
                    dist[ni][nj] = dist[i][j] + 1
                    q.append((ni, nj))
                    seen.add((ni, nj))
        return dist

The algorithm adopts bfs breadth first traversal

2. Rotten oranges

In a given m x n grid, each cell can have one of the following three values:

A value of 0 represents an empty cell;
A value of 1 represents fresh oranges;
A value of 2 represents rotten oranges.
Every minute, the adjacent fresh oranges in four directions around the rotten oranges will rot.

The minimum number of minutes that must elapse until no oranges are returned in the cell. If this is not possible, return - 1.

Example 1:
Input: grid = [[2,1,1],[1,1,0],[0,1,1]]
Output: 4

Example 2:
Input: grid = [[2,1,1],[0,1,1],[1,0,1]]
Output: - 1
Explanation: the orange in the lower left corner (row 2, column 0) will never rot, because rot will only occur in four positive directions.

Example 3:
Input: grid = [[0,2]]
Output: 0
Explanation: because there are no fresh oranges in 0 minutes, the answer is 0.

import collections
class Solution:
    def __init__(self):
        self.grid = [[2, 1, 1], [1, 1, 0], [0, 1, 1]]

    def orangesRotting(self):
        grid = self.grid
        # Algorithm part
        m = len(grid)
        n = len(grid[0])
        bad_list = []
        for i in range(m):
            for j in range(n):
                if grid[i][j] == 2:
                    bad_list.append((i, j))
        q = collections.deque(bad_list)
        time = 0

        def good_bag(q):
            ls = []
            while q:
                i, j = q.popleft()
                for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]:
                    if 0 <= ni < m and 0 <= nj < n and grid[ni][nj] == 1:
                        grid[ni][nj] = 2
                        ls.append((ni, nj))
            q = collections.deque(ls)
            return q

        while q:
            q = good_bag(q)
            time += 1
        if time > 0:
            time -= 1

        for i in range(m):
            for j in range(n):
                if grid[i][j] == 1:
                    return -1
        return time

The algorithm adopts bfs breadth first traversal

Day 4 (recursion / backtracking)

1. Merge two ordered linked lists

Merge the two ascending linked lists into a new ascending linked list and return. The new linked list is composed of all nodes of a given two linked lists.

Example 1:
Input: l1 = [1,2,4], l2 = [1,3,4]
Output: [1,1,2,3,4,4]

Example 2:
Input: l1 = [], l2 = []
Output: []

Example 3:
Input: l1 = [], l2 = [0]
Output: [0]

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeTwoLists(self):
        # Cannot simulate linked list, only record algorithm
        # if list1 is None:
        #     return list2
        # elif list2 is None:
        #     return list1
        # elif list1.val < list2.val:
        #     list1.next = self.mergeTwoLists(list1.next, list2)
        #     return list1
        # else:
        #     list2.next = self.mergeTwoLists(list1, list2.next)
        #     return list2
        pass

The algorithm adopts recursion

2. Reverse linked list

Give you the head node of the single linked list. Please reverse the linked list and return the reversed linked list.

Example 1:
Input: head = [1,2,3,4,5]
Output: [5,4,3,2,1]

Example 2:
Input: head = [1,2]
Output: [2,1]

Example 3:
Input: head = []
Output: []

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseList(self):
        # Record only algorithm
        # ls = []
        # ans = head
        # while head:
        #     ls.append(head.val)
        #     head = head.next
        # head = ans
        # while ls:
        #     head.val = ls.pop()
        #     head = head.next
        # return ans
        pass

The algorithm adopts stack

Day 5 (recursion / backtracking)

1. Combination

Given two integers n and k, returns the combination of all possible k numbers in the range [1, n].

You can return answers in any order.

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

Example 2:
Input: n = 1, k = 1
Output: [[1]]

    def combine(self):
        n = self.n
        k = self.k
        # Algorithmic logic
        result = []
        path = []
        def backtrack(n, k, index):
            if len(path) == k:
                result.append(path[:])
                print(result)
                return
            for i in range(index, n+1):
                path.append(i)
                backtrack(n, k, i + 1)
                path.pop()

        backtrack(n, k, 1)
        return result

The algorithm adopts backtracking

2. Full arrangement

Given an array nums without duplicate numbers, all possible permutations are returned. You can return answers in any order.

Example 1:
Input: num = [1,2,3]
Output: [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]

Example 2:
Input: num = [0,1]
Output: [[0,1], [1,0]]

Example 3:
Input: num = [1]
Output: [[1]]

class Solution:
    def __init__(self):
        self.nums = [1, 2, 3]

    def permute(self):
        nums = self.nums
        # Algorithmic logic
        result = []
        lens = len(nums)
        used = [0] * lens
        if lens == 0:
            return []
        depth = 0
        path = []

        def dfs(nums, lens, depth, used, path):
            if depth == lens:
                result.append(path[:])
                return
            for i in range(lens):
                if used[i] == 1:
                    continue
                path.append(nums[i])
                used[i] = 1
                dfs(nums, lens, depth + 1, used, path)
                path.pop()
                used[i] = 0

        dfs(nums, lens, depth, used, path)
        return result

The algorithm adopts backtracking

3. The letters are arranged in full case

Given a string s, we can get a new string by converting each letter in string s to case.

Returns a collection of all possible strings. Returns the output in any order.

Example 1:
Input: s = "a1b2"
Output: [A1B2 "," A1B2 "," A1B2 "," A1B2 "]

Example 2:
Input: s = "3z4"
Output: ["3z4", "3z4"]

class Solution:
    def __init__(self):
        self.s = "a1b2"

    def letterCasePermutation(self):
        s = self.s
        # Algorithmic logic
        result = []
        n = len(s)
        if n == 0:
            return [""]
        start = 0

        def dfs(start, temp):
            if len(temp) == n:
                result.append(temp)
                return
            if s[start].isdigit():
                dfs(start + 1, temp + s[start])
            elif s[start].islower():
                dfs(start + 1, temp + s[start])
                dfs(start + 1, temp + s[start].upper())
            else:
                dfs(start + 1, temp + s[start])
                dfs(start + 1, temp + s[start].lower())

        dfs(start, "")
        return result

The algorithm adopts dfs depth first traversal

Day 6 (dynamic planning)

1. Climb stairs

Suppose you are climbing stairs. You need n steps to reach the roof.

You can climb one or two steps at a time. How many different ways can you climb to the roof?

Example 1:
Input: n = 2
Output: 2
Explanation: there are two ways to climb to the roof.

  1. 1st order + 1st order
  2. Second order

Example 2:
Input: n = 3
Output: 3
Explanation: there are three ways to climb to the roof.

  1. 1st order + 1st order + 1st order
  2. 1st order + 2nd order
  3. 2nd order + 1st order
class Solution:
    def __init__(self):
        self.n = 44

    def climbStairs(self):
        n = self.n
        # Algorithm part
        if n == 1:
            return 1
        if n == 2:
            return 2
        d1 = 1
        d2 = 2
        sum = 0
        for i in range(3, n + 1):
            sum = d1 + d2
            d1 = d2
            d2 = sum
        return d2

The algorithm adopts dynamic programming

2. House raiding

You are a professional thief who plans to steal houses along the street. There is a certain amount of cash hidden in each room. The only restrictive factor affecting your theft is that the adjacent houses are equipped with interconnected anti-theft systems. If two adjacent houses are intruded by thieves on the same night, the system will automatically alarm.

Given a non negative integer array representing the amount stored in each house, calculate the maximum amount you can steal overnight without touching the alarm device.

Example 1:
Input: [1,2,3,1]
Output: 4
Explanation: steal house 1 (amount = 1) and then steal house 3 (amount = 3).
Maximum amount of theft = 1 to 4.

Example 2:
Input: [2,7,9,3,1]
Output: 12
Explanation: steal house 1 (amount = 2), steal house 3 (amount = 9), and then steal house 5 (amount = 1).
Maximum amount stolen = 2 + 9 + 1 = 12.

class Solution:
    def __init__(self):
        self.list = [1, 2, 3, 1]

    def rob(self):
        nums = self.list
        # Algorithmic logic
        n = len(nums)
        if n == 0:
            return 0
        if n == 1:
            return nums[0]
        first = nums[0]
        second = max(nums[0], nums[1])
        for i in range(2, n):
            temp = second
            second = max(second, first + nums[i])
            first = temp
        return second

The algorithm adopts dynamic programming

3. Triangle minimum path and

Given a triangle, find the minimum path sum from top to bottom.

Each step can only move to the adjacent nodes in the next row. Adjacent nodes here refer to two nodes whose subscript is the same as or equal to the subscript + 1 of the previous node. That is, if it is in the subscript i of the current row, the next step can be moved to the subscript i or i + 1 of the next row.

Example 1:

Input: triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
Output: 11
Explanation: as shown in the following diagram:
2
3 4
6 5 7
4 1 8 3
The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).
Example 2:

Input: triangle = [[-10]]
Output: - 10

class Solution:
    def __init__(self):
        self.triangle = [[-1], [2, 3], [1, -1, -3]]

    def minimumTotal(self):
        triangle = self.triangle
        # Algorithm part
        n = len(triangle)
        f = [0] * n
        f[0] = triangle[0][0]
        for i in range(1, n):
            f[i] = f[i - 1] + triangle[i][i]
            for j in range(i - 1, 0, -1):
                f[j] = min(f[j - 1], f[j]) + triangle[i][j]
            f[0] += triangle[i][0]
        return min(f)

The algorithm adopts dynamic programming

summary

In the past two weeks, I have been practicing the introduction of algorithm. The records are relatively simple. The introduction is almost over, and the blog behind me may be updated every day.

Topics: Operation & Maintenance network leetcode server