Go-Python-Java-C-LeetCode High Resolution Method-Seventh 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

Go-Python-Java-C-LeetCode high decomposition method - first week collection
Go-Python-Java-C-LeetCode high decomposition method - second week collection
Go-Python-Java-C-LeetCode high decomposition method - third week Collection
Go-Python-Java-C-LeetCode high decomposition method - the fourth week collection
Go-Python-Java-C-LeetCode high decomposition method - the fifth week collection
Go-Python-Java-C-LeetCode high decomposition method - sixth week Zhou Collection
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. Welcome to subscribe to the column, one question every day, and improve the LeetCode column
with the bloggers

43. Multiply Strings

topic

Given two non-negative integersnum1andnum2represented as strings, return the product ofnum1andnum2, also
represented as a string.

**Note:**You must not use any built-in BigInteger library or convert the inputs to integer directly.

Example 1:

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

Example 2:

Input: num1 = "123", num2 = "456"
Output: "56088"

Constraints:

  • 1 <= num1.length, num2.length <= 200
  • num1andnum2consist of digits only.
  • Bothnum1andnum2do not contain any leading zero, except the number0itself.

The general idea of ​​the topic

Given two nonnegative integers num1 and num2 represented as strings, return the product of num1 and num2, also represented as strings.

Problem-solving ideas

  • Simulate multiplication with arrays. Create an len(num1) + len(num2)
    array of length to store the product. For any 0 ≤ i < len(num1), 0 ≤ j < len(num2), num1[i] * num2[j]the result of , lies in tmp[i+j+1]
    , if tmp[i+j+1]≥10, then the carry part is added to tmp[i+j]. Finally, convert the array tmpinto a string, discarding the highest bit if it is 0.
    The following introduces the problem-solving ideas for each version:

Go version problem-solving ideas

  1. First, check whether the input num1and num2are "0", if one of them is "0", then return "0", because any number multiplied by 0 is equal to 0.

  2. Creates an integer slice tmpof length len(num1) + len(num2)to store the intermediate results of multiplication.

  3. Use a nested loop to iterate over each character of num1and num2, multiply the numbers at the corresponding positions, and accumulate the results into the tmpappropriate positions in .

  4. Handle carry: Traverse from right to left tmp, add the carry of each bit to the previous bit, and take the current bit modulo 10 to keep it in the range of 0 to 9.

  5. If tmpthe highest bit of is 0, remove the 0 from the highest bit.

  6. Convert tmpthe numbers in the slice to characters and build the resulting string.

  7. Returns the result string.

Python version problem-solving ideas

  1. First, check whether the input num1and num2are "0", if one of them is "0", then return "0", because any number multiplied by 0 is equal to 0.

  2. Use the built-in int()function to convert num1and num2to integers, then multiply them to get an integer result.

  3. Convert the integer result to a string and return it.

Java version problem solving ideas

  1. First, check whether the input num1and num2are "0", if one of them is "0", then return "0", because any number multiplied by 0 is equal to 0.

  2. Converts num1and num2to character arrays b1and b2.

  3. Create an integer array tmpof length num1.length() + num2.length()to store the intermediate results of multiplication.

  4. Use a nested loop to iterate over each character of b1and b2, multiply the numbers at the corresponding positions, and accumulate the results into the tmpappropriate positions in .

  5. Handle carry: Traverse from right to left tmp, add the carry of each bit to the previous bit, and take the current bit modulo 10 to keep it in the range of 0 to 9.

  6. If tmpthe highest bit of is 0, remove the 0 from the highest bit.

  7. Constructs the resulting string, converting tmpthe numbers in the array to characters.

  8. Returns the result string.

C++ version problem-solving ideas

  1. First, check whether the input num1and num2are "0", if one of them is "0", then return "0", because any number multiplied by 0 is equal to 0.

  2. Converts num1and num2to character arrays b1and b2.

  3. Create an integer array tmpof length num1.length() + num2.length()to store the intermediate results of multiplication.

  4. Use a nested loop to iterate over each character of b1and b2, multiply the numbers at the corresponding positions, and accumulate the results into the tmpappropriate positions in .

  5. Handle carry: Traverse from right to left tmp, add the carry of each bit to the previous bit, and take the current bit modulo 10 to keep it in the range of 0 to 9.

  6. If tmpthe highest bit of is 0, remove the 0 from the highest bit.

  7. Constructs the resulting string, converting tmpthe numbers in the array to characters.

  8. Returns the result string.

Generally speaking, the problem-solving ideas of these versions are similar. They all simulate the process of manual multiplication, store the product of each bit in the intermediate array, and then handle the carry and construct the final result string. Different programming languages ​​have different syntax and data structures, but the basic idea is the same.

code

Go

func multiply(num1 string, num2 string) string {
    if num1 == "0" || num2 == "0" {
        return "0"
    }

    // 将输入的两个字符串转换为字节数组
    b1, b2, tmp := []byte(num1), []byte(num2), make([]int, len(num1)+len(num2))

    // 使用嵌套循环遍历两个输入字符串的每一位数字进行相乘,结果存储在 tmp 数组中
    for i := 0; i < len(b1); i++ {
        for j := 0; j < len(b2); j++ {
            tmp[i+j+1] += int(b1[i]-'0') * int(b2[j]-'0')
        }
    }

    // 处理进位,将 tmp 数组中的每一位数字都保留在 0 到 9 的范围内
    for i := len(tmp) - 1; i > 0; i-- {
        tmp[i-1] += tmp[i] / 10
        tmp[i] = tmp[i] % 10
    }

    // 如果最高位是0,则去除最高位的0
    if tmp[0] == 0 {
        tmp = tmp[1:]
    }

    // 将结果从整数数组转换回字符串
    res := make([]byte, len(tmp))
    for i := 0; i < len(tmp); i++ {
        res[i] = '0' + byte(tmp[i])
    }
    return string(res)
}

Python

class Solution:
    def multiply(self, num1: str, num2: str) -> str:
        return str(int(num1) * int(num2))

Java

class Solution {
    public String multiply(String num1, String num2) {
        if (num1.equals("0") || num2.equals("0")) {
            return "0";
        }

        char[] b1 = num1.toCharArray();
        char[] b2 = num2.toCharArray();
        int[] tmp = new int[num1.length() + num2.length()];

        for (int i = 0; i < b1.length; i++) {
            for (int j = 0; j < b2.length; j++) {
                tmp[i + j + 1] += (b1[i] - '0') * (b2[j] - '0');
            }
        }

        for (int i = tmp.length - 1; i > 0; i--) {
            tmp[i - 1] += tmp[i] / 10;
            tmp[i] = tmp[i] % 10;
        }

        if (tmp[0] == 0) {
            tmp = Arrays.copyOfRange(tmp, 1, tmp.length);
        }

        StringBuilder result = new StringBuilder();
        for (int num : tmp) {
            result.append(num);
        }

        return result.toString();
    }
}

Cpp

class Solution {
public:
    string multiply(string num1, string num2) {
        if (num1 == "0" || num2 == "0") {
            return "0";
        }

        vector<char> b1(num1.begin(), num1.end());
        vector<char> b2(num2.begin(), num2.end());
        vector<int> tmp(num1.length() + num2.length(), 0);

        for (int i = 0; i < b1.size(); i++) {
            for (int j = 0; j < b2.size(); j++) {
                tmp[i + j + 1] += (b1[i] - '0') * (b2[j] - '0');
            }
        }

        for (int i = tmp.size() - 1; i > 0; i--) {
            tmp[i - 1] += tmp[i] / 10;
            tmp[i] = tmp[i] % 10;
        }

        if (tmp[0] == 0) {
            tmp.erase(tmp.begin());
        }

        string result;
        for (int num : tmp) {
            result += to_string(num);
        }

        return result;
    }
};

When using different programming languages ​​to implement the same algorithm, you need to master the basic knowledge and syntax associated with that language. Here’s a breakdown of the basic knowledge requirements for each version:

Go version

  1. Data Types and Variables : Learn about the basic data types in Go such as integers, strings, and arrays. Learn how to declare and use variables.

  2. Slice : Slices in Go are dynamic arrays, and you need to understand how to create, manipulate, and use slices to handle character arrays.

  3. Loops : Learn about loop statements in Go forto perform nested loops on characters of two strings.

  4. Conditional Statements : Learn about conditional statements in Go ifto handle special cases, such as when the multiplier is "0".

  5. Array and Slice Operations : Understand how to access the elements of arrays and slices, and how to iterate over arrays and slices.

Python version

  1. Data Types and Variables : Learn about the basic data types in Python, such as integers, strings, and lists. Learn how to declare and use variables.

  2. String manipulation : There are powerful string manipulation capabilities in Python that require understanding how to access the characters of a string, slice a string, and convert a string to an integer.

  3. Loopsfor : Learn about loops and loop statements in Python whileto perform nested loops on characters of two strings.

  4. Conditional Statements : Learn about conditional statements in Python ifto handle special cases, such as when the multiplier is "0".

  5. List : Learn how to create, manipulate, and use list data structures in Python to store intermediate results.

Java version

  1. Classes and Objects : Java is an object-oriented programming language, and one needs to know how to create classes and objects to organize the code.

  2. Data Types and Variables : Understand the basic data types in Java such as integers, strings, and character arrays. Learn how to declare and use variables.

  3. Character Array Operations : Learn how to create character arrays in which to store the characters of a string and perform operations between characters.

  4. Loopsfor : Learn about loops and loop statements in Java whileto perform nested loops on characters of two character arrays.

  5. Conditional Statements : Learn about conditional statements in Java ifto handle special cases such as when the multiplier is '0'.

  6. String Operations : Java provides many string manipulation methods, requiring knowledge of how to access the characters of a string, convert a string to an integer, and how to construct the StringBuilderresulting string using classes.

C++ version

  1. Data Types and Variables : Understand the basic data types in C++ such as integers, strings, and arrays. Learn how to declare and use variables.

  2. Character Array Operations : Learn how to create character arrays in which to store the characters of a string and perform operations between characters.

  3. Loopsfor : Learn about loops and loop statements in C++ whileto perform nested loops on characters of two character arrays.

  4. Conditional Statements : Learn about conditional statements in C++ ifto handle special cases, such as when the multiplier is "0".

  5. String Operations : C++ provides many string manipulation functions, requiring knowledge of how to access the characters of a string, convert a string to an integer, and how to construct the stringstreamresulting string using .

Whichever version you choose, you'll need to be familiar with basic data types, variable declarations, loops, conditional statements, and operations related to strings and character arrays. Additionally, understanding how to handle special cases (for example, a multiplier of "0") and how to convert the result from other data types to a string are also key points in solving this problem.

44.Wildcard Matching

Given an input string (s) and a pattern ( p), implement wildcard pattern matching with support for ‘?’ and ‘*’ where:

‘?’ Matches any single character.
‘*’ Matches any sequence of characters (including the empty sequence).
The matching should cover the entire input string (not partial).

Example 1:

Input: s = “aa”, p = “a”
Output: false
Explanation: “a” does not match the entire string “aa”.
Example 2:

Input: s = “aa”, p = ""
Output: true
Explanation: '
’ matches any sequence.
Example 3:

Input: s = “cb”, p = “?a”
Output: false
Explanation: ‘?’ matches ‘c’, but the second letter is ‘a’, which does not match ‘b’.

Constraints:

0 <= s.length, p.length <= 2000
s contains only lowercase English letters.
p contains only lowercase English letters, ‘?’ or ‘*’.

The general idea of ​​the topic

Given an input string(s) and a character pattern§, please implement a wildcard match that supports '?' and ' ' matching rules:
'?' can match any single character.
'
' can match any character sequence (including the empty character sequence).
The necessary and sufficient condition for a successful match is that the character pattern must completely match the input string (rather than a partial match).

Problem-solving ideas

When discussing the problem-solving ideas of each version, we will introduce the algorithm steps of each version in detail. Here are the problem-solving ideas for each version:

Go version:

The Go version of the problem-solving idea is to use double pointers and backtracking to match strings and patterns. The main steps are as follows:

  1. First, use a loop to process pconsecutive *characters at the end of the pattern. This is to skip redundancy in the pattern *.

  2. Then enter a loop and iterate through the string sand pattern at the same time p:

    • If the current pattern character is *, record the position of the current string sand pattern p, and pmove the pattern pointer one position backward.
    • If the current character matches or is ?a wildcard character, move both the string and pattern pointers backward one bit.
    • If the characters do not match and there is a backtracking position, backtrack to the previous *position and update the string and pattern pointers.
  3. After the loop ends, check if there are any unprocessed *characters in the pattern p.

  4. Finally, check pwhether the pattern has exactly matched the string s. If the pattern pointer preaches the end of the pattern, the match is successful.

Python version:

The problem-solving ideas of the Python version are similar to the Go version, also using double pointers and backtracking. The main steps are as follows:

  1. First, use a loop to process pconsecutive *characters at the end of the pattern. This is to skip redundancy in the pattern *.

  2. Then enter a loop and iterate through the string sand pattern at the same time p:

    • If the current pattern character is *, record the position of the current string sand pattern p, and pmove the pattern pointer one position backward.
    • If the current character matches or is ?a wildcard character, move both the string and pattern pointers backward one bit.
    • If the characters do not match and there is a backtracking position, backtrack to the previous *position and update the string and pattern pointers.
  3. After the loop ends, check if there are any unprocessed *characters in the pattern p.

  4. Finally, check pwhether the pattern has exactly matched the string s. If the pattern pointer preaches the end of the pattern, the match is successful.

Java version:

The Java version's problem-solving ideas also use double pointers and backtracking. The main steps are as follows:

  1. First, use a loop to process pconsecutive *characters at the end of the pattern. This is to skip redundancy in the pattern *.

  2. Then enter a loop and iterate through the string sand pattern at the same time p:

    • If the current pattern character is *, record the position of the current string sand pattern p, and pmove the pattern pointer one position backward.
    • If the current character matches or is ?a wildcard character, move both the string and pattern pointers backward one bit.
    • If the characters do not match and there is a backtracking position, backtrack to the previous *position and update the string and pattern pointers.
  3. After the loop ends, check if there are any unprocessed *characters in the pattern p.

  4. Finally, check pwhether the pattern has exactly matched the string s. If the pattern pointer preaches the end of the pattern, the match is successful.

C++ version:

The problem-solving ideas of the C++ version are similar to those of other versions, also using double pointers and backtracking. The main steps are as follows:

  1. First, use a loop to process pconsecutive *characters at the end of the pattern. This is to skip redundancy in the pattern *.

  2. Then enter a loop and iterate through the string sand pattern at the same time p:

    • If the current pattern character is *, record the position of the current string sand pattern p, and pmove the pattern pointer one position backward.
    • If the current character matches or is ?a wildcard character, move both the string and pattern pointers backward one bit.
    • If the characters do not match and there is a backtracking position, backtrack to the previous *position and update the string and pattern pointers.
  3. After the loop ends, check if there are any unprocessed *characters in the pattern p.

  4. Finally, check pwhether the pattern has exactly matched the string s. If the pattern pointer preaches the end of the pattern, the match is successful.

Overall, no matter which programming language you use, the core idea of ​​the solution is double pointers and backtracking for matching strings and patterns, while handling wildcards *and ?.

code

func isMatch(s string, p string) bool {
    
    
    // 进入循环,只要s和p非空且p的最后一个字符不是'*'
    for len(s) > 0 && len(p) > 0 && p[len(p)-1] != '*' {
    
    
        // 如果字符匹配或者p的最后一个字符是'?',则从s和p的末尾去掉一个字符
        if charMatch(s[len(s)-1], p[len(p)-1]) {
    
    
            s = s[:len(s)-1]
            p = p[:len(p)-1]
        } else {
    
    
            // 如果字符不匹配,返回false
            return false
        }
    }
    // 如果p为空,返回s是否也为空
    if len(p) == 0 {
    
    
        return len(s) == 0
    }
    // 初始化索引和记录变量
    sIndex, pIndex := 0, 0
    sRecord, pRecord := -1, -1
    // 开始循环,sIndex小于s的长度且pRecord小于p的长度
    for sIndex < len(s) && pRecord < len(p) {
    
    
        // 如果p的当前字符是'*',将p的索引向后移动,记录s和p的位置
        if p[pIndex] == '*' {
    
    
            pIndex++
            sRecord, pRecord = sIndex, pIndex
        } else if charMatch(s[sIndex], p[pIndex]) {
    
    
            // 如果字符匹配,将s和p的索引都向后移动
            sIndex++
            pIndex++
        } else if sRecord != -1 && sRecord + 1 < len(s) {
    
    
            // 如果字符不匹配,但是有记录的位置可用,并且sRecord+1小于s的长度,更新sIndex和pIndex
            sRecord++
            sIndex, pIndex = sRecord, pRecord
        } else {
    
    
            // 如果没有符合的情况,返回false
            return false
        }
    }
    // 最后,检查p中是否只包含'*'
    return allStars(p, pIndex, len(p))
}

// 辅助函数,检查字符串中是否都是'*'
func allStars(str string, left, right int) bool {
    
    
    for i := left; i < right; i++ {
    
    
        if str[i] != '*' {
    
    
            return false
        }
    }
    return true
}

// 辅助函数,检查两个字符是否匹配
func charMatch(u, v byte) bool {
    
    
    return u == v || v == '?'
}

Python

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        # 进入循环,只要s和p非空且p的最后一个字符不是'*'
        while s and p and p[-1] != '*':
            # 如果字符匹配或者p的最后一个字符是'?',则从s和p的末尾去掉一个字符
            if self.charMatch(s[-1], p[-1]):
                s = s[:-1]
                p = p[:-1]
            else:
                # 如果字符不匹配,返回false
                return False
        # 如果p为空,返回s是否也为空
        if not p:
            return not s
        # 初始化索引和记录变量
        sIndex, pIndex = 0, 0
        sRecord, pRecord = -1, -1
        # 开始循环,sIndex小于s的长度且pRecord小于p的长度
        while sIndex < len(s) and pRecord < len(p):
            # 如果p的当前字符是'*',将p的索引向后移动,记录s和p的位置
            if p[pIndex] == '*':
                pIndex += 1
                sRecord, pRecord = sIndex, pIndex
            elif self.charMatch(s[sIndex], p[pIndex]):
                # 如果字符匹配,将s和p的索引都向后移动
                sIndex += 1
                pIndex += 1
            elif sRecord != -1 and sRecord + 1 < len(s):
                # 如果字符不匹配,但是有记录的位置可用,并且sRecord+1小于s的长度,更新sIndex和pIndex
                sRecord += 1
                sIndex, pIndex = sRecord, pRecord
            else:
                # 如果没有符合的情况,返回false
                return False
        # 最后,检查p中是否只包含'*'
        return self.allStars(p, pIndex, len(p))

    # 辅助函数,检查字符串中是否都是'*'
    def allStars(self, s, left, right):
        for i in range(left, right):
            if s[i] != '*':
                return False
        return True

    # 辅助函数,检查两个字符是否匹配
    def charMatch(self, u, v):
        return u == v or v == '?'

Java

class Solution {
    public boolean isMatch(String s, String p) {
        // 进入循环,只要s和p非空且p的最后一个字符不是'*'
        while (s.length() > 0 && p.length() > 0 && p.charAt(p.length() - 1) != '*') {
            // 如果字符匹配或者p的最后一个字符是'?',则从s和p的末尾去掉一个字符
            if (charMatch(s.charAt(s.length() - 1), p.charAt(p.length() - 1))) {
                s = s.substring(0, s.length() - 1);
                p = p.substring(0, p.length() - 1);
            } else {
                // 如果字符不匹配,返回false
                return false;
            }
        }
        // 如果p为空,返回s是否也为空
        if (p.length() == 0) {
            return s.length() == 0;
        }
        // 初始化索引和记录变量
        int sIndex = 0, pIndex = 0;
        int sRecord = -1, pRecord = -1;
        // 开始循环,sIndex小于s的长度且pRecord小于p的长度
        while (sIndex < s.length() && pRecord < p.length()) {
            // 如果p的当前字符是'*',将p的索引向后移动,记录s和p的位置
            if (p.charAt(pIndex) == '*') {
                pIndex++;
                sRecord = sIndex;
                pRecord = pIndex;
            } else if (charMatch(s.charAt(sIndex), p.charAt(pIndex))) {
                // 如果字符匹配,将s和p的索引都向后移动
                sIndex++;
                pIndex++;
            } else if (sRecord != -1 && sRecord + 1 < s.length()) {
                // 如果字符不匹配,但是有记录的位置可用,并且sRecord+1小于s的长度,更新sIndex和pIndex
                sRecord++;
                sIndex = sRecord;
                pIndex = pRecord;
            } else {
                // 如果没有符合的情况,返回false
                return false;
            }
        }
        // 最后,检查p中是否只包含'*'
        return allStars(p, pIndex, p.length());
    }

    // 辅助函数,检查字符串中是否都是'*'
    private boolean allStars(String str, int left, int right) {
        for (int i = left; i < right; i++) {
            if (str.charAt(i) != '*') {
                return false;
            }
        }
        return true;
    }

    // 辅助函数,检查两个字符是否匹配
    private boolean charMatch(char u, char v) {
        return u == v || v == '?';
    }
}

Cpp

class Solution {
public:
    bool isMatch(string s, string p) {
        int lens = s.size(); // 获取字符串s的长度
        int lenp = p.size(); // 获取模式p的长度
        int scur = 0; // 初始化字符串s的当前指针
        int sstar = -1; // 初始化字符串s的'*'的位置记录
        int pcur = 0; // 初始化模式p的当前指针
        int pstar = -1; // 初始化模式p的'*'的位置记录
        
        while (scur < lens) { // 循环处理字符串s
            if (pcur < lenp && p[pcur] == '*') { // 如果模式p当前字符是'*'
                sstar = scur; // 记录当前字符串s的位置
                pstar = ++pcur; // 记录当前模式p的位置,同时将模式p指针向后移动
            } else {
                if (pcur < lenp && (p[pcur] == '?' || p[pcur] == s[scur])) {
                    // 如果模式p当前字符是'?'或者与字符串s当前字符相匹配
                    scur++; // 移动字符串s的指针
                    pcur++; // 移动模式p的指针
                } else {
                    if (sstar < 0) return false; // 如果没有'*'的位置记录,返回false
                    scur = ++sstar; // 回溯到'*'的位置的下一个字符
                    pcur = pstar; // 恢复模式p的指针到'*'的位置的下一个字符
                }
            }
        }
        
        while (pcur < lenp && p[pcur] == '*') pcur++; // 处理模式p中多余的'*'
        
        return pcur == lenp; // 返回是否模式p已经处理完毕
    }
};

We'll detail the basics required when discussing each version of the solution. First, we will use versions of Go, Python, Java, and C++ for analysis.

Go version:

  1. Basic syntax and data types : In Go, you need to understand basic syntax and data types, including variable declarations, loops, conditional statements, etc.

  2. String operations : You need to know how to process strings, including string slicing operations and getting the length of a string.

  3. Loops and Conditional Statements : Loops and conditional statements are used in the code to iterate through strings and perform different operations, so you need to understand these control structures.

  4. Slicing operation : In Go, slicing operation is one of the key operations for processing strings and arrays. You need to know how to intercept and manipulate slices.

Python version:

  1. Basic syntax and data types : In Python, you need to understand basic syntax and data types, including variables, lists, strings, loops, conditional statements, etc.

  2. String operation : Python provides a wealth of string operation methods, including slicing, splicing, length, etc. You need to understand these operations.

  3. Loops and Conditional Statements : Loops and conditional statements are used in the code to iterate through strings and perform different operations, so you need to understand these control structures.

  4. Object-Oriented Programming (OOP) : Although classes and objects are not used in the code, Python is an object-oriented programming language, so you need to understand the basic concepts of OOP.

Java version:

  1. Basic syntax and data types : In Java, you need to know the basic syntax and data types, including variable declaration, list, string, loop, conditional statement, etc.

  2. String operations : Java provides classes and methods for processing strings. You need to understand how to use Stringclass methods to operate strings.

  3. Loops and Conditional Statements : Loops and conditional statements are used in the code to iterate through strings and perform different operations, so you need to understand these control structures.

  4. Object-Oriented Programming (OOP) : Java is an object-oriented programming language, and you need to understand the basic concepts of OOP, namely classes, objects, inheritance, etc.

C++ version:

  1. Basic syntax and data types : In C++, you need to understand basic syntax and data types, including variable declarations, arrays, strings, loops, conditional statements, etc.

  2. String operations : C++ provides a standard library for processing strings. You need to know how to use the string functions in the standard library to operate strings.

  3. Loops and Conditional Statements : Loops and conditional statements are used in the code to iterate through strings and perform different operations, so you need to understand these control structures.

  4. Pointers and references : C++ involves the concepts of pointers and references, especially when dealing with strings. You need to understand how to use pointers and references to manipulate data.

In general, no matter which programming language version you choose, you need to master basic programming concepts, control structures, string manipulation methods, and understand and implement algorithms based on specific language features. Each version uses basic programming knowledge such as loops, conditional statements, and string manipulation to solve wildcard matching problems.

45. Jump Game II

topic

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

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

Your goal is to reach the last index in the minimum number of jumps.

You can assume that you can always reach the last index.

Example 1:

Input: nums = [2,3,1,1,4]
Output: 2
Explanation: The minimum number of jumps to reach the last index is 2. Jump 1 step from index 0 to 1, then 3 steps to the last index.

Example 2:

Input: nums = [2,3,0,1,4]
Output: 2

Constraints:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 10^5

The general idea of ​​the topic

Given an array of non-negative integers, you are initially at the first position of the array. Each element in the array represents the maximum length you can jump at that position. Your goal is to reach the last position of the array using the fewest number of jumps.

Problem-solving ideas

  • If you are asked to find the minimum number of jumps, you will naturally think of using a greedy algorithm to solve the problem. Scan the step array, maintain the current position that can reach the maximum subscript, and record it as the farthest boundary that can be reached. If the farthest boundary is reached during the scanning process, update the boundary and increase the number of jumps by 1.
  • When scanning the array, there is actually no need to scan the last element, because before jumping to the last element, the farthest boundary that can be reached must be greater than or equal to the position of the last element, otherwise the last element will not be jumped and the end point will not be reached. ; If the last element is traversed, it means that the boundary is exactly the last position, and the final number of jumps can be directly + 1, and there is no need to access the last element.

Go version problem-solving ideas

In the Go version, the idea to solve the "Jump Game II" problem is as follows:

  1. Initialize three variables: needChoose(indicating the location where you need to choose the next step), canReach(indicating the farthest position that can currently be reached), step(indicating the number of steps to jump), and initialize them all to 0.

  2. To iterate over the input array nums, use for i, x := range numsto traverse.

  3. During the traversal process, check whether the current position iplus the maximum distance that can be jumped is greater than , if so, update to , indicating the further position that can be reached.xcanReachcanReachi + x

  4. If canReachis already greater than or equal to the last position of the array len(nums)-1, then return directly step + 1because the end point has been reached.

  5. If the current position iis equal to needChoosethe position pointed to, it means you need to select the next position. At this time, needChooseupdate to canReach, indicating that the next step will canReachstart from , and stepadd 1 to , indicating that one step has been jumped.

  6. Finally, the minimum number of steps is returned step, which is the minimum number of jumps required to reach the last position.

Python version problem-solving ideas

In the Python version, the idea of ​​​​solving the "Jump Game II" problem is similar to the Go version:

  1. Initialize three variables: needChoose(indicating the location where you need to choose the next step), canReach(indicating the farthest position that can currently be reached), step(indicating the number of steps to jump), and initialize them all to 0.

  2. To iterate over the input list nums, use for i in range(len(nums))to traverse.

  3. During the traversal process, check whether the current position iplus the maximum distance that can be jumped is greater than , if so, update to , indicating the further position that can be reached.nums[i]canReachcanReachi + nums[i]

  4. If canReachis already greater than or equal to the last position of the list len(nums)-1, then return directly step + 1because the end point has been reached.

  5. If the current position iis equal to needChoosethe position pointed to, it means you need to select the next position. At this time, needChooseupdate to canReach, indicating that the next step will canReachstart from , and stepadd 1 to , indicating that one step has been jumped.

  6. Finally, the minimum number of steps is returned step, which is the minimum number of jumps required to reach the last position.

Java version problem solving ideas

In the Java version, the idea of ​​​​solving the "Jump Game II" problem is similar to the Go and Python versions:

  1. Initialize three variables: needChoose(indicating the location where you need to choose the next step), canReach(indicating the farthest position that can currently be reached), step(indicating the number of steps to jump), and initialize them all to 0.

  2. To iterate over the input array nums, use for (int i = 0; i < nums.length; i++)to traverse.

  3. During the traversal process, check whether the current position iplus the maximum distance that can be jumped is greater than , if so, update to , indicating the further position that can be reached.nums[i]canReachcanReachi + nums[i]

  4. If canReachis already greater than or equal to the last position of the array nums.length - 1, then return directly step + 1because the end point has been reached.

  5. If the current position iis equal to needChoosethe position pointed to, it means you need to select the next position. At this time, needChooseupdate to canReach, indicating that the next step will canReachstart from , and stepadd 1 to , indicating that one step has been jumped.

  6. Finally, the minimum number of steps is returned step, which is the minimum number of jumps required to reach the last position.

C++ version problem-solving ideas

In the C++ version, the idea of ​​​​solving the "Jump Game II" problem is similar to the previous version:

  1. Initialize three variables: needChoose(indicating the location where you need to choose the next step), canReach(indicating the farthest position that can currently be reached), step(indicating the number of steps to jump), and initialize them all to 0.

  2. To iterate over the input vector nums, usefor (int i = 0; i < nums.size(); i++)

  3. During the traversal process, check whether the current position iplus the maximum distance that can be jumped is greater than , if so, update to , indicating the further position that can be reached.nums[i]canReachcanReachi + nums[i]

  4. If canReachis already greater than or equal to the last position of the vector nums.size() - 1, then return directly step + 1because the end point has been reached.

  5. If the current position iis equal to needChoosethe position pointed to, it means you need to select the next position. At this time, needChooseupdate to canReach, indicating that the next step will canReachstart from , and stepadd 1 to , indicating that one step has been jumped.

  6. Finally, the minimum number of steps is returned step, which is the minimum number of jumps required to reach the last position.

This is the solution idea for each version

code

func jump(nums []int) int {
    
    
    // 如果数组长度为1,无需跳跃,返回0
    if len(nums) == 1 {
    
    
        return 0
    }
    // needChoose 表示需要选择下一步的位置,canReach 表示当前可以到达的最远位置,step 表示跳跃的步数
    needChoose, canReach, step := 0, 0, 0
    // 遍历数组
    for i, x := range nums {
    
    
        // 如果当前位置加上跳跃力可以到达更远的位置
        if i+x > canReach {
    
    
            // 更新 canReach 为更远的位置
            canReach = i + x
            // 如果 canReach 已经可以到达数组末尾,返回步数加1
            if canReach >= len(nums)-1 {
    
    
                return step + 1
            }
        }
        // 如果当前位置已经是 needChoose 所指的位置
        if i == needChoose {
    
    
            // 更新 needChoose 为 canReach,表示下一步要从 canReach 开始跳跃
            needChoose = canReach
            // 步数加1
            step++
        }
    }
    // 返回最小步数
    return step
}

Python

class Solution:
    def jump(self, nums: List[int]) -> int:
        if len(nums) == 1:
            return 0
        needChoose, canReach, step = 0, 0, 0
        for i in range(len(nums)):
            if i + nums[i] > canReach:
                canReach = i + nums[i]
                if canReach >= len(nums) - 1:
                    return step + 1
            if i == needChoose:
                needChoose = canReach
                step += 1
        return step

Java

class Solution {
    public int jump(int[] nums) {
        if (nums.length == 1) {
            return 0;
        }
        int needChoose = 0, canReach = 0, step = 0;
        for (int i = 0; i < nums.length; i++) {
            if (i + nums[i] > canReach) {
                canReach = i + nums[i];
                if (canReach >= nums.length - 1) {
                    return step + 1;
                }
            }
            if (i == needChoose) {
                needChoose = canReach;
                step++;
            }
        }
        return step;
    }
}

Cpp

class Solution {
public:
    int jump(vector<int>& nums) {
        if (nums.size() == 1) {
            return 0;
        }
        int needChoose = 0, canReach = 0, step = 0;
        for (int i = 0; i < nums.size(); i++) {
            if (i + nums[i] > canReach) {
                canReach = i + nums[i];
                if (canReach >= nums.size() - 1) {
                    return step + 1;
                }
            }
            if (i == needChoose) {
                needChoose = canReach;
                step++;
            }
        }
        return step;
    }
};

Basic knowledge required for each version of the code.

Go version

  • Go (also known as Golang) is an open source programming language with concise syntax and efficient performance. In this Go version of the code, you need to know the following basics:
    • Go's basic syntax, including variable declaration, loops, conditional statements, etc.
    • The use of slices and arrays because the question involves processing integer arrays.
    • Definition and calling of functions, as well as processing of function parameters and return values.
    • Use of loop structures (for loops) and conditional statements (if statements) as these are important when solving problems.
    • Slicing operations, such as slice expansion, index access, etc., because these are related to jumping problems.

Python version

  • Python is a widely used high-level programming language known for its simple and easy-to-read syntax. In this Python version of the code, you need to know the following basics:
    • Basic syntax of Python, including variable declaration, loops, conditional statements, etc.
    • The use of lists (List), because the question involves processing lists of integers.
    • Definition of classes and methods because the code uses classes to organize the solution.
    • Use of loop structures (for loops) and conditional statements (if statements) as these are important when solving problems.

Java version

  • Java is a widely used statically typed programming language, often used for building large-scale applications. In this Java version of the code, you need to know the following basics:
    • Basic syntax of Java, including variable declaration, loops, conditional statements, etc.
    • The use of arrays because the question involves processing integer arrays.
    • Definition of classes and methods because the code uses classes to organize the solution.
    • Use of loop structures (for loops) and conditional statements (if statements) as these are important when solving problems.

C++ version

  • C++ is a multi-paradigm programming language that combines features of high-level and low-level programming. In this C++ version of the code, you need to know the following basics:
    • Basic syntax of C++, including variable declaration, loops, conditional statements, etc.
    • The use of vector (Vector), because the question involves processing integer vectors.
    • Definition of classes and methods because the code uses classes to organize the solution.
    • Use of loop structures (for loops) and conditional statements (if statements) as these are important when solving problems.

The above is an overview of the basics required for each version of the code. If you need a more detailed explanation or have specific questions, feel free to ask.

46. Permutations

topic

Given a collection of distinct integers, return all possible permutations.

Example:

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

The general idea of ​​the topic

Given a sequence with no repeating numbers, return all possible permutations of it.

Problem-solving ideas

  • To find all the permutations in the permutations and combinations of an array, just use DFS to search deeply.

Go version problem-solving ideas:

  1. Depth First Search (DFS): This solution uses a depth first search algorithm to generate all possible permutations.

  2. DFS recursive function: In dfsthe function, we maintain two important parameters: pathand visited. pathStores the current permutation being generated, visitedmarking which numbers have been used.

  3. Recursive process: In each recursive call, we try to add unused numbers to pathand mark them as used. Then, dfsthe function is called recursively to continue generating the next number. The end condition of the recursion is paththat the length of is equal to numsthe length of the input array, indicating that a complete permutation has been generated.

  4. Backtracking: When recursion returns, we need to backtrack to the previous level of state. This involves removing the last pathnumber added to and marking its corresponding visitedas unused so that other numbers can be tried on the next iteration.

  5. Result collection: Whenever we find a complete permutation, we copy it into a result set ( ans), eventually returning all permutations.

Python version problem-solving ideas:

  1. Depth First Search (DFS): This solution also uses a depth first search algorithm to generate all possible permutations.

  2. DFS recursive function: In trackbackthe function, we maintain three important parameters: currthe permutation that is currently being generated, usedthe index of the number that has been used, numsand the input array.

  3. Recursive process: In each recursive call, we loop through the unused numbers (by checking usedthe list), add them to curr, and add the corresponding index to used. Then, trackbackthe function is called recursively to continue generating the next number. The end condition of the recursion is currthat the length of is equal to numsthe length of the input array, indicating that a complete permutation has been generated.

  4. Backtracking: When recursion returns, we need to backtrack to the previous level of state. This involves removing the last currnumber added to and removing its corresponding index usedfrom so that other numbers can be tried on the next iteration.

  5. Result collection: Whenever we find a complete permutation, we add it to the result set and eventually return all permutations.

Java version solution ideas:

  1. Depth First Search (DFS): This solution also uses a depth first search algorithm to generate all possible permutations.

  2. DFS recursive function: In dfsthe function, we maintain three important parameters: numsan input array that pathstores the arrangement currently being generated, visitedand a Boolean array that marks which numbers have been used.

  3. Recursive process: In each recursive call, we loop through the unused numbers, add them to path, and mark them as used. Then, dfsthe function is called recursively to continue generating the next number. The end condition of the recursion is paththat the length of is equal to numsthe length of the input array, indicating that a complete permutation has been generated.

  4. Backtracking: When recursion returns, we need to backtrack to the previous level of state. This involves removing the last pathnumber added to and marking its corresponding index visitedas unused so that other numbers can be tried on the next iteration.

  5. Result collection: Whenever we find a complete permutation, we add it to the result set ( ans), eventually returning all permutations.

C++ version problem-solving ideas:

  1. Depth First Search (DFS): This solution also uses a depth first search algorithm to generate all possible permutations.

  2. DFS recursive function: In dfsthe function, we maintain four important parameters: numsan input array to currentPermutationstore the permutation currently being generated, visiteda Boolean array to mark which numbers have been used, and a boolean array ansto store the results of all permutations .

  3. Recursive process: In each recursive call, we loop through the unused numbers, add them to currentPermutation, and mark them as used. Then, dfsthe function is called recursively to continue generating the next number. The end condition of the recursion is currentPermutationthat the length of is equal to numsthe length of the input array, indicating that a complete permutation has been generated.

  4. Backtracking: When recursion returns, we need to backtrack to the previous level of state. This involves removing the last currentPermutationnumber added to and marking its corresponding index visitedas unused so that other numbers can be tried on the next iteration.

  5. Result collection: Whenever we find a complete permutation, we add it ansto and eventually return all permutations.

code

Go

func permute(nums []int) [][]int {
    var ans [][]int
    var dfs func(path []int, visited []bool)

    dfs = func(path []int, visited []bool) {
        if len(path) == len(nums) {
            temp := make([]int, len(path))
            copy(temp, path)
            ans = append(ans, temp)
            return
        }

        for i := 0; i < len(nums); i++ {
            if visited[i] {
                continue
            }
            path = append(path, nums[i])
            visited[i] = true
            dfs(path, visited)
            visited[i] = false
            path = path[:len(path)-1]
        }
    }

    visited := make([]bool, len(nums))
    dfs([]int{}, visited)
    return ans
}

Python

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        res = []
        self.trackback([], [], nums, res)
        return res
        
    def trackback(self, curr, used, nums, res):
        if len(curr) == len(nums):
            res.append(curr)
            return
        else:
            for i in range(len(nums)):
                if i not in used:
                    self.trackback(curr+[nums[i]], used+[i], nums, res)

Java

class Solution {
    List<List<Integer>> ans;  // 用于存储所有全排列的结果
    public List<List<Integer>> permute(int[] nums) {
        ans = new ArrayList<>();
        boolean[] visited = new boolean[nums.length];  // 用于标记数字是否已经被访问
        dfs(nums, new ArrayList<Integer>(), visited);  // 调用深度优先搜索函数
        return ans;  // 返回所有全排列的结果
    }

    public void dfs(int[] nums, List<Integer> path, boolean[] visited) {
        if (path.size() == nums.length) {  // 如果当前路径的长度等于数组长度,表示找到了一个全排列
            ans.add(new ArrayList<>(path));  // 将当前路径加入结果集
            return;  // 返回上一层继续搜索
        }

        for (int i = 0; i < nums.length; i++) {
            if (visited[i]) {
                continue;  // 如果数字已经被访问过,则跳过
            }
            path.add(nums[i]);  // 将数字加入当前路径
            visited[i] = true;  // 标记数字已经被访问
            dfs(nums, path, visited);  // 递归搜索下一层
            visited[i] = false;  // 恢复标记,以便尝试其他可能的数字
            path.remove(path.size() - 1);  // 移除最后一个数字,回溯到上一层状态
        }
    }
}

Cpp

class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> ans;
        vector<int> currentPermutation;
        vector<bool> visited(nums.size(), false);

        dfs(nums, currentPermutation, visited, ans);

        return ans;
    }

    void dfs(vector<int>& nums, vector<int>& currentPermutation, vector<bool>& visited, vector<vector<int>>& ans) {
        if (currentPermutation.size() == nums.size()) {
            ans.push_back(currentPermutation);
            return;
        }

        for (int i = 0; i < nums.size(); i++) {
            if (!visited[i]) {
                currentPermutation.push_back(nums[i]);
                visited[i] = true;
                dfs(nums, currentPermutation, visited, ans);
                visited[i] = false;
                currentPermutation.pop_back();
            }
        }
    }
};

Basic knowledge you need to master in each version:

Go version:

  1. Basic knowledge :

    • The basic syntax of Go language, including variables, functions, loops, conditional statements, etc.
    • Slice: Variable-length array in Go, used to dynamically store data.
    • Recursion: Understand the concept and use of recursion, as it is used here to generate full permutations.
  2. DFS (Depth First Search) :

    • Understand how the depth-first search algorithm works, a common approach to solving combination and permutation problems.
    • How state is maintained in recursive functions, including paths and access tokens.

Python version:

  1. Basic knowledge :

    • Python's basic syntax, including lists, loops, conditional statements, etc.
    • List: A mutable sequence in Python used to store multiple elements.
    • Recursion: Understand the concept and use of recursion, as it is used here to generate full permutations.
  2. DFS (Depth First Search) :

    • Understand how the depth-first search algorithm works, a common approach to solving combination and permutation problems.
    • How to maintain state in a recursive function, including the current arrangement, the list of used elements, etc.

Java version:

  1. Basic knowledge :

    • Basic syntax of Java language, including classes, methods, arrays, loops, conditional statements, etc.
    • List: A collection class in Java, used to store multiple elements.
    • Recursion: Understand the concept and use of recursion, as it is used here to generate full permutations.
  2. DFS (Depth First Search) :

    • Understand how the depth-first search algorithm works, a common approach to solving combination and permutation problems.
    • How to maintain state in a recursive function, including the current arrangement, a tagged array of used elements, etc.

C++ version:

  1. Basic knowledge :

    • Basic syntax of C++, including classes, functions, arrays, loops, conditional statements, etc.
    • Vector: A variable-length array in C++, used to store multiple elements.
    • Recursion: Understand the concept and use of recursion, as it is used here to generate full permutations.
  2. DFS (Depth First Search) :

    • Understand how the depth-first search algorithm works, a common approach to solving combination and permutation problems.
    • How to maintain state in a recursive function, including the current arrangement, a tagged array of used elements, etc.

Regardless of which version you choose, understanding the concepts of depth-first search and recursion is key. These code examples all show how to use depth-first search to solve permutation problems, where recursion is the core way of thinking. At the same time, it is also important to understand the syntax and data structures of each programming language, as they may be implemented differently in different languages.

47. Permutations II

topic

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

Example:

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

The general idea of ​​the topic

Given a sequence that may contain repeated numbers, return all non-repeating permutations.

Problem-solving ideas

  • This question is an enhanced version of question 46. In question 46, the arrangement of the array is found. The elements in the array are not repeated. However, in this question, the array elements are repeated, so the final arranged result needs to be deduplicated.
  • The method of deduplication is classic logic. After sorting the array, the duplicate elements are determined and then logical judgment is made.
  • The other ideas are exactly the same as question 46, just do a deep search with DFS.

Go version problem-solving ideas:

  1. Sorting array: First, sort the input integer array nums. This step is critical because it puts duplicate elements together to prepare for subsequent deduplication logic.

  2. Depth-first search (DFS): Uses a depth-first search algorithm to recursively generate permutations. From beginning to end, consider whether the elements in the array can be added to the current arrangement one by one.

  3. Deduplication logic: In the process of recursively generating an arrangement, it is necessary to determine whether the current element can be added to the arrangement to avoid duplication. If the current element is the same as the previous element and the previous element is not used, the current element is skipped to prevent repeated arrangement.

  4. Result Collection: Whenever a complete permutation is generated, it is added to the result set. Finally, the result set is returned.

Python version problem-solving ideas:

  1. Sorted array: Again, the input array of integers is first numssorted to handle duplicate elements.

  2. Depth-First Search (DFS): Uses a depth-first search algorithm to recursively generate permutations. During the recursive process, elements are continuously added to the current arrangement.

  3. Deduplication logic: In the process of recursively generating the arrangement, duplication is avoided by determining whether the element has been used and whether it is the same as the previous element and the previous element has not been used.

  4. Result collection: Whenever a complete permutation is generated, it is added to the results list. Finally, a list of results is returned.

Java version solution ideas:

  1. Sort Array: Sorts the input array of integers nums, which helps with duplicate elements.

  2. Depth-First Search (DFS): Uses a depth-first search algorithm to recursively generate permutations. During the recursive process, elements are continuously added to the current arrangement.

  3. Deduplication logic: In the process of recursively generating the arrangement, duplication is avoided by determining whether the element has been used and whether it is the same as the previous element and the previous element has not been used.

  4. Result collection: Whenever a complete permutation is generated, it is added to the results list. Finally, a list of results is returned.

C++ version problem-solving ideas:

  1. Sorted array: Again, the input array of integers numsis sorted to handle duplicate elements.

  2. Depth-First Search (DFS): Uses a depth-first search algorithm to recursively generate permutations. During the recursive process, elements are continuously added to the current arrangement.

  3. Deduplication logic: In the process of recursively generating the arrangement, duplication is avoided by determining whether the element has been used and whether it is the same as the previous element and the previous element has not been used.

  4. Result collection: Whenever a complete permutation is generated, it is added to the result vector. Finally, the resulting vector is returned.

In general, the problem-solving ideas of these four versions are based on depth-first search (DFS) and deduplication logic, which generate arrangements and avoid duplication by continuously adding and removing elements. Sorting the array is a key preprocessing step to ensure that the same elements are together for deduplication judgment. These ideas are general methods for solving permutation problems. When dealing with situations containing repeated elements, you need to be extra careful to remove duplicates.

code

Go

import "sort"

func permuteUnique(nums []int) [][]int {
    if len(nums) == 0 {
        return [][]int{}
    }
    used, p, res := make([]bool, len(nums)), []int{}, [][]int{}
    sort.Ints(nums) // 对输入数组进行排序,关键的去重逻辑
    generatePermutation47(nums, 0, p, &res, &used)
    return res
}

func generatePermutation47(nums []int, index int, p []int, res *[][]int, used *[]bool) {
    if index == len(nums) {
        temp := make([]int, len(p))
        copy(temp, p)
        *res = append(*res, temp) // 将当前排列添加到结果集中
        return
    }
    for i := 0; i < len(nums); i++ {
        if !(*used)[i] {
            if i > 0 && nums[i] == nums[i-1] && !(*used)[i-1] {
                continue // 关键的去重逻辑,跳过重复的数字
            }
            (*used)[i] = true // 标记当前数字已被使用
            p = append(p, nums[i]) // 将当前数字添加到排列中
            generatePermutation47(nums, index+1, p, res, used) // 递归生成下一个位置的排列
            p = p[:len(p)-1] // 回溯,移除当前数字
            (*used)[i] = false // 取消标记当前数字未被使用
        }
    }
    return
}

Python

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        def generatePermutation(nums, used, current, result):
            if len(current) == len(nums):
                result.append(current[:])
                return
            
            for i in range(len(nums)):
                if used[i] or (i > 0 and nums[i] == nums[i - 1] and not used[i - 1]):
                    continue
                
                used[i] = True
                current.append(nums[i])
                generatePermutation(nums, used, current, result)
                current.pop()
                used[i] = False
        
        nums.sort() # 对输入数组进行排序,关键的去重逻辑
        result = []
        used = [False] * len(nums)
        generatePermutation(nums, used, [], result)
        return result

Java

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

class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        if (nums == null || nums.length == 0) {
            return result;
        }
        
        Arrays.sort(nums); // 对输入数组进行排序,关键的去重逻辑
        boolean[] used = new boolean[nums.length];
        List<Integer> current = new ArrayList<>();
        
        generatePermutation(nums, used, current, result);
        
        return result;
    }
    
    private void generatePermutation(int[] nums, boolean[] used, List<Integer> current, List<List<Integer>> result) {
        if (current.size() == nums.length) {
            result.add(new ArrayList<>(current));
            return;
        }
        
        for (int i = 0; i < nums.length; i++) {
            if (used[i] || (i > 0 && nums[i] == nums[i - 1] && !used[i - 1])) {
                continue;
            }
            
            used[i] = true;
            current.add(nums[i]);
            generatePermutation(nums, used, current, result);
            current.remove(current.size() - 1);
            used[i] = false;
        }
    }
}

Cpp

class Solution {
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<vector<int>> result;
        if (nums.empty()) {
            return result;
        }
        
        sort(nums.begin(), nums.end()); // 对输入数组进行排序,关键的去重逻辑
        vector<bool> used(nums.size(), false);
        vector<int> current;
        
        generatePermutation(nums, used, current, result);
        
        return result;
    }
    
private:
    void generatePermutation(vector<int>& nums, vector<bool>& used, vector<int>& current, vector<vector<int>>& result) {
        if (current.size() == nums.size()) {
            result.push_back(current);
            return;
        }
        
        for (int i = 0; i < nums.size(); i++) {
            if (used[i] || (i > 0 && nums[i] == nums[i - 1] && !used[i - 1])) {
                continue;
            }
            
            used[i] = true;
            current.push_back(nums[i]);
            generatePermutation(nums, used, current, result);
            current.pop_back();
            used[i] = false;
        }
    }
};

Relevant basic knowledge points.

Go version:

  • Basic knowledge:
    • Go language basics: Be familiar with basic concepts such as Go syntax, data structures, slices, loops, and conditional statements.
    • Slices and Arrays: Learn the difference between slices and arrays in Go and how to use them.
    • Recursion: Understand the concept of recursion and how to implement recursive functions in Go.

Python version:

  • Basic knowledge:
    • Python basics: Master basic knowledge of Python's syntax, data types, lists, loops, conditional statements, etc.
    • Lists and Sets: Learn about list and set data structures in Python, along with their operations and properties.
    • Recursion: Understand the concept of recursion and how to implement recursive functions in Python.

Java version:

  • Basic knowledge:
    • Java basics: Familiar with basic knowledge of Java syntax, arrays, lists, loops, conditional statements, etc.
    • Lists and Sets: Learn about the List and Set data structures in Java and how to use them.
    • Recursion: Understand the concept of recursion and how to implement recursive methods in Java.

C++ version:

  • Basic knowledge:
    • C++ basics: Master basic concepts such as C++ syntax, arrays, vectors, loops, and conditional statements.
    • Vector: Learn about the vector data structure in C++ and how to use it to store and process data.
    • Recursion: Understand the concept of recursion and how to implement recursive functions in C++.

48. Rotate Image

topic

You are given an n x n 2D matrix representing an image.

Rotate the image by 90 degrees (clockwise).

Note:

You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation.

Example 1:

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

Example 2:

Given input matrix =
[
  [ 5, 1, 9,11],
  [ 2, 4, 8,10],
  [13, 3, 6, 7],
  [15,14,12,16]
], 

rotate the input matrix in-place such that it becomes:
[
  [15,13, 2, 5],
  [14, 3, 4, 1],
  [12, 6, 8, 9],
  [16, 7,10,11]
]

The general idea of ​​the topic

Given an n × n two-dimensional matrix representing an image. Rotate the image 90 degrees clockwise. Note: You must rotate the image in place, which means you need to modify the input 2D matrix directly. Please do not use another matrix to rotate the image.

Problem-solving ideas

  • Given a two-dimensional array, it is required to rotate 90 degrees clockwise.
  • This question is relatively simple, just follow the meaning of the question. Here are the implementations of two rotation methods, clockwise rotation and counterclockwise rotation.
    When solving the problem "Rotate Image", the problem-solving ideas in each version are basically the same, but the specific language syntax and operations are slightly different. Here are the problem-solving ideas for each version:

Go version problem-solving ideas

  1. Diagonal transformation : First, we perform a diagonal transformation, exchanging the elements in the matrix along the main diagonal (from the upper left corner to the lower right corner). This step actually rotates the matrix half way through 90 degrees clockwise.

  2. Vertical axis symmetry flip : Next, we perform a vertical axis symmetry flip for each row. This step will complete the remaining rotation of the matrix, making it 90 degrees clockwise.

Python version problem-solving ideas

The problem-solving ideas of the Python version are basically the same as the Go version, including two steps of diagonal transformation and vertical axis symmetry flipping.

Java version problem solving ideas

The problem-solving ideas of the Java version are also similar to the Go version:

  1. Diagonal transformation : First, we perform a diagonal transformation, exchanging the elements in the matrix according to the main diagonal.

  2. Vertical axis symmetry flip : Next, perform a vertical axis symmetry flip on each row to complete the remaining rotation of the matrix.

C++ version problem-solving ideas

The solution idea of ​​the C++ version is very similar to the Java version:

  1. Diagonal transformation : First, we perform a diagonal transformation, exchanging the elements in the matrix according to the main diagonal.

  2. Vertical axis symmetry flip : Then, perform a vertical axis symmetry flip for each row to complete the remaining rotation of the matrix.

In short, each version of the problem-solving idea follows the two steps of diagonal transformation and vertical axis symmetry flipping to achieve a 90-degree clockwise rotation of the matrix. If you have any questions about a specific version or need a more detailed explanation, please let me know.

code

Go

// 解法一
func rotate(matrix [][]int) {
    length := len(matrix) // 获取矩阵的长度

    // rotate by diagonal 对角线变换
    for i := 0; i < length; i++ { // 遍历行
        for j := i + 1; j < length; j++ { // 遍历列,从当前行的下一个元素开始
            matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j] // 交换矩阵[i][j]和矩阵[j][i]的值,实现对角线翻转
        }
    }

    // rotate by vertical centerline 竖直轴对称翻转
    for i := 0; i < length; i++ { // 遍历每一行
        for j := 0; j < length/2; j++ { // 遍历每一行的前一半列
            matrix[i][j], matrix[i][length-j-1] = matrix[i][length-j-1], matrix[i][j] // 交换矩阵[i][j]和矩阵[i][length-j-1]的值,实现竖直轴对称翻转
        }
    }
}

Python

class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        length = len(matrix)

        # rotate by diagonal 对角线变换
        for i in range(length):
            for j in range(i + 1, length):
                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]

        # rotate by vertical centerline 竖直轴对称翻转
        for i in range(length):
            for j in range(length // 2):
                matrix[i][j], matrix[i][length - j - 1] = matrix[i][length - j - 1], matrix[i][j]

Java

class Solution {
    public void rotate(int[][] matrix) {
        int length = matrix.length;

        // rotate by diagonal 对角线变换
        for (int i = 0; i < length; i++) {
            for (int j = i + 1; j < length; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }

        // rotate by vertical centerline 竖直轴对称翻转
        for (int i = 0; i < length; i++) {
            for (int j = 0; j < length / 2; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[i][length - j - 1];
                matrix[i][length - j - 1] = temp;
            }
        }
    }
}

Cpp

class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        length = len(matrix)

        # rotate by diagonal 对角线变换
        for i in range(length):
            for j in range(i + 1, length):
                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]

        # rotate by vertical centerline 竖直轴对称翻转
        for i in range(length):
            for j in range(length // 2):
                matrix[i][j], matrix[i][length - j - 1] = matrix[i][length - j - 1], matrix[i][j]

Go version

  1. Slice : In Go, a slice is a flexible data structure used to handle dynamic arrays. In this problem, we use slices to represent 2D matrices.

  2. Loops and Iteration : Go uses forloops to iterate over arrays and slices. Here, we use nested forloops to iterate over the rows and columns of the matrix.

  3. Swapping variable values : In Go, you can swap the values ​​of two variables through multiple assignment. This is the key to achieving matrix element exchange.

Python version

  1. List : In Python, we use lists to represent arrays or matrices. The matrix here is a two-dimensional list.

  2. Loops and Iteration : Python uses forloops to iterate over lists. In this problem, we use nested forloops to iterate over the rows and columns of the matrix.

  3. Multiple assignment : Python allows the use of multiple assignment to exchange the values ​​of two variables, which is useful for exchanging matrix elements.

Java version

  1. Two-dimensional array : Java uses two-dimensional array to represent matrices. In this problem, we represent the matrix as int[][]type.

  2. Nested Loops : Java uses nested forloops to traverse a two-dimensional array. The first loop is used to iterate over the rows and the second loop is used to iterate over the columns.

  3. Temporary variable : We use a temporary variable to store while exchanging the values ​​of two matrix elements.

C++ version

  1. Two-dimensional array : C++ also uses two-dimensional arrays to represent matrices. The type of matrix is vector<vector<int>>.

  2. Loops and Iteration : C++ uses forloops to iterate over vectors. Nested forloops are used to iterate over two-dimensional vectors.

  3. Temporary variable : Like Java, we use a temporary variable to exchange the values ​​of two matrix elements.

These are the basics required to solve this problem, including data structures and programming concepts such as loops, iteration, and variable manipulation. If you have any specific questions about these versions or need a more detailed explanation, please feel free to ask.

49. Group Anagrams

topic

Given an array of strings, group anagrams together.

Example:

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

Note:

  • All inputs will be in lowercase.
  • The order of your output does not matter.

The general idea of ​​the topic

Given a string array, it is required to group the strings with Anagrams relationships in the string array. The Anagrams relationship means that the characters of the two strings are exactly the same but in different orders. They are composed of permutations and combinations.

Problem-solving ideas

This question can sort each string. After the sorting is completed, strings with the same Anagrams will inevitably be sorted to the same result. Store the sorted strings as keys into the map
. After traversing the array, you can get a map. The key is the sorted string, and the value corresponds to the Anagrams string set after the sorted string.
Finally , output the string array corresponding to these values.
Of course, the following are the problem-solving ideas for each version:

Go version problem-solving ideas

  1. Create an empty map that groups strings with the same alphabetical composition.
  2. Create an empty result slice.
  3. Define an anonymous function signthat accepts a string as input and returns an identifier representing the letters of the string.
  4. Iterate over the input string array:
    • For each string, calculate its alphabetic identifier, signimplemented through an anonymous function.
    • Add the current string to a group of corresponding identifiers, organized using mappings.
  5. Iterate over each grouping in the map, convert the grouping to a slice, and add the slice to the resulting slice.
  6. Returns the final result slice, which contains strings grouped alphabetically.

Python version problem-solving ideas

  1. Create an empty dictionary that groups strings with the same alphabetical composition.
  2. Iterate over the input string list:
    • Sort each string into a tuple that will be used as a dictionary key.
    • If the key does not exist in the dictionary, an empty list is created as the value and the original string is added to the list.
    • If the key already exists in the dictionary, the original string is added to the list of corresponding keys.
  3. Converts a dictionary's values ​​(grouped) into a list and returns the result.

Java version problem solving ideas

  1. Create a map that groups strings with the same alphabetical composition. In Java, it is usually used HashMap.
  2. Iterate over the input string array:
    • Convert each string to a character array and sort the character array to form a sorted string.
    • Use the sorted string as the key of the map and the original string as the value to be stored in the map.
  3. Converts the groupings in the map to a list and returns the result.

C++ version problem-solving ideas

  1. Create a map (unordered_map) that groups strings with the same alphabetical composition.
  2. Iterate over the input string vector:
    • Sort each string to form a sorted string.
    • Use the sorted string as the key of the map and the original string as the value to be stored in the map.
  3. Converts mapped values ​​(groups) to vectors and returns the result.

Regardless of which version of the solution you use, the basic idea is to use a data structure (such as a map or dictionary) to organize and store strings with the same alphabetical composition and then group them together. Strings are sorted to ensure that
strings of the same Anagrams have the same identifier so that they are grouped correctly.

code

Go

func groupAnagrams(strs []string) [][]string {
    // 创建一个空的映射(map),用于将具有相同字母组成的字符串分组
    hashMap := map[string][]string{}
    // 创建一个空的结果切片(slice)
    res := [][]string{}

    // 定义一个匿名函数 sign,该函数接受一个字符串 s,并返回一个表示 s 字母组成的标识符
    sign := func(s string) string {
        // 创建一个长度为 26 的字节数组,用于统计每个字母出现的次数
        strB := [26]byte{}
        // 遍历字符串 s 中的每个字符
        for _, v := range s {
            // 将字符 v 转换为小写字母,并将对应字母的计数加一
            strB[v-'a']++
        }
        // 将字节数组转换为字符串并返回
        return string(strB[:])
    }

    // 遍历输入的字符串切片 strs
    for _, v := range strs {
        // 对当前字符串 v 计算其字母组成的标识符
        signV := sign(v)
        // 将当前字符串添加到对应标识符的分组中
        hashMap[signV] = append(hashMap[signV], v)
    }

    // 遍历映射中的每个分组,并将其添加到结果切片 res 中
    for _, v := range hashMap {
        res = append(res, v)
    }
    // 返回最终的结果切片,其中包含了按字母组成分组的字符串
    return res
}

Python

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        # 创建一个字典,用于将具有相同字母组成的字符串分组
        hashMap = {}

        # 遍历输入的字符串列表
        for str in strs:
            # 将字符串转换为排序后的元组,作为字典的键
            sorted_str = tuple(sorted(str))
            # 将原始字符串添加到对应键的列表中
            hashMap.setdefault(sorted_str, []).append(str)

        # 将字典的值(分组)转换为列表,并返回结果
        result = list(hashMap.values())
        return result

Java

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        // 创建一个映射,用于将具有相同字母组成的字符串分组
        Map<String, List<String>> hashMap = new HashMap<>();

        // 遍历输入的字符串数组
        for (String str : strs) {
            // 将字符串转换为字符数组,并排序
            char[] charArray = str.toCharArray();
            Arrays.sort(charArray);
            // 排序后的字符数组作为键,原始字符串作为值存入映射中
            String sortedStr = new String(charArray);
            if (!hashMap.containsKey(sortedStr)) {
                hashMap.put(sortedStr, new ArrayList<>());
            }
            hashMap.get(sortedStr).add(str);
        }

        // 将映射中的分组转换为列表
        List<List<String>> result = new ArrayList<>(hashMap.values());
        return result;
    }
}

Cpp

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        // 创建一个映射,用于将具有相同字母组成的字符串分组
        unordered_map<string, vector<string>> hashMap;
        
        // 遍历输入的字符串向量
        for (string str : strs) {
            // 将字符串排序,作为映射的键
            string sortedStr = str;
            sort(sortedStr.begin(), sortedStr.end());
            // 将原始字符串添加到对应键的向量中
            hashMap[sortedStr].push_back(str);
        }
        
        // 将映射的值(分组)转换为向量,并返回结果
        vector<vector<string>> result;
        for (auto& pair : hashMap) {
            result.push_back(pair.second);
        }
        return result;
    }
};

Required basics for each version:

Go version

  • Go language basics : Understand the basic syntax of Go language, including variable declaration, function definition, conditional statements, loops, etc.
  • Slices and Maps : Learn how to use slices and maps to work with collection data. In this solution, slicing and mapping are used to organize and store grouped
    Anagrams.
  • Anonymous Functions : Learn how to define anonymous functions, such as those in solutions sign.
  • Character Operations : Learn how to manipulate strings, including character traversal and comparison.

Python version

  • Python basics : Be familiar with the basic syntax of Python, including variables, lists, loops, conditional statements, etc.
  • Dictionaries and Lists : Learn how to use dictionaries and lists to work with collection data. In this solution, a dictionary is used to organize and store grouped
    Anagrams.
  • String operations : Familiar with the basic operations of Python strings, including string sorting.
  • Tuples : Learn how to use tuples, such as sorted string tuples in solutions.

Java version

  • Java Basics : Understand the basic syntax of Java, including class and method definitions, loops, conditional statements, etc.
  • Collections Framework : Learn about the Java Collections Framework, including the use of HashMapand ArrayList
    . In this solution, use HashMapto organize and store grouped Anagrams.
  • Character manipulation and sorting : Be familiar with character manipulation in Java, including converting strings into character arrays and sorting them.

C++ version

  • C++ Basics : Understand the basic syntax of C++, including variable declaration, function definition, loops, conditional statements, etc.
  • STL (Standard Template Library) : Familiar with C++ STL, including the use of unordered_mapand vector
    . In this solution, use unordered_mapto organize and store grouped Anagrams.
  • Character Manipulation and Sorting : Learn how to manipulate strings in C++, including sorting them.

No matter which language version you choose, basic programming knowledge, including mastery of basic syntax and data structure operations, is required to understand and modify these solutions. In addition, understanding the basic idea of ​​​​the algorithm will also be helpful in understanding these codes.

Guess you like

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