Go-Python-Java-C-LeetCode High Decomposition Method-Eighth Week Collection

Preface

The Go language part of this problem solution is based on LeetCode-Go.
The other parts are based on my practical learning.
Personal problem solution GitHub link: LeetCode-Go-Python-Java-C.
Welcome to subscribe to the CSDN column, one question per day, and make progress with the bloggers
in the LeetCode column.

Insert image description here

Part of the content of this article comes from online collection and personal practice. If any information contains errors, readers are welcome to criticize and correct them. This article is only for learning and communication, not for any commercial purposes.

50. Pow(x, n)

topic

Implement pow(x, n), which calculates x raised to the power n (xn).

Example 1:

Input: 2.00000, 10
Output: 1024.00000

Example 2:

Input: 2.10000, 3
Output: 9.26100

Example 3:

Input: 2.00000, -2
Output: 0.25000
Explanation: 2-2 = 1/22 = 1/4 = 0.25

Note:

  • -100.0 < x < 100.0
  • n is a 32-bit signed integer, within the range [−2^31, 2^31− 1]

The general idea of ​​the topic

Implement pow(x, n), that is, calculate the nth power function of x.

Problem-solving ideas

  • Asked to calculate Pow(x, n)
  • This question uses a recursive method to continuously divide n 2. Pay attention to the positive and negative numbers of n and the parity of n.
    Of course, let us introduce the problem-solving ideas of each version separately:

Go version problem-solving ideas:

  1. Basic case handling : First, check for special cases. If n is equal to 0, 1 is returned directly, because any number raised to the 0th power is equal to 1. If n is equal to 1, x is returned directly, because any number raised to the power of 1 is equal to itself.

  2. Handling negative exponents : If n is negative, change n to its absolute value and x to 1/x. This is because the negative exponent of x is equal to 1/the positive exponent of x.

  3. Recursive calculation : Next, calculate the n/2 power of x recursively and store the result in the tmp variable. This is because x^n can be split into x^(n/2) * x^(n/2).

  4. Handle odd and even numbers : According to the parity of n, if n is an even number, return the square of tmp; if n is an odd number, return the square of tmp multiplied by x.

Python version problem-solving ideas:

  1. Base case handling : Again, check for special cases first. If n equals 0, returns 1. If n equals 1, return x.

  2. Handling negative exponents : If n is negative, change n to its absolute value and x to 1/x.

  3. Recursive calculation : Use recursion to calculate the n/2 power of x and store the result in the tmp variable.

  4. Handle odd and even numbers : According to the parity of n, if n is an even number, return the square of tmp; if n is an odd number, return the square of tmp multiplied by x.

Java version solution ideas:

  1. Base case handling : Again, check for special cases first. If n equals 0, returns 1. If n equals 1, return x.

  2. Handling negative exponents : If n is negative, change n to its absolute value and x to 1/x.

  3. Recursive calculation : Use recursion to calculate the n/2 power of x and store the result in the tmp variable.

  4. Handle odd and even numbers : According to the parity of n, if n is an even number, return the square of tmp; if n is an odd number, return the square of tmp multiplied by x.

C++ version problem-solving ideas:

  1. Base case handling : Again, check for special cases first. If n equals 0, returns 1. If n equals 1, return x.

  2. Handling negative exponents : If n is negative, change n to its absolute value and x to 1/x.

  3. Data type conversion : Convert n to long long type to avoid integer overflow problems.

  4. Recursive calculation : Use recursion to calculate the n/2 power of x and store the result in the tmp variable.

  5. Handle odd and even numbers : According to the parity of n, if n is an even number, return the square of tmp; if n is an odd number, return the square of tmp multiplied by x.

These are the main ideas used in each version to solve the Pow(x, n) problem. They all use recursion to split the problem, taking into account the sign and parity of the exponent to obtain the final result.

code

Go

// 时间复杂度 O(log n), 空间复杂度 O(1)
func myPow(x float64, n int) float64 {
    if n == 0 {
        return 1
    }
    if n == 1 {
        return x
    }
    if n < 0 {
        n = -n
        x = 1 / x
    }
    // 递归计算 x 的 n/2 次幂
    tmp := myPow(x, n/2)
    if n%2 == 0 {
        // 如果 n 为偶数,则返回 tmp 的平方
        return tmp * tmp
    }
    // 如果 n 为奇数,则返回 tmp 的平方再乘以 x
    return tmp * tmp * x
}

Python

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

Java

class Solution {
    public double myPow(double x, long n) {
        if (n == 0) {
            return 1;
        }
        if (n == 1) {
            return x;
        }
        if (n < 0) {
            n = -n;
            x = 1 / x;
        }
        double tmp = myPow(x, n / 2);
        if (n % 2 == 0) {
            return tmp * tmp;
        }
        return tmp * tmp * x;
    }
}

Cpp

class Solution {
public:
    double myPow(double x, int n) {
        if (n == 0) {
            return 1.0;
        }
        if (n == 1) {
            return x;
        }
        long long absN = n; // 将 n 转换为 long long 类型
…};

Of course, let's go version by version and discuss the basics required:

Go version:

  1. Basic Go language knowledge : Before writing Go code, you need to understand the basic grammar, data types, variable declarations, function definitions and other basic knowledge of the Go language.

  2. Recursion : This algorithm uses recursion to compute power functions. It is important to understand the concept of recursion and how to write recursive functions in Go.

  3. Conditional Statementsif : Conditional statements ( and ) are used in the code if-elseto handle different situations such as the sign and parity of n.

Python version:

  1. Python language basics : You need to understand the basics of Python language, including variables, functions, conditional statements, recursion, etc.

  2. Recursion : Like the Go version, the Python version also uses recursion to calculate power functions. It is important to understand the concept of recursion and how to write recursive functions in Python.

Java version:

  1. Java language basics : You need to be familiar with the basics of the Java language, including class definitions, method declarations, conditional statements, etc.

  2. Recursion : Like the previous two versions, the Java version also uses recursion to calculate power functions. It is necessary to understand the concept of recursion and how to write recursive functions in Java.

  3. Data type conversion : The Java version performs data type conversion on n, converting int to long. Understanding the concept of data type conversion is very important when working with data.

C++ version:

  1. C++ language basics : You need to be familiar with the basic knowledge of the C++ language, including class definitions, function declarations, conditional statements, etc.

  2. Recursion : Like other versions, the C++ version also uses recursion to calculate power functions. It is necessary to understand the concept of recursion and how to write recursive functions in C++.

  3. Data type : The C++ version uses the long long data type to handle n to avoid integer overflow problems. It's important to understand C++'s data types and overflow issues.

These are the basics to master in each version. If you have more specific questions about any of these versions or need further explanation, please feel free to ask.

51. N-Queens

topic

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

Given an integern, return all distinct solutions to then-queens puzzle.

Each solution contains a distinct board configuration of then-queens’ placement, where'Q'and'.'both indicate a
queen and an empty space respectively.

Example:

Input: 4
Output: [
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
]
Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above.

The general idea of ​​the topic

Given an integer n, return all different solutions to the n-queens problem. Each solution contains an explicit chess placement scheme for the n-queens problem, where 'Q' and '.'
represent queens and vacancies respectively.

Problem-solving ideas

  • Solve the n-queens problem
  • Use the col array to record column information, col has ncolumns. Use dia1 and dia2 to record the information of the diagonal line from the lower left to the upper right and the diagonal line from the upper left to the lower right. Dia1 and dia2
    each have 2*n-1.
  • The rule of the diagonal of dia1 is i + j 是定值, for example, [0,0] is 0; [1,0], [0,1] is 1; [2,0], [1,1], [0,2] is 2;
  • The rule of dia2 diagonal is i - j 是定值, for example, [0,7] is -7; [0,6], [1,7] is -6; [0,5], [1,6], [2,7 ] is -5; in order for them to start at 0, i -
    j + n - 1 are offset to start at 0, so the law of dia2 is i - j + n - 1 为定值.

There is also a bit operation method. Each row can only choose one position to put the queen, then traverse the possible positions of the queen for each row. How to efficiently judge which points cannot be placed on the queen? The approach here is clever after all. It saves all the previously selected points in order, and then based on the distance from the previously selected point to the current row, you can quickly determine whether there is a conflict. For example:
If in the 4-queen problem, if the first and second rows have already selected positions [1, 3], then when selecting the third row, columns 1 and 3 cannot be selected first, and for the third row, The distance 1
has length 2, so it affects the -1, 3 columns. In the same way, 3 is in the second row, and the distance to the third row is 1, so 3 will affect columns 2 and 4. From the above results, we know that -1 and
4 are beyond the boundary and do not need to be taken care of. The other points that cannot be selected are 1, 2, and 3, so the third row can only select 0. In the code implementation, you can generate an occupied based on the previous selection before each traversal to
record the current row, the positions that have been selected and the positions that cannot be selected due to the previous queen's attack range, and then only select legal positions to enter. Go to the next level of recursion. In addition, a queen is preprocessed to place strings in different positions, so that these strings can be reused in memory when returning results, saving some memory.
Of course, let us introduce the problem-solving ideas of each version separately:

Go version problem-solving ideas:

  1. Recursive backtracking method : The Go
    version of the solution uses recursive backtracking. Starting from the first row, try to place a queen in each column of each row, then recurse to the next row. If a feasible queen position is found in a row, placement continues on the next row. If you can't find a suitable position, go back to the previous row and try other column positions until you find all possible solutions.

  2. Boolean arraycol : To ensure that queens do not attack each other, Boolean arrays , dia1and are used dia2
    to keep track of which columns and diagonals are occupied. The indexes of these arrays represent column and diagonal numbers, with values ​​of trueindicating occupied and values false​​indicating available.

  3. Generate the board : After finding a solution, use generateBoardthe function to generate the board, mark the queen position as 'Q', and add the board to the result.

Python version problem-solving ideas:

  1. Recursive backtracking : The Python version also uses recursive backtracking, which
    is similar to the Go version. Starting from the first row, try to place a queen in each column of each row, then recurse to the next row. If a feasible queen position is found in a row, placement continues on the next row. If you can't find a suitable position, go back to the previous row and try other column positions until you find all possible solutions.

  2. Boolean Listcol : To ensure that queens do not attack each other, Boolean lists , dia1and are used dia2
    to keep track of which columns and diagonals are occupied. The indexes of these lists represent column and diagonal numbers, with values ​​of Trueindicating occupied and values False​​indicating available.

  3. Generate the board : After finding a solution, use generateBoardthe function to generate the board, mark the queen position as 'Q', and add the board to the result.

Java version solution ideas:

  1. Recursive backtracking method : The Java
    version of the solution also uses recursive backtracking. Starting from the first row, try to place a queen in each column of each row, then recurse to the next row. If a feasible queen position is found in a row, placement continues on the next row. If you can't find a suitable position, go back to the previous row and try other column positions until you find all possible solutions.

  2. Boolean arraycol : To ensure that queens do not attack each other, Boolean arrays , dia1and are used dia2
    to keep track of which columns and diagonals are occupied. The indexes of these arrays represent column and diagonal numbers, with values ​​of trueindicating occupied and values false​​indicating available.

  3. Generate the board : After finding a solution, use generateBoardthe function to generate the board, mark the queen position as 'Q', and add the board to the result.

C++ version problem-solving ideas:

  1. Recursive backtracking : The C++
    version also uses recursive backtracking, which is similar to other versions. Starting from the first row, try to place a queen in each column of each row, then recurse to the next row. If a feasible queen position is found in a row, placement continues on the next row. If you can't find a suitable position, go back to the previous row and try other column positions until you find all possible solutions.

  2. Boolean vectorscol : To ensure that queens do not attack each other, Boolean vectors , dia1and are used dia2
    to keep track of which columns and diagonals are occupied. The indices of these vectors represent column and diagonal numbers, with values true​​of being occupied and values false​​being available.

  3. Generate the board : After finding a solution, use generateBoardthe function to generate the board, mark the queen position as 'Q', and add the board to the result.

The core of these problem-solving ideas are to use recursive backtracking to try different ways of placing queens, and to use Boolean arrays/lists/vectors to track which positions are occupied to ensure that the queens do not attack each other. At the same time, string processing is used to generate and represent the chessboard.

code

Go

// 解法一 DFS
func solveNQueens(n int) [][]string {
    col, dia1, dia2, row, res := make([]bool, n), make([]bool, 2*n-1), make([]bool, 2*n-1), []int{}, [][]string{}
    putQueen(n, 0, &col, &dia1, &dia2, &row, &res) // 调用putQueen函数来找到解
    return res
}

// 尝试在一个n皇后问题中, 摆放第index行的皇后位置
func putQueen(n, index int, col, dia1, dia2 *[]bool, row *[]int, res *[][]string) {
    if index == n { // 所有皇后都已经成功摆放,得到一个解
        *res = append(*res, generateBoard(n, row)) // 生成棋盘并添加到结果集中
        return
    }
    for i := 0; i < n; i++ {
        // 尝试将第index行的皇后摆放在第i列
        if !(*col)[i] && !(*dia1)[index+i] && !(*dia2)[index-i+n-1] {
            *row = append(*row, i)          // 在当前行的row中记录皇后位置
            (*col)[i] = true                // 在列col中标记为占用
            (*dia1)[index+i] = true         // 在对角线dia1中标记为占用
            (*dia2)[index-i+n-1] = true     // 在对角线dia2中标记为占用
            putQueen(n, index+1, col, dia1, dia2, row, res) // 递归下一行
            (*col)[i] = false               // 回溯:取消占用
            (*dia1)[index+i] = false        // 回溯:取消占用
            (*dia2)[index-i+n-1] = false    // 回溯:取消占用
            *row = (*row)[:len(*row)-1]    // 回溯:移除上一行的皇后位置
        }
    }
    return
}

// 生成一个N皇后问题的棋盘
func generateBoard(n int, row *[]int) []string {
    board := []string{}
    res := ""
    for i := 0; i < n; i++ {
        res += "."
    }
    for i := 0; i < n; i++ {
        board = append(board, res) // 初始化棋盘为全"."
    }
    for i := 0; i < n; i++ {
        tmp := []byte(board[i])    // 将当前行转换为字节切片以修改皇后位置
        tmp[(*row)[i]] = 'Q'        // 在皇后位置处添加"Q"表示皇后
        board[i] = string(tmp)
    }
    return board // 返回表示棋盘的字符串切片
}

Python

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        result = []
        col = [False] * n
        dia1 = [False] * (2 * n - 1)
        dia2 = [False] * (2 * n - 1)
        row = [0] * n
        self.putQueen(n, 0, col, dia1, dia2, row, result)
        return result

    def putQueen(self, n, index, col, dia1, dia2, row, result):
        if index == n:
            result.append(self.generateBoard(n, row))
            return
        for i in range(n):
            if not col[i] and not dia1[index + i] and not dia2[index - i + n - 1]:
                row[index] = i
                col[i] = True
                dia1[index + i] = True
                dia2[index - i + n - 1] = True
                self.putQueen(n, index + 1, col, dia1, dia2, row, result)
                col[i] = False
                dia1[index + i] = False
                dia2[index - i + n - 1] = False

    def generateBoard(self, n, row):
        board = []
        for i in range(n):
            row_str = ['.' for _ in range(n)]
            row_str[row[i]] = 'Q'
            board.append(''.join(row_str))
        return board

Java

import java.util.ArrayList;
import java.util.List;

class Solution {
    public List<List<String>> solveNQueens(int n) {
        List<List<String>> result = new ArrayList<>();
        boolean[] col = new boolean[n];
        boolean[] dia1 = new boolean[2 * n - 1];
        boolean[] dia2 = new boolean[2 * n - 1];
        int[] row = new int[n];
        putQueen(n, 0, col, dia1, dia2, row, result);
        return result;
    }

    private void putQueen(int n, int index, boolean[] col, boolean[] dia1, boolean[] dia2, int[] row, List<List<String>> result) {
        if (index == n) {
            result.add(generateBoard(n, row));
            return;
        }
        for (int i = 0; i < n; i++) {
            if (!col[i] && !dia1[index + i] && !dia2[index - i + n - 1]) {
                row[index] = i;
                col[i] = true;
                dia1[index + i] = true;
                dia2[index - i + n - 1] = true;
                putQueen(n, index + 1, col, dia1, dia2, row, result);
                col[i] = false;
                dia1[index + i] = false;
                dia2[index - i + n - 1] = false;
            }
        }
    }

    private List<String> generateBoard(int n, int[] row) {
        List<String> board = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            sb.append('.');
        }
        for (int i = 0; i < n; i++) {
            char[] chars = sb.toString().toCharArray();
            chars[row[i]] = 'Q';
            board.add(new String(chars));
        }
        return board;
    }
}

Cpp

class Solution {
public:
    vector<vector<string>> solveNQueens(int n) {
        vector<vector<string>> result;
        vector<bool> col(n, false);
        vector<bool> dia1(2 * n - 1, false);
        vector<bool> dia2(2 * n - 1, false);
        vector<int> row(n, 0);
        putQueen(n, 0, col, dia1, dia2, row, result);
        return result;
    }

    void putQueen(int n, int index, vector<bool>& col, vector<bool>& dia1, vector<bool>& dia2, vector<int>& row, vector<vector<string>>& result) {
        if (index == n) {
            result.push_back(generateBoard(n, row));
            return;
        }
        for (int i = 0; i < n; i++) {
            if (!col[i] && !dia1[index + i] && !dia2[index - i + n - 1]) {
                row[index] = i;
                col[i] = true;
                dia1[index + i] = true;
                dia2[index - i + n - 1] = true;
                putQueen(n, index + 1, col, dia1, dia2, row, result);
                col[i] = false;
                dia1[index + i] = false;
                dia2[index - i + n - 1] = false;
            }
        }
    }

    vector<string> generateBoard(int n, vector<int>& row) {
        vector<string> board(n, string(n, '.'));
        for (int i = 0; i < n; i++) {
            board[i][row[i]] = 'Q';
        }
        return board;
    }
};

Of course, let's cover the basics required in each version of the code:

Go version:

  1. Slices : Go uses slices to handle dynamic arrays. In the code, use []stringrepresents a string slice that stores the position of each queen.

  2. Recursion : The key to solving the N-Queens problem is recursion. The code uses recursion to try to place a queen in each row while backtracking to find all possible solutions.

  3. Boolean Arrays : Use Boolean arrays to keep track of which columns and diagonals are occupied to ensure queens don't attack each other.

Python version:

  1. Lists : Python uses lists to handle dynamic arrays, similar to slices in Go. In the code, use List[List[str]]
    represents a list of strings used to store different solutions to the chessboard.

  2. Recursion : Similar to the Go version, the Python version also uses recursion to try to place the queen in each row and backtrack.

  3. Boolean Lists : Python uses Boolean lists to keep track of which columns and diagonals are occupied to ensure that queens don't attack each other.

  4. List Comprehension : When generating a chessboard, use list comprehension to convert a list of strings into a string containing the queen's position.

Java version:

  1. ArrayList : Used in Java ArrayListto handle dynamic arrays, similar to Go's slices and Python
    's lists. In code, use List<List<String>>a list to represent a list of strings.

  2. Recursion : Similar to the Go and Python versions, the Java version also uses recursion to try to place the queen in each row and backtrack.

  3. Boolean Arrays : Java uses Boolean arrays to keep track of which columns and diagonals are occupied to ensure that queens do not attack each other.

  4. String handling : Java uses StringBuilderto handle mutability of strings in order to place queens on the chessboard.

C++ version:

  1. Vectors : C++ uses vectors to handle dynamic arrays, similar to Go's slices, Python's lists, and Java's
    ArrayList. In code, use vector<vector<string>>a vector that represents a vector of strings.

  2. Recursion : Similar to the other versions, the C++ version also uses recursion to try to place the queen in each row and backtrack.

  3. Boolean Vectors : C++ uses Boolean vectors to keep track of which columns and diagonals are occupied to ensure that queens don't attack each other.

  4. String handling : C++ uses string vectors and character arrays to represent and manipulate the chessboard, adding queen positions to the appropriate positions.

These basics include slicing, lists, recursion, Boolean arrays/lists, string processing, etc., and are
key elements in understanding and writing solutions to N-Queens problems. If you have more specific questions about any of these concepts, or need a more in-depth explanation, please feel free to ask.

52. N-Queens II

topic

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

Given an integer n, return the number of distinct solutions to the n-queens puzzle.

Example:

Input: 4
Output: 2
Explanation: There are two distinct solutions to the 4-queens puzzle as shown below.
[
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
]

The general idea of ​​the topic

Given an integer n, return n queens the number of distinct solutions.

Problem-solving ideas

  • This question is an enhanced version of question 51. Based on question 51, just add up and record the number of solutions.
  • This question can also be solved using a violent table method, and the time complexity is O(1).

Of course, let us introduce the problem-solving ideas of each version separately:

Go version of problem-solving ideas

The Go version of the solution uses depth-first search (DFS) and backtracking to solve the N-queens problem. The following are the key steps in solving the problem:

  1. Create and initialize a boolean array that records whether the columns and two diagonals are occupied, an integer slice that records the position of the queen in each row, and the resulting variable.

  2. Starting from the first row, recursively tries to place a queen on each row until the last row is reached. Every time you place a queen, you need to check whether the current column and the two diagonals are occupied.

  3. If a queen can be placed in a row, the queen position is recorded in the integer slice, and the column and diagonal occupancy is updated.

  4. Continue recursing to the next line and repeat the same process.

  5. When all rows have been placed, the count is incremented by 1, indicating that a solution has been found.

  6. Go back to the previous row, undo the queen placement in the current row, and continue trying the next column.

  7. Repeat the above steps until all solutions are found.

Python version of problem-solving ideas

The Python version of the solution also uses depth-first search (DFS) and backtracking to solve the N-queens problem. The problem-solving idea is basically the same as the Go version:

  1. Create and initialize a Boolean array that records whether the column, two diagonals are occupied, and an integer slice that records the position of the queen in each row.

  2. Starting from the first row, recursively tries to place a queen on each row until the last row is reached. Every time you place a queen, you need to check whether the current column and the two diagonals are occupied.

  3. If a queen can be placed in a row, the queen position is recorded in the integer slice, and the column and diagonal occupancy is updated.

  4. Continue recursing to the next line and repeat the same process.

  5. When all rows have been placed, the count is incremented by 1, indicating that a solution has been found.

  6. Go back to the previous row, undo the queen placement in the current row, and continue trying the next column.

  7. Repeat the above steps until all solutions are found.

Java version of problem-solving ideas

The Java version of the solution also uses depth-first search (DFS) and backtracking to solve the N-queens problem. The problem-solving ideas are as follows:

  1. Create and initialize a boolean array that records whether the column and two diagonals are occupied, and an integer array that records the position of the queen of each row.

  2. Starting from the first row, recursively tries to place a queen on each row until the last row is reached. Every time you place a queen, you need to check whether the current column and the two diagonals are occupied.

  3. If a queen can be placed in a row, the queen's position is recorded in the integer array, and the column and diagonal occupancy is updated.

  4. Continue recursing to the next line and repeat the same process.

  5. When all rows have been placed, the count is incremented by 1, indicating that a solution has been found.

  6. Go back to the previous row, undo the queen placement in the current row, and continue trying the next column.

  7. Repeat the above steps until all solutions are found.

C++ version of problem-solving ideas

The C++ version of the solution also uses depth-first search (DFS) and backtracking to solve the N-queens problem. The following are the key steps in solving the problem:

  1. Use bitwise operations to efficiently record whether a column, two diagonals are occupied. Among them, the column is represented by an integer, and each bit indicates whether a column is occupied; the two diagonals are also represented by integers respectively.

  2. Starting from the first row, recursively try to place a queen on each row until the last row is reached. In each row, bit operations are used to check whether the current column and two diagonals are occupied.

  3. If a queen can be placed in a row, use bitwise operations to mark the queen position as occupied, and continue recursing to the next row.

  4. When all rows have been placed, the count is incremented by 1, indicating that a solution has been found.

  5. Go back to the previous row, undo the queen placement in the current row, and continue trying the next column.

  6. Repeat the above steps until all solutions are found.

In general, these versions of problem-solving ideas involve depth-first search and backtracking, while using different data structures and language features to implement the same algorithm. Understanding recursion, backtracking, and bitwise operations is important to understanding these solutions.

code

Go

// 解法二,DFS 回溯法
func totalNQueens(n int) int {
    // 创建并初始化用于记录列、两个对角线是否被占用的布尔数组,
    // 以及记录每行皇后位置的数组,以及结果的变量
    col, dia1, dia2, row, res := make([]bool, n), make([]bool, 2*n-1), make([]bool, 2*n-1), []int{}, 0
    // 调用递归函数放置皇后并计算结果
    putQueen52(n, 0, &col, &dia1, &dia2, &row, &res)
    // 返回结果
    return res
}

// 尝试在一个n皇后问题中, 摆放第index行的皇后位置
func putQueen52(n, index int, col, dia1, dia2 *[]bool, row *[]int, res *int) {
    // 当摆放完成所有行时,计数结果加1
    if index == n {
        *res++
        return
    }

    // 遍历当前行的每一列,尝试放置皇后
    for i := 0; i < n; i++ {
        // 检查当前列、两个对角线是否被占用
        if !(*col)[i] && !(*dia1)[index+i] && !(*dia2)[index-i+n-1] {
            // 如果没有被占用,将皇后放置在当前位置
            (*row) = append((*row), i)
            (*col)[i] = true
            (*dia1)[index+i] = true
            (*dia2)[index-i+n-1] = true
            // 递归放置下一行的皇后
            putQueen52(n, index+1, col, dia1, dia2, row, res)
            // 回溯,撤销当前行的皇后放置,继续尝试下一列
            (*col)[i] = false
            (*dia1)[index+i] = false
            (*dia2)[index-i+n-1] = false
            (*row) = (*row)[:len(*row)-1]
        }
    }
    return
}

Python

class Solution:
    def totalNQueens(self, n: int) -> int:
        # 计算可以放置皇后的列的位掩码,limit 为一个 n 位的二进制数,所有位都为 1
        limit = (1 << n) - 1
        # 调用 process 函数,初始时传入全0的状态,表示没有皇后被放置
        return self.process(limit, 0, 0, 0)

    def process(self, limit, colLim, leftDiaLim, rightDiaLim):
        # 如果所有列都已经放置了皇后,表示找到了一种解法,返回 1
        if colLim == limit:
            return 1

        mostRight = 0
        # 计算当前行可以放置皇后的位置,pos 为一个二进制数,1 表示可以放置皇后的位置
        pos = limit & (~(colLim | leftDiaLim | rightDiaLim))
        res = 0
        while pos != 0:
            # 取出最右边的 1,表示在该位置放置皇后
            mostRight = pos & (~pos + 1)
            pos = pos - mostRight
            # 递归调用 process 函数,放置下一行的皇后,并累加解的数量
            res += self.process(limit, colLim | mostRight, (leftDiaLim | mostRight) << 1, (rightDiaLim | mostRight) >> 1)
        # 返回总解的数量
        return res

Java

class Solution {
    public int totalNQueens(int n) {
        boolean[] col = new boolean[n];
        boolean[] dia1 = new boolean[2 * n - 1];
        boolean[] dia2 = new boolean[2 * n - 1];
        int[] row = new int[n];
        int[] res = new int[1];
        putQueen(n, 0, col, dia1, dia2, row, res);
        return res[0];
    }

    private void putQueen(int n, int index, boolean[] col, boolean[] dia1, boolean[] dia2, int[] row, int[] res) {
        if (index == n) {
            res[0]++;
            return;
        }

        for (int i = 0; i < n; i++) {
            if (!col[i] && !dia1[index + i] && !dia2[index - i + n - 1]) {
                row[index] = i;
                col[i] = true;
                dia1[index + i] = true;
                dia2[index - i + n - 1] = true;
                putQueen(n, index + 1, col, dia1, dia2, row, res);
                col[i] = false;
                dia1[index + i] = false;
                dia2[index - i + n - 1] = false;
            }
        }
    }
}

Cpp

class Solution {
public:
    int totalNQueens(int n) {
        // 调用 solve 函数,初始时传入全0的状态,表示没有皇后被放置
        return solve(n, 0, 0, 0, 0);
    }

    int solve(int n, int row, int columns, int diagonals1, int diagonals2) {
        // 如果已经放置了 n 个皇后,表示找到了一种解法,返回 1
        if (row == n) {
            return 1;
        } else {
            int count = 0;
            // 计算当前行可用的位置,通过位运算得到一个二进制数,1 表示可以放置皇后的位置
            int availablePositions = ((1 << n) - 1) & (~(columns | diagonals1 | diagonals2));
            
            // 遍历所有可用的位置
            while (availablePositions != 0) {
                // 取出最低位的 1,表示在该位置放置皇后
                int position = availablePositions & (-availablePositions);
                // 将该位置从可用位置中移除
                availablePositions = availablePositions & (availablePositions - 1);
                // 递归调用 solve 函数,放置下一行的皇后,并累加解的数量
                count += solve(n, row + 1, columns | position, (diagonals1 | position) << 1, (diagonals2 | position) >> 1);
            }
            // 返回总解的数量
            return count;
        }
    }
};

Of course, let's cover each version of the code separately and the basics they require:

Go version

The Go version of the code is a solution using depth-first search (DFS) and backtracking to solve the N-queens problem. Here are the basics involved in the code:

  1. Arrays and Slices : Arrays and slices in Go are important data structures used to store and process data. In this problem, multiple boolean arrays are used to keep track of occupied columns and diagonals, and an integer slice is used to record the queen position of each row.

  2. Recursion and backtracking : This solution uses recursion to try to place the queen, and backtracking to undo infeasible solutions. Recursion is the key to solving the N-queens problem.

  3. Bitwise operations : Bitwise operations are used to quickly check if columns, diagonals are occupied, and where to place the queen. This is a key part of the algorithm.

Python version

The Python version of the code is also a solution using depth-first search (DFS) and backtracking. Here are the basics involved in the code:

  1. Recursion and backtracking : Like the Go version, the Python version also uses recursion to try to place the queen, and backtracking to undo unfeasible solutions. Recursion is the key to solving the N-queens problem.

  2. Bitwise operations : Bitwise operations are used to quickly check if columns, diagonals are occupied, and where to place the queen. This is a key part of the algorithm.

Java version

The Java version of the code is also a solution using depth-first search (DFS) and backtracking. Here are the basics involved in the code:

  1. Arrays and Lists : Arrays and lists (ArrayList) in Java are used to store and process data. In this problem, multiple boolean arrays are used to keep track of occupied columns and diagonals, and an integer array is used to record the queen position of each row.

  2. Recursion and backtracking : This solution uses recursion to try to place the queen, and backtracking to undo infeasible solutions. Recursion is the key to solving the N-queens problem.

C++ version

The C++ version of the code is also a solution using depth-first search (DFS) and backtracking. Here are the basics involved in the code:

  1. Bit operations : Bit operations are used in the C++ version to quickly check if columns, diagonals are occupied, and where to place the queen. This is a key part of the algorithm.

  2. Recursion and backtracking : This solution uses recursion to try to place the queen, and backtracking to undo infeasible solutions. Recursion is the key to solving the N-queens problem.

In summary, regardless of the programming language used, the key concepts for solving the N-Queens problem include recursion, backtracking, and bitwise operations. Understanding these concepts will help in understanding and implementing these codes.

53. Maximum Subarray

topic

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

Example:

Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

Follow up:

If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

The general idea of ​​the topic

Given an integer array nums, find a contiguous subarray with the maximum sum (the subarray contains at least one element) and return its maximum sum.

Problem-solving ideas

  • This problem can be solved using DP or not.
  • The question requires outputting the value with the largest sum of numbers in a certain interval in the array. dp[i]Represents [0,i]the maximum value of the sum of each sub-interval in the interval, and the state transition equation is dp[i] = nums[i] + dp[i-1] (dp[i-1] > 0), dp[i] = nums[i] (dp[i-1] ≤ 0).
    Go version:
  1. Define the maxSubArray function, the parameter is nums slice.
  2. Define tmp and m variables to represent the sum of the current subarray and the sum of the largest subarray respectively. m is initialized to nums[0].
  3. Traverse nums and accumulate the current element with tmp.
  4. Compare m and tmp, and assign the larger value to m through the max function.
  5. If tmp<0, assign tmp to 0 through the max function.
  6. Return m after the loop ends.

Python version:

  1. Define the maxSubArray function, the parameter is a list of nums.
  2. Define tmp and m variables to represent the sum of the current subarray and the sum of the largest subarray respectively. m is initialized to nums[0].
  3. Traverse nums and accumulate the current element with tmp.
  4. Compare m and tmp, and assign the larger value to m through the built-in max function.
  5. If tmp<0, assign tmp to 0 through the max function.
  6. Return m after the loop ends.

Java version:

  1. Define the maxSubArray method, the parameter is the nums array.
  2. Define tmp and m variables to represent the sum of the current subarray and the sum of the largest subarray respectively. m is initialized to nums[0].
  3. Traverse nums and accumulate the current element with tmp.
  4. Compare m and tmp, and assign the larger value to m through Math.max.
  5. If tmp<0, assign tmp to 0 through Math.max.
  6. Return m after the loop ends.

C++ version:

  1. Define the maxSubArray method, the parameter is the nums vector.
  2. Define tmp and m variables to represent the sum of the current subarray and the sum of the largest subarray respectively. m is initialized to nums[0].
  3. Traverse nums and accumulate the current element with tmp.
  4. Compare m and tmp, and assign the larger value to m through the max method.
  5. If tmp<0, assign tmp to 0 through the max method.
  6. Return m after the loop ends.

The core ideas are the same, the main difference lies in the grammatical details and the use of local language characteristics for optimization.

code

Go

// 定义一个名为 maxSubArray 的函数,接受一个整数数组 nums 作为参数,返回最大子数组和。
func maxSubArray(nums []int) int {
    // 如果数组为空,直接返回 0。
    if len(nums) == 0 {
        return 0
    }
    // 初始化一个临时变量 tmp 和最大子数组和 m,初始值为数组的第一个元素。
    var tmp = 0
    var m = nums[0]
    // 遍历整个数组。
    for i := 0; i < len(nums); i++ {
        // 更新临时变量 tmp,将当前元素加入其中。
        tmp += nums[i]
        // 更新最大子数组和 m,取当前的 m 和 tmp 的较大值。
        m = max(m, tmp)
        // 如果 tmp 小于 0,将 tmp 重置为 0,因为负数不会对最大子数组和产生正面影响。
        tmp = max(tmp, 0)
    }
    // 返回最大子数组和 m。
    return m
}

// 定义一个名为 max 的辅助函数,接受两个整数参数 a 和 b,返回较大的整数。
func max(a, b int) int {
    // 如果 a 大于 b,返回 a,否则返回 b。
    if a > b {
        return a
    }
    return b
}

Python

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        # 如果数组为空,直接返回0。
        if not nums:
            return 0
        # 初始化一个临时变量 tmp 和最大子数组和 m,初始值为数组的第一个元素。
        tmp = 0
        m = nums[0]
        # 遍历整个数组。
        for num in nums:
            # 更新临时变量 tmp,将当前元素加入其中。
            tmp += num
            # 更新最大子数组和 m,取当前的 m 和 tmp 的较大值。
            m = max(m, tmp)
            # 如果 tmp 小于 0,将 tmp 重置为 0,因为负数不会对最大子数组和产生正面影响。
            tmp = max(tmp, 0)
        # 返回最大子数组和 m。
        return m

Java

class Solution {
    public int maxSubArray(int[] nums) {
        // 如果数组为空,直接返回0。
        if (nums.length == 0) {
            return 0;
        }
        // 初始化一个临时变量 tmp 和最大子数组和 m,初始值为数组的第一个元素。
        int tmp = 0;
        int m = nums[0];
        // 遍历整个数组。
        for (int i = 0; i < nums.length; i++) {
            // 更新临时变量 tmp,将当前元素加入其中。
            tmp += nums[i];
            // 更新最大子数组和 m,取当前的 m 和 tmp 的较大值。
            m = Math.max(m, tmp);
            // 如果 tmp 小于 0,将 tmp 重置为 0,因为负数不会对最大子数组和产生正面影响。
            tmp = Math.max(tmp, 0);
        }
        // 返回最大子数组和 m。
        return m;
    }
}

Cpp

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        // 如果数组为空,直接返回0。
        if (nums.empty()) {
            return 0;
        }
        // 初始化一个临时变量 tmp 和最大子数组和 m,初始值为数组的第一个元素。
        int tmp = 0;
        int m = nums[0];
        // 遍历整个数组。
        for (int num : nums) {
            // 更新临时变量 tmp,将当前元素加入其中。
            tmp += num;
            // 更新最大子数组和 m,取当前的 m 和 tmp 的较大值。
            m = max(m, tmp);
            // 如果 tmp 小于 0,将 tmp 重置为 0,因为负数不会对最大子数组和产生正面影响。
            tmp = max(tmp, 0);
        }
        // 返回最大子数组和 m。
        return m;
    }
};

basic knowledge

For the Go version:

  • Function definition: In the Go language, the func keyword is used to define a function, the parameter list in parentheses, and the function body in curly braces.
  • Return value: Go function can only return a value, using the return statement.
  • Slicing operation: nums[]int defines an int slice, len(nums) gets the slice length, and nums[i] accesses the slice elements.
  • if conditional judgment: if a > b {} else {}.
  • for循环:for i := 0; i < len(nums); i++ {}。
  • Variable definition: var tmp int defines temporary variables.
  • Get the maximum value: call the max function to compare the sizes of a and b and return the larger value.

For Python version:

  • Function definition: Use def to define a function, and self in the parameter list represents an intra-class method.
  • Return value: Use the return statement to return a value.
  • List operations: nums is used as a list parameter, len(nums) gets the length, and num traverses the list elements.
  • If conditional judgment: if not nums: judge the empty list.
  • Get the maximum value: Call the built-in max function to compare two values.

For Java version:

  • Method definition: public type describes method access permissions, int return value type.
  • Array operations: nums.length gets the length of the array, nums[i] accesses the elements.
  • if conditional judgment: if(nums.length == 0).
  • for loop: for (initialization; condition; iteration).
  • Get the maximum value: Math.max(a, b) calls the tool class method.

For the C++ version:

  • Method definition: defined in class, int return type.
  • Vector operation: nums is used as a vector parameter, empty() determines empty, and num is traversed.
  • if conditional judgment: if(nums.empty()).
  • for loop: for (element type element: container).
  • Get the maximum value: call the max method to compare two values.
    The main ones are function/method definition, operation of basic data structures, use of process control language (if/for), and numerical comparison to obtain the maximum value. Once you master these basic syntaxes, you can write algorithm code.

54. Spiral Matrix

topic

Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.

Example 1:

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

Example 2:

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

The general idea of ​​the topic

Given a matrix containing mxn elements (m rows, n columns), return all elements in the matrix in clockwise spiral order.

Problem-solving ideas

  • Given a two-dimensional array, output it in a spiral fashion
  • Solution 1: What needs to be paid attention to are special cases, such as a two-dimensional array degenerating into one dimension or one column or one element. After paying attention to these situations, you can basically pass it in one go.
  • Solution 2: Calculate the total number of elements in advance and traverse the matrix circle by circle. The stopping condition is that all elements have been traversed (count == sum)
    Go version:
  1. Define the direction vector array spDir, which represents the direction to the right, down, left, and up.
  2. Use the visit matrix to mark visited locations
  3. Determine the direction based on the round variable and initialize it to the right
  4. Traverse the matrix and update the coordinates according to the direction vector each time
  5. Determine whether the corner has been reached, if so, the round will increment and change direction.
  6. Determine whether the coordinates are out of bounds
  7. Determine whether the location has been visited. If not, mark it and add it to the results.
  8. Determine whether the surrounding area has been visited based on the current direction, and if so, change the direction.

Python version:

  1. Define the left and right upper and lower boundaries to indicate the current traversed range
  2. Implement spiral traversal by constantly changing boundary coordinates
  3. Traverse the upper boundary from left to right, then move the upper boundary down
  4. Traverse the right border from top to bottom, then move the right border left
  5. Determine whether the boundaries meet. If they meet, it ends.
  6. Traverse the lower border from right to left, then move the lower border up
  7. Traverse the left border from bottom to top, then move the left border to the right

Java version:

  1. Define dr and dc arrays to represent four directions
  2. Use visited array to mark visited locations
  3. The di variable controls the direction. It increases and changes the direction after each traversal.
  4. Calculate the next traversal position based on the direction array
  5. If the next location is legal and has not been visited, move the coordinates
  6. Otherwise, change di and continue traversing

C++ version:

  1. Define direction arrays dr, dc
  2. Use visited vector to mark visited locations
  3. The di variable controls the direction. When turning a corner, it increases di to change the direction.
  4. Calculate the next traversal position based on dr and dc
  5. If legal and not visited, move the coordinates
  6. Otherwise, change the direction and continue traversing

code

Go

// 定义一个螺旋遍历二维矩阵的函数
func spiralOrder(matrix [][]int) []int {
    // 如果矩阵为空,直接返回空切片
    if len(matrix) == 0 { 
       return []int{}
    }
    // 定义一个结果切片
    res := []int{}
    // 如果矩阵只有一行,直接遍历添加到结果切片
    if len(matrix) == 1 {
       for i := 0; i < len(matrix[0]); i++ {
          res = append(res, matrix[0][i])
       }
       return res
    }
    // 如果矩阵只有一列,直接遍历添加到结果切片   
    if len(matrix[0]) == 1 {
       for i := 0; i < len(matrix); i++ {
          res = append(res, matrix[i][0])
       }
       return res
    }
    // 定义一个访问矩阵,标记已访问过的元素
    visit, m, n, round, x, y, spDir := make([][]int, len(matrix)), len(matrix), len(matrix[0]), 0, 0, 0, [][]int{
       []int{0, 1},  // 向右的方向向量
       []int{1, 0},  // 向下的方向向量
       []int{0, -1}, // 向左的方向向量
       []int{-1, 0}, // 向上的方向向量
    }
    // 初始化访问矩阵
    for i := 0; i < m; i++ {
       visit[i] = make([]int, n)
    }
    // 标记当前位置为已访问
    visit[x][y] = 1
    // 将当前位置元素添加到结果切片
    res = append(res, matrix[x][y])
    // 开始遍历矩阵
    for i := 0; i < m*n; i++ {
       // 根据当前方向向量更新x、y坐标 
       x += spDir[round%4][0] 
       y += spDir[round%4][1]
       // 如果遍历到转角,改变方向
       if (x == 0 && y == n-1) || (x == m-1 && y == n-1) || (y == 0 && x == m-1) {
          round++
       }
       // 检查坐标是否出界
       if x > m-1 || y > n-1 || x < 0 || y < 0 {
          return res
       }
       // 如果当前位置未访问过
       if visit[x][y] == 0 {
          // 标记为已访问
          visit[x][y] = 1
          // 添加到结果切片 
          res = append(res, matrix[x][y])
       }
       // 根据当前方向判断是否需要改变方向
       switch round % 4 {
       case 0: // 向右
          if y+1 <= n-1 && visit[x][y+1] == 1 { // 右侧已访问过
             round++ // 改变方向
             continue
          }
       case 1: // 向下
          if x+1 <= m-1 && visit[x+1][y] == 1 { // 下方已访问过
             round++
             continue
          } 
       case 2: // 向左
          if y-1 >= 0 && visit[x][y-1] == 1 { // 左侧已访问过
             round++
             continue
          }
       case 3: // 向上
          if x-1 >= 0 && visit[x-1][y] == 1 { // 上方已访问过
             round++
             continue
          }
       }
    }
    // 返回结果切片
    return res
}

Python

python
class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        # 定义左、上边界
        left, top = 0, 0 
        # 定义右、下边界  
        bottom, right = len(matrix), len(matrix[0])

        # 结果列表
        ans = []

        # 当左右边界未相遇,上下边界未相遇时
        while left < right and top < bottom:
            
            # 从左到右遍历上边界  
            for i in range(left, right):
                ans.append(matrix[top][i])
            # 上边界下移
            top += 1

            # 从上到下遍历右边界
            for i in range(top, bottom):
                ans.append(matrix[i][right - 1])
            # 右边界左移
            right -= 1

            # 如果边界相遇,结束循环
            if left >= right or top >= bottom:
                break

            # 从右到左遍历下边界
            for i in range(right - 1, left - 1, -1):
                ans.append(matrix[bottom - 1][i])
            # 下边界上移
            bottom -= 1

            # 从下到上遍历左边界
            for i in range(bottom - 1, top - 1, -1):
                ans.append(matrix[i][left])
            # 左边界右移
            left += 1

        return ans

Java


import java.util.ArrayList; 
import java.util.List;

class Solution {
  public List<Integer> spiralOrder(int[][] matrix) {
    
    List<Integer> res = new ArrayList<>();
    
    if(matrix.length == 0) return res;
    
    int m = matrix.length;
    int n = matrix[0].length;
    
    boolean[][] visited = new boolean[m][n];
    
    int[] dr = {0, 1, 0, -1}; // 右、下、左、上 
    int[] dc = {1, 0, -1, 0};
    
    int r = 0, c = 0, di = 0;
    
    for(int i = 0; i < m * n; i++) {
      
      res.add(matrix[r][c]);
      visited[r][c] = true;
      
      int cr = r + dr[di];
      int cc = c + dc[di];
      
      if(0 <= cr && cr < m && 0 <= cc && cc < n && !visited[cr][cc]) {
        r = cr;
        c = cc; 
      }
      else {
        di = (di + 1) % 4; // 改变方向
        r += dr[di]; 
        c += dc[di];
      }
    }
    
    return res;

  }
}

Cpp

#include <vector>

using namespace std;

class Solution {
public:
  vector<int> spiralOrder(vector<vector<int>>& matrix) {

    vector<int> res;
    if (matrix.empty()) return res;

    int m = matrix.size(), n = matrix[0].size();
    vector<vector<bool>> visited(m, vector<bool>(n));

    int dr[4] = {0, 1, 0, -1}; // 右、下、左、上
    int dc[4] = {1, 0, -1, 0};  

    int r = 0, c = 0, di = 0;

    for (int i = 0; i < m * n; i++) {

      res.push_back(matrix[r][c]);
      visited[r][c] = true;

      int cr = r + dr[di], cc = c + dc[di];

      if (0 <= cr && cr < m && 0 <= cc && cc < n && !visited[cr][cc]) {
        r = cr; c = cc;
      }  
      else {
        di = (di + 1) % 4; // 改变方向
        r += dr[di]; c += dc[di]; 
      }
    }

    return res;

  }
};

basic knowledge

  1. Go version
  • Use the direction vector to control the traversal order, and control the direction according to the round variable
  • Use visit matrix to record visited locations to avoid repeated visits
  • Pay attention to handling boundary conditions, such as the case where the matrix has only one row or column
  1. Python version
  • Use left, right, upper and lower boundaries to control the traversal range
  • Implement spiral traversal by changing boundary coordinates
  • Pay attention to handling boundary encounter situations
  1. Java version
  • Use direction arrays dr and dc to control the traversal direction
  • visited array records visited locations
  • Change the di control direction. When turning the corner, di will increase automatically to achieve the direction change.
  1. C++ version
  • Similar to the Java version, use the direction arrays dr, dc
  • visited vector records visited locations
  • Changing di changes the direction, and increases di when turning a corner.

In summary, the spiral traversal matrix needs to pay attention to boundary processing and realize the spiral traversal sequence by controlling the direction. It is important to record visited locations to avoid repeated visits.

55. Jump Game

topic

Given an array of non-negative integers, you are initially positioned at the first index of the array.

Each element in the array represents your maximum jump length at that position.

Determine if you are able to reach the last index.

Example 1:

Input: [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.

Example 2:

Input: [3,2,1,0,4]
Output: false
Explanation: You will always arrive at index 3 no matter what. Its maximum
             jump length is 0, which makes it impossible to reach the last index.

The general idea of ​​the topic

Given an array of non-negative integers, initially located at the first position of the array. Each element in the array represents the maximum length that can be jumped at that position. Determine whether the last position can be reached.

Problem-solving ideas

  • Given a non-negative array, it is required to determine whether starting from the 0 index of the array, it can reach the last position of the array.
  • This question is relatively simple. If a certain 起跳点grid that can be used as can jump a distance of n, then it means that nthe following grids can be used as 起跳点. 起跳点You can try to jump once for each grid that can be used as , and keep 能跳到最远的距离maxJumpupdating . If you can skip all the way to the end, you've succeeded. If there is a point in the middle that maxJumpis larger than , it means that there is no connection between this point and maxJump, and some points cannot reach the last position.
    Of course, I will introduce the problem-solving ideas of each version separately:

Go version problem-solving ideas:

  • The question requires judging whether it is possible to jump from the first position to the last position.
  • Use a variable maxjto represent the farthest position that can currently be jumped, and the initial value is 0.
  • Traverse each element in the array, for each element, check whether it can jump to the current position ( i > maxjwhich means it cannot jump to the current position, return false), and then update it maxjto the larger of the current position and the maximum distance that the current position can jump to. value.
  • If the entire array is traversed successfully, it means that you can jump to the last position and return true.

Python version problem-solving ideas:

  • Similarly, the question requires judging whether it is possible to jump from the first position to the last position.
  • Use the variable max_ito represent the farthest position that can currently be jumped, and the initial value is 0.
  • Use enumeratethe function to traverse the list, iindicating the current position and jumpthe number of hops to the current position.
  • If max_iis greater than or equal to iand i + jumpis greater than max_i, then update max_iis i + jump.
  • Finally, determine max_iwhether is greater than or equal to the last position i, if so, return True, otherwise return False.

Java version solution ideas:

  • The question requires judging whether it is possible to jump from the first position to the last position.
  • Use the variable max_ito represent the farthest position that can currently be jumped, and the initial value is 0.
  • Use forto loop through the array ito represent the current position.
  • If max_iis greater than or equal to iand i + nums[i]is greater than max_i, then update max_iis i + nums[i].
  • Finally, determine max_iwhether is greater than or equal to the last position of the array, if so, return True, otherwise return False.

C++ version problem-solving ideas:

  • Similarly, the question requires judging whether it is possible to jump from the first position to the last position.
  • Use the variable max_ito represent the farthest position that can currently be jumped, and the initial value is 0.
  • Use forto loop through the vector irepresenting the current position.
  • If max_iis greater than or equal to iand i + nums[i]is greater than max_i, then update max_iis i + nums[i].
  • Finally, determine max_iwhether is greater than or equal to the last position of the vector, if so, return True, otherwise return False.

These problem-solving ideas are all based on the idea of ​​a greedy algorithm, that is, constantly updating the farthest position that can be jumped to, and finally judging whether it can jump to the last position. Hopefully these problem-solving ideas will help you understand the solutions for each version. If you have more questions, please feel free to ask.

code

func canJump(nums []int) bool {
    
    
  maxj := 0 // 初始化一个变量 maxj,表示当前能够跳到的最远的位置
  for i := 0; i < len(nums); i++ {
    
     // 遍历数组中的每个元素
    if i > maxj {
    
     // 如果当前索引 i 大于 maxj,说明无法跳到当前位置
      return false // 返回 false,表示无法跳到末尾
    }
    maxj = max(maxj, nums[i]+i) // 更新 maxj,取当前 maxj 和当前位置能跳到的最远位置的较大值
  }
  return true // 如果成功遍历完数组,说明可以跳到末尾,返回 true
}

func max(a, b int) int {
    
    
  if a > b {
    
    
    return a
  }
  return b
}

Python

class Solution:
    def canJump(self, nums) :
        max_i = 0       # 初始化当前能到达最远的位置,开始时为0
        for i, jump in enumerate(nums):   # 使用enumerate函数遍历列表,i为当前位置,jump是当前位置的跳数
            if max_i >= i and i + jump > max_i:  # 如果当前位置能到达,并且当前位置+跳数>最远位置
                max_i = i + jump  # 更新最远能到达位置
        return max_i >= i  # 判断最远能到达位置是否大于等于最后一个位置i,返回True或False

Java

class Solution {
    public boolean canJump(int[] nums) {
        int max_i = 0;  // 初始化当前能到达最远的位置,开始时为0
        for (int i = 0; i < nums.length; i++) {
            if (max_i >= i && i + nums[i] > max_i) {
                max_i = i + nums[i];  // 更新最远能到达位置
            }
        }
        return max_i >= nums.length - 1;  // 判断最远能到达位置是否大于等于最后一个位置
    }
}


Cpp

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int max_i = 0;  // 初始化当前能到达最远的位置,开始时为0
        for (int i = 0; i < nums.size(); i++) {
            if (max_i >= i && i + nums[i] > max_i) {
                max_i = i + nums[i];  // 更新最远能到达位置
            }
        }
        return max_i >= nums.size() - 1;  // 判断最远能到达位置是否大于等于最后一个位置
    }
};


Of course, I can use Chinese to detail the required basics of each version.

Go version:

  1. Arrays and Slices : Learn how to declare and use arrays and slices. In Go, arrays are fixed length, while slices are dynamic arrays.

  2. Loops and Iteration : Understand forloops and how to iterate over a slice or array.

  3. Functions : Be familiar with how to define and call functions. In this example, there are two functions, canJumpand max.

Python version:

  1. Lists and Iteration : Learn how to declare and manipulate Python's list (List) data structure. Lists can contain elements of different types.

  2. enumerate function : Learn about enumeratethe function, which is used to iterate over the indexes and values ​​of a list simultaneously.

  3. Conditional Statements : Understand ifthe use of conditional statements and how to perform different actions based on conditions.

Java version:

  1. Arrays and Loops : Learn how to declare and manipulate Java arrays. The size of arrays in Java is fixed.

  2. for loop : Understand forthe use of loops and how to traverse arrays.

  3. Conditional Statements : Become familiar ifwith the use of conditional statements to perform different actions based on conditions.

C++ version:

  1. Vector : Learn how to use C++'s vector container, which is similar to a dynamic array. Vectors can be automatically resized.

  2. for loop : Understand forthe use of loops and how to traverse vectors.

  3. Conditional Statements : Become familiar ifwith the use of conditional statements to perform different actions based on conditions.

This basic knowledge is required to understand and write solutions in these releases. If you need a more detailed explanation or have additional questions, please feel free to ask.

56. Merge Intervals

topic

Given a collection of intervals, merge all overlapping intervals.

Example 1:

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].

Example 2:

Input: [[1,4],[4,5]]
Output: [[1,5]]
Explanation: Intervals [1,4] and [4,5] are considered overlapping.

The general idea of ​​the topic

Merge multiple given intervals. If the intervals overlap, the intervals must be merged.

Problem-solving ideas

Go version:

  1. First, by traversing all intervals, find their maximum starting point and minimum end point for subsequent initialization of the array.

  2. Create two arrays startand endto count the occurrences of each starting point and ending point.

  3. Iterate through the interval list for the second time and add one to the corresponding array for the starting point and end point of each interval.

  4. Use prefixthe variable to record the number of currently active intervals, and use prefixthe value to determine whether to start a new merged interval.

  5. Finally, prefixthe merged interval is added to the answer based on the value of .

Python version:

  1. First, by traversing all intervals, find their maximum starting point and minimum end point for initialization of the subsequent list.

  2. Create two lists startand endto count the occurrences of each starting point and ending point.

  3. Iterate through the interval list for the second time and add one to the corresponding list for the starting point and end point of each interval.

  4. Use prefixthe variable to record the number of currently active intervals, and use prefixthe value to determine whether to start a new merged interval.

  5. Finally, prefixthe merged interval is added to the answer based on the value of .

Java version:

  1. First, by traversing all intervals, find their maximum starting point and minimum end point for subsequent initialization of the array.

  2. Create two arrays startand endto count the occurrences of each starting point and ending point.

  3. Iterate through the interval list for the second time and add one to the corresponding array for the starting point and end point of each interval.

  4. Use prefixthe variable to record the number of currently active intervals, and use prefixthe value to determine whether to start a new merged interval.

  5. Finally, the merged intervals are added to the answer array.

C++ version:

  1. First, by traversing all intervals, find their maximum starting point and minimum end point for initialization of subsequent vectors.

  2. Create two vectors startand endto count the occurrences of each starting point and ending point.

  3. Iterate through the interval list for the second time and add one to the corresponding vector for the start and end points of each interval.

  4. Use prefixthe variable to record the number of currently active intervals, and use prefixthe value to determine whether to start a new merged interval.

  5. Finally, the merged intervals are added to the answer vector.

In general, these versions of the solutions all adopt similar core ideas: first find the maximum starting point and minimum end point of the interval, then count the number of occurrences of each starting point and end point, and finally perform a merge operation based on this information.

code

Go

func merge(intervals [][]int) [][]int {
    MAX := math.MinInt
    MIN := math.MaxInt
    left := -1
    prefix := 0
    for _, temp := range intervals {
        x := temp[0]
        y := temp[1]
        if x < MIN {
            MIN = x
        }
        if y > MAX {
            MAX = y
        }
    }

    start := make([]int, MAX+1)
    end := make([]int, MAX+1)

    for i := 0; i < len(intervals); i++ {
        x := intervals[i][0]
        y := intervals[i][1]
        start[x]++
        end[y]++
    }

    var ans [][]int
    size := 0
    for i := MIN; i <= MAX; i++ {
        if start[i] > 0 {
            prefix += start[i]
            if prefix == start[i] {
                left = i
            }
        }
        if end[i] > 0 {
            prefix -= end[i]
            if prefix == 0 {
                ans = append(ans, []int{left, i})
                size++
            }
        }
    }
    return ans
}

Python

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        MAX = float('-inf')
        MIN = float('inf')
        left = -1
        prefix = 0
        for temp in intervals:
            x = temp[0]
            y = temp[1]
            if x < MIN:
                MIN = x
            if y > MAX:
                MAX = y

        start = [0] * (MAX + 1)
        end = [0] * (MAX + 1)
        
        for i in range(len(intervals)):
            x = intervals[i][0]
            y = intervals[i][1]
            start[x] += 1
            end[y] += 1

        ans = []
        size = 0
        for i in range(MIN, MAX + 1):
            if start[i] > 0:
                prefix += start[i]
                if prefix == start[i]:
                    left = i
            if end[i] > 0:
                prefix -= end[i]
                if prefix == 0:
                    ans.append([left, i])
                    size += 1
        
        return ans

Java

class Solution {
    static int[][] ans = new int[10001][2]; // 创建一个静态二维数组用于存储合并后的区间
    public int[][] merge(int[][] intervals) {
        int MAX = Integer.MIN_VALUE, MIN = Integer.MAX_VALUE, left = -1, prefix = 0;
        for (int[] temp : intervals) {
            int x = temp[0];
            int y = temp[1];
            if (x < MIN) MIN = x;
            if (y > MAX) MAX = y;
        }
        int[] start = new int[MAX+1], end = new int[MAX+1];
        
        // 统计每个起始点和结束点出现的次数
        for (int i = 0; i < intervals.length; i++) {
            int x = intervals[i][0];
            int y = intervals[i][1];
            start[x]++;
            end[y]++;
        }

        int size = 0;
        for (int i = MIN; i <= MAX; i++) {
            if (start[i] > 0) {
                prefix += start[i];
                if (prefix == start[i]) {
                    left = i;
                }
            }
            if (end[i] > 0) {
                prefix -= end[i];
                if (prefix == 0) {
                    ans[size++] = new int[]{left, i}; // 找到一个合并后的区间
                }
            }
        }
        return Arrays.copyOfRange(ans, 0, size); // 返回合并后的结果数组
    }
}

Cpp

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        int MAX = INT_MIN;
        int MIN = INT_MAX;
        int left = -1;
        int prefix = 0;
        for (const vector<int>& temp : intervals) {
            int x = temp[0];
            int y = temp[1];
            if (x < MIN) MIN = x;
            if (y > MAX) MAX = y;
        }

        vector<int> start(MAX + 1, 0);
        vector<int> end(MAX + 1, 0);

        for (int i = 0; i < intervals.size(); i++) {
            int x = intervals[i][0];
            int y = intervals[i][1];
            start[x]++;
            end[y]++;
        }

        vector<vector<int>> ans;
        int size = 0;
        for (int i = MIN; i <= MAX; i++) {
            if (start[i] > 0) {
                prefix += start[i];
                if (prefix == start[i]) {
                    left = i;
                }
            }
            if (end[i] > 0) {
                prefix -= end[i];
                if (prefix == 0) {
                    ans.push_back({left, i});
                    size++;
                }
            }
        }
        return ans;
    }
};

Solutions for each version and the basics required.

Go version:

This Go version of the solution uses the following important basics:

  1. Slices and Arrays: Slices and arrays in Go are data structures used to store multiple data of the same type. In this solution, slices are used to store the merged ranges.

  2. Loop: Use forloops to traverse range lists and other data structures.

  3. Conditional Statements: Use conditional statements to handle different situations, such as merging intervals.

  4. Slice Append: Use appendthe function to dynamically extend the slice to add the merged interval.

Python version:

This Python version of the solution uses the following basics:

  1. Lists: A list is a data structure in Python that is used to store multiple objects. In this solution, a list is used to store the merged ranges.

  2. Loop: Use forloops to traverse range lists and other data structures.

  3. Conditional Statements: Use conditional statements to handle different situations, such as merging intervals.

  4. List Append: Use appendthe method to dynamically extend the list to add merged intervals.

Java version:

This Java version of the solution uses the following basics:

  1. Classes and Objects: Java is an object-oriented programming language. In this solution, a Solutionclass named is created to solve the problem.

  2. Arrays: Use arrays to store merged intervals.

  3. Loop: Use forloops to traverse range lists and other data structures.

  4. Conditional Statements: Use conditional statements to handle different situations, such as merging intervals.

  5. Static and Dynamic Arrays: Static arrays are arrays whose size is defined in advance, while dynamic arrays can dynamically allocate sizes as needed.

C++ version:

This C++ version of the solution uses the following basics:

  1. Classes and Objects: C++ is an object-oriented programming language. In this solution, a Solutionclass named is created to solve the problem.

  2. Vectors: Use vectors to store merged intervals. Vector is a dynamic array data structure provided by the C++ standard library.

  3. Loop: Use forloops to traverse range lists and other data structures.

  4. Conditional Statements: Use conditional statements to handle different situations, such as merging intervals.

Guess you like

Origin blog.csdn.net/qq_42531954/article/details/133458355