LeetCode Java Implementations

repository·master·Indexed 43 days ago

https://github.com/gaoshengnan/leetcode

A curated collection of Java-based implementations and theoretical explanations for data structures and algorithms. The repository covers foundational topics including Arrays, Linked Lists, Binary Trees, Dynamic Programming, and Greedy algorithms, providing solutions to high-frequency LeetCode problems to help developers prepare for technical interviews.

Tokens
9.3K
Snippets
8
Records
17
Agent score
54%

What's inside LeetCode

  1. Overview of the LeetCode Learning Repository

    master
    This repository is designed to help developers master data structures and algorithms to write more performant code and improve logical thinking. The learning path focuses on strengthening foundational data structure knowledge and deepening understanding through LeetCode algorithmic problems.
  2. Detect a cycle in a linked list

    master

    To determine if a singly linked list contains a cycle, you can use one of three primary approaches:

    1. Null Pointer Check: If the list is linear and has no cycle, the last node's next pointer will eventually point to null. If it never reaches null, a cycle exists.
    2. Hash Set Approach: Traverse the list and store each visited node's pointer in a Set. If you encounter a node that is already present in the Set, a cycle is detected.
    3. Fast and Slow Pointers (Floyd's Cycle-Finding Algorithm): Use two pointers starting at the same node. The fast pointer moves two steps at a time, while the low (slow) pointer moves one step at a time.
      • If there is no cycle, the fast pointer will reach null.
      • If there is a cycle, the fast pointer will eventually enter the loop and catch up to the low pointer (they will meet at the same node).
  3. Understand the 0-1 Knapsack Problem

    master
    The 0-1 Knapsack problem is a classic optimization problem where you have a backpack with a maximum weight capacity bw and n items, each with a specific weight. The goal is to select a subset of items such that their total weight does not exceed bw and the total weight is maximized. The '0-1' designation means items are indivisible: you either include an item in its entirety (1) or you do not (0).
  4. Understand the Frog Jump Problem (LeetCode 70)

    master

    This problem is a classic application of recursive thinking.

    Problem Statement: A frog can jump either 1 step or 2 steps at a time. Given a staircase with n steps, calculate the total number of distinct ways the frog can reach the top.

    Core Concept: This is a combinatorial problem that can be modeled using recursion or dynamic programming. The number of ways to reach step n is the sum of the ways to reach step n-1 (by taking a 1-step jump) and the ways to reach step n-2 (by taking a 2-step jump). This follows the Fibonacci sequence pattern.

  5. Understand Reverse Nodes in k-Group

    master

    The 'Reverse Nodes in k-Group' problem involves reversing a linked list in segments of size k. If the number of nodes remaining is less than k, those nodes should remain in their original order.

    Logic Overview

    1. Identify Segments: Iterate through the list using a pointer (cur) and a counter (count) to find segments of length k.
    2. Reverse Segment: Once k nodes are identified, use a reversal method (similar to reversing a standard singly linked list) to flip the direction of the pointers within that segment.
    3. Reconnect Segments:
      • Connect the tail of the previously reversed segment to the head of the newly reversed segment.
      • Connect the tail of the newly reversed segment to the start of the next segment.
    4. Handle the Head: Maintain a reference to the new head of the entire list (the head of the first reversed segment) to return it at the end.

    For the complete implementation, refer to ReverseNodesInkGroup.java in the same directory.

  6. Reverse a Singly Linked List using Iteration

    master

    To reverse a singly linked list, use an iterative approach with three pointers: pre (previous), cur (current), and next (temporary storage for the next node).

    Implementation Steps

    1. Edge Case Check: If the head is null or head.next is null, the list is empty or has only one node. Return head immediately.
    2. Pointer Initialization:
      • pre: Initialized to null (this will become the new tail).
      • cur: Initialized to head (the starting point of traversal).
    3. Iteration Loop: While cur is not null, perform the following four steps in order:
      • Store Next: Save the next node to prevent losing the reference: ListNode next = cur.next;
      • Reverse Pointer: Point the current node's next reference to the previous node: cur.next = pre;
      • Advance Previous: Move the pre pointer forward to the current node: pre = cur;
      • Advance Current: Move the cur pointer forward to the saved next node: cur = next;
    4. Return: Once the loop finishes, pre will point to the new head of the reversed list.

    Key Concept: Assignment vs. Reference

    • next = cur.next: Assigns the value of the next node to a temporary variable.
    • cur.next = pre: Assigns the reference of the pre node to the cur.next pointer, effectively reversing the direction.
  7. Solve 0-1 Knapsack using Backtracking and Memoized Recursion

    master

    This approach treats the problem as $n$ decision stages. For each item, you have two choices: include it or exclude it. To avoid redundant calculations in the resulting recursion tree, use a memoization table mem[i][curLoadSum] to store whether a specific state (current item index and current total weight) has already been visited.

    Key logic:

    • Base Case: If the current weight equals bw or all items have been considered, update the maximum weight found.
    • Pruning: If adding an item would exceed bw, do not proceed with that branch.
    • Memoization: Check mem[i][curLoadSum] before proceeding to avoid re-calculating known states.
    /**
         * 解法1 回溯 + 记忆化递归
         *
         * @param i: 考察到哪个物品
         * @param curLoadSum: 当前已经装进去的物品的重量和
         * @param n:物品个数
         * @param bpWeight:背包可承受重量
         */
        private void f(int i, int curLoadSum, int n, int bpWeight) {
            if (curLoadSum == bw || i == n) {
                maxW = Math.max(maxW, curLoadSum);
                return;
            }
            if (mem[i][curLoadSum]) return;
            mem[i][curLoadSum] = true;
            f(i + 1, curLoadSum, n, bpWeight); // 不装第 i 件物品
            if (curLoadSum + weights[i] <= bw) // 剪枝
                f(i + 1, curLoadSum + weights[i], n, bpWeight); // 装第 i 件物品
        }
  8. Solve the 0/1 Knapsack Problem using Backtracking and Dynamic Programming

    master

    The repository provides detailed guides on solving the classic 0/1 Knapsack problem using two primary algorithmic approaches:

    1. Backtracking: An exhaustive search approach.
    2. Dynamic Programming: An optimized approach for solving subproblems.

    You can find the implementation details and theoretical explanations in the dedicated documentation file.

    https://github.com/gaoshengnan/LeetCode/blob/master/src/main/java/theoreticalBasis/%E8%83%8C%E5%8C%85/backpack.md
  9. Explore Theoretical Foundations of Data Structures and Algorithms

    master

    The repository provides structured theoretical knowledge across several key areas. You can study these topics to build a strong foundation before tackling complex algorithmic problems. The topics are categorized into Data Structures and Algorithmic Paradigms/Analysis.

    ### Theoretical Foundations
    
    **Data Structures:**
    - Array (数组)
    - Linked List (链表)
    - Stack (栈)
    - Skip List (跳表)
    - Hash Table (散列表)
    - Binary Tree (二叉树)
    
    **Algorithms & Analysis:**
    - Greedy (贪心)
    - Divide and Conquer (分治)
    - Backtracking (回溯)
    - Dynamic Programming (动态规划)
    - Recursion (递归)
    - Complexity Analysis (复杂度分析)
  10. Find the entry point of a linked list cycle (LeetCode 142)

    master

    This guide explains the mathematical approach to solving LeetCode 142: finding the specific node where a cycle begins in a linked list.

    Algorithm Logic

    1. Detect the Cycle: Use two pointers, fast (moves two steps) and low (moves one step). If they meet, a cycle exists.
    2. Calculate the Entry Point:
      • Let $x$ be the distance from the start node to the cycle entry point.
      • Let $y$ be the distance from the entry point to the meeting point.
      • Let $z$ be the distance from the meeting point back to the entry point.
      • Based on the relationship between these distances, once the pointers meet, resetting one pointer to the start node and moving both pointers one step at a time will result in them meeting exactly at the cycle's entry point.

    Implementation Strategy

    • Start fast and low at the head.
    • Move fast by 2 and low by 1 until they meet.
    • If they meet, reset fast to the head node.
    • Move both fast and low by 1 step at a time. The node where they meet is the entry point of the cycle.
  11. Review high-frequency LeetCode problems by category

    master

    This repository provides a curated list of high-frequency and classic LeetCode algorithm problems categorized by data structure and algorithmic technique. Each entry includes the problem number, difficulty level, a link to the problem on LeetCode, and a link to the Java solution within this repository.

    Categories include:

    • Array
    • Linked List
    • Binary Tree
    • Divide and Conquer (分治)
    • Binary Search (二分查找)
    • Union Find (并查集)
    • Traversal and Search (遍历和搜索)
    • Dynamic Programming (动态规划)
    • Pruning (剪枝)
    • Greedy (贪心)
    • Trie Tree (trie 树)
    • Bit Manipulation (位运算)
    • LRU Cache
  12. Solve 0-1 Knapsack using Dynamic Programming

    master

    Dynamic Programming (DP) solves the problem by tracking all possible reachable weights at each stage (each item).

    Implementation Details:

    1. Use a 2D boolean array s[n][bw + 1] where s[i][j] is true if weight j can be achieved using a subset of the first i items.
    2. Initialization: Set s[0][0] = true (not picking the first item) and, if the first item's weight is $\le$ bw, set s[0][weights[0]] = true (picking the first item).
    3. Transitions: For each subsequent item i:
      • Exclude item i: Carry over all reachable weights from the previous stage: s[i][j] = s[i-1][j].
      • Include item i: For every weight j reachable in the previous stage, mark j + weights[i] as reachable in the current stage, provided it doesn't exceed bw.
    4. Result: After processing all items, iterate backwards from bw to 0 in the last row of the DP table. The first index i where s[n-1][i] is true is the maximum weight.
    /**
         * 解法2 动态规划
         *
         * @param n:物品个数
         * @param bw: 当前已经装进去的物品的重量和
         * @return 最大可以装多少重量
         */
        private int dpBackpack (int n, int bw) {
            boolean[][] s = new boolean[n][bw + 1];
            s[0][0] = true;
            if (weights[0] <= bw) s[0][weights[0]] = true;
            for (int i = 1; i < n; i++) {
                for (int j = 0; j <= bw ; j++) {
                    if (s[i - 1][j]) s[i][j] = s[i - 1][j];
                }
                for (int j = 0; j <= bw - weights[i]; j++) {
                    if (s[i - 1][j]) s[i][j + weights[i]] = true;
                }
            }
    
            for (int i = bw; i >= 0; i--) {
                if (s[n - 1][i]) return i;
            }
            return 0;
        }