LeetCode-Master Study Plan

repository·master·Indexed 13 days ago

https://github.com/youngyangyang04/leetcode-master

A structured, step-by-step roadmap for mastering data structures and algorithms. The guide provides a logical progression from basic topics like Arrays and Linked Lists to advanced concepts like Dynamic Programming and Graph Theory, featuring theoretical foundations, problem sets, and multi-language implementations in C++, Java, Python, Go, and JS.

Tokens
418.3K
Snippets
898
Records
969
Agent score
96%

What's inside LeetCode-Master

  1. Overview of LeetCode-Master Study Plan

    master
    LeetCode-Master is a systematic, step-by-step study plan designed to help developers master data structures and algorithms. The repository provides a structured learning path where problems are ordered by knowledge context and difficulty. Each problem is accompanied by text-and-image solutions and video explanations. It is suitable for learners moving from zero knowledge to advanced levels.
  2. Design a Linked List (LeetCode 707)

    master

    This problem requires implementing a linked list class with five core operations: retrieving a value at a specific index, adding nodes at the head, adding nodes at the tail, adding nodes at a specific index, and deleting a node at a specific index.

    Key requirements:

    • get(index): Returns the value at index. Returns -1 if the index is invalid.
    • addAtHead(val): Inserts a new node with val at the beginning.
    • addAtTail(val): Appends a new node with val to the end.
    • addAtIndex(index, val): Inserts val before the index-th node. If index equals the list length, append to the end. If index > length, do nothing. If index < 0, insert at the head.
    • deleteAtIndex(index): Removes the node at index if the index is valid.

    Complexity:

    • Time Complexity: Operations involving index are $O(index)$; others are $O(1)$.
    • Space Complexity: $O(n)$ to store $n$ nodes.
  3. Solve LeetCode 17: Letter Combinations of a Phone Number

    master

    This problem asks to return all possible letter combinations that a string of digits (2-9) can represent, based on a phone keypad mapping.

    Key Constraints & Logic:

    • Input: A string containing digits 2-9.
    • Output: A list of all possible letter combinations.
    • Mapping: Use a fixed mapping where 2='abc', 3='def', etc. Note that 1 does not map to any letters.
    • Complexity:
      • Time Complexity: $O(3^m \times 4^n)$, where $m$ is the count of digits mapping to 3 letters and $n$ is the count of digits mapping to 4 letters.
      • Space Complexity: $O(3^m \times 4^n)$.
  4. Explore the LeetCode Problem Roadmap

    master

    The leetcode-master repository provides a structured learning path for algorithm practice, organized by topic and optimized according to the learning curve. The roadmap is divided into several major categories, including:

    • Prerequisites (前序): Algorithm performance analysis (Time/Space complexity, memory usage) and AI tool integration.
    • Data Structures: Arrays (数组), Linked Lists (链表), Hash Tables (哈希表), Stacks & Queues (栈与队列), and Monotonic Stacks (单调栈).
    • Algorithms: String manipulation (字符串), Two Pointers (双指针法), Binary Trees (二叉树), Backtracking (回溯算法), Greedy Algorithms (贪心算法), Dynamic Programming (动态规划), and Graph Theory (图论).

    Each topic contains theoretical foundations, specific LeetCode problems, and summary guides to consolidate knowledge.

  5. Optimize DFS by 'Drowning' the Island

    master

    Instead of using a separate visited array, you can optimize space by 'drowning' the island. When a cell with value 1 is encountered, perform a DFS and set the value of each visited cell in the grid to 0. This prevents the same island from being counted multiple times and eliminates the need for an auxiliary boolean array.

    // DFS Optimization: Drowning the island
    public int maxAreaOfIsland(int[][] grid) {
        int res = 0;
        for(int i = 0;i < grid.length;i++){
            for(int j = 0; j < grid[0].length;j++){
                if(grid[i][j] == 1){
                    res = Math.max(res, dfs(grid, i, j));
                }
            }
        }
        return res;
    }
    
    public int dfs(int[][] grid, int i, int j){
        if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == 0) return 0;
        grid[i][j] = 0; // Drown the land
        return 1 + dfs(grid, i - 1, j) + 
                   dfs(grid, i + 1, j) + 
                   dfs(grid, i, j + 1) + 
                   dfs(grid, i, j - 1);
    }
  6. Solve Sudoku using 2D Backtracking

    master

    To solve a Sudoku puzzle, use a 2D backtracking approach (also referred to as 2D recursion). Unlike standard 1D backtracking (like permutations or combinations), this method involves nested loops to traverse both rows and columns to find empty cells ('.') and then recursively attempting to place digits '1'-'9' in those cells.

    Core Logic: The Backtracking Three-Step

    1. Recursive Function and Parameters: The function should return a bool type. This allows the algorithm to immediately stop and return true once a valid complete solution is found at a leaf node of the recursion tree.
      • Signature: bool backtracking(vector<vector<char>>& board)
    2. Termination Condition: This specific implementation does not use an explicit termination condition. Instead, it relies on the fact that as numbers are filled, the board eventually becomes full. If a cell is processed and all 9 digits fail the validity check, the function returns false to trigger backtracking.
    3. Single-Layer Search Logic:
      • Iterate through rows using a for loop.
      • Iterate through columns using a for loop.
      • If a cell board[i][j] is not '.', skip it.
      • If it is '.', iterate through characters '1' to '9'.
      • Check if the digit is valid using isValid().
      • If valid, place the digit, recurse, and if the recursion returns true, propagate true upwards. If not, reset the cell to '.' (backtrack).
    bool backtracking(vector<vector<char>>& board) {
        for (int i = 0; i < board.size(); i++) {
            for (int j = 0; j < board[0].size(); j++) {
                if (board[i][j] == '.') {
                    for (char k = '1'; k <= '9'; k++) {
                        if (isValid(i, j, k, board)) {
                            board[i][j] = k;
                            if (backtracking(board)) return true;
                            board[i][j] = '.';
                        }
                    }
                    return false;
                }
            }
        }
        return true;
    }
  7. Solve LeetCode 743: Network Delay Time

    master

    The problem asks for the minimum time required for a signal sent from node K to reach all n nodes in a directed graph. You are given a list of times where each element is (ui, vi, wi) representing a directed edge from ui to vi with weight wi. If not all nodes can be reached, return -1.

    /* 
    Problem Constraints:
    1 <= k <= n <= 100
    1 <= times.length <= 6000
    1 <= ui, vi <= n
    0 <= wi <= 100
    */
  8. Master Dynamic Programming (DP) Sub-topics

    master

    The Dynamic Programming section is highly granular, categorized into specific patterns to help you recognize problem types:

    • Basic DP: Fibonacci numbers, climbing stairs, and different paths.
    • Knapsack Problems (背包问题): 0/1 Knapsack (using 1D or 2D arrays), Complete Knapsack, and Multiple Knapsack.
    • House Robber Series (打家劫舍): Variations of the house robber problem.
    • Stock Series (股票系列): Best time to buy/sell stocks with various constraints (cooldowns, transaction fees, etc.).
    • Subsequence Series (子序列系列): Longest Increasing Subsequence, Longest Common Subsequence, Edit Distance, and Palindromic Substrings.

    Each sub-category includes theoretical foundations and summary guides.

  9. Solve Max Area of Island using DFS (Two Patterns)

    master

    To find the maximum area of an island in a binary matrix, you can use Depth First Search (DFS). The problem requires counting connected 1s (land) in four directions (horizontal and vertical).

    There are two common patterns for implementing DFS in this context:

    1. Pattern 1: DFS handles neighbors. The main loop identifies a land cell, increments the count to 1, and then calls DFS to process all subsequent adjacent land cells.
    2. Pattern 2: DFS handles the current node. The main loop identifies a land cell but sets the initial count to 0. The DFS function is responsible for marking the current node as visited, incrementing the count, and then exploring neighbors.
    // Pattern 1: DFS handles neighbors
    // Main loop: count = 1; dfs(grid, visited, i, j);
    void dfs(vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y) {
        for (int i = 0; i < 4; i++) {
            int nextx = x + dir[i][0];
            int nexty = y + dir[i][1];
            if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;
            if (!visited[nextx][nexty] && grid[nextx][nexty] == 1) {
                visited[nextx][nexty] = true;
                count++;
                dfs(grid, visited, nextx, nexty);
            }
        }
    }
    
    // Pattern 2: DFS handles current node
    // Main loop: count = 0; dfs(grid, visited, i, j);
    void dfs(vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y) {
        if (visited[x][y] || grid[x][y] == 0) return;
        visited[x][y] = true;
        count++;
        for (int i = 0; i < 4; i++) {
            int nextx = x + dir[i][0];
            int nexty = y + dir[i][1];
            if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;
            dfs(grid, visited, nextx, nexty);
        }
    }
  10. Solve Palindrome Partitioning II using Dynamic Programming

    master

    To find the minimum number of cuts required to partition a string s such that every substring is a palindrome, use a two-step Dynamic Programming approach.

    1. Precompute Palindromes

    Create a 2D boolean array isPalindromic[i][j] where isPalindromic[i][j] is true if the substring from index i to j is a palindrome.

    • Base Case: If s[i] == s[j] and the distance between i and j is $\le 1$, it is a palindrome.
    • Recursive Step: If s[i] == s[j] and isPalindromic[i+1][j-1] is true, it is a palindrome.

    2. Compute Minimum Cuts

    Use a 1D DP array dp[i] representing the minimum cuts for the substring s[0...i].

    • Initialization: dp[0] = 0. For $i > 0$, initialize dp[i] to its maximum possible value (either i or INT_MAX).
    • Transition: For each i from $1$ to $n-1$:
      • If isPalindromic[0][i] is true, dp[i] = 0.
      • Otherwise, iterate through all possible split points j from $0$ to $i-1$. If isPalindromic[j+1][i] is true, update dp[i] = min(dp[i], dp[j] + 1).

    Complexity:

    • Time: $O(n^2)$
    • Space: $O(n^2)$ to store the isPalindromic table.
    class Solution {
    public:
        int minCut(string s) {
            int n = s.size();
            vector<vector<bool>> isPalindromic(n, vector<bool>(n, false));
            for (int i = n - 1; i >= 0; i--) {
                for (int j = i; j < n; j++) {
                    if (s[i] == s[j] && (j - i <= 1 || isPalindromic[i + 1][j - 1])) {
                        isPalindromic[i][j] = true;
                    }
                }
            }
    
            vector<int> dp(n);
            for (int i = 0; i < n; i++) dp[i] = i;
    
            for (int i = 1; i < n; i++) {
                if (isPalindromic[0][i]) {
                    dp[i] = 0;
                    continue;
                }
                for (int j = 0; j < i; j++) {
                    if (isPalindromic[j + 1][i]) {
                        dp[i] = min(dp[i], dp[j] + 1);
                    }
                }
            }
            return dp[n - 1];
        }
    };