LeetCode Java Implementations
repository·master·Indexed 43 days ago
https://github.com/gaoshengnan/leetcodeA 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.
What's inside LeetCode
- 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.
Detect a cycle in a linked list
masterTo determine if a singly linked list contains a cycle, you can use one of three primary approaches:
- Null Pointer Check: If the list is linear and has no cycle, the last node's
nextpointer will eventually point tonull. If it never reachesnull, a cycle exists. - 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 theSet, a cycle is detected. - Fast and Slow Pointers (Floyd's Cycle-Finding Algorithm): Use two pointers starting at the same node. The
fastpointer moves two steps at a time, while thelow(slow) pointer moves one step at a time.- If there is no cycle, the
fastpointer will reachnull. - If there is a cycle, the
fastpointer will eventually enter the loop and catch up to thelowpointer (they will meet at the same node).
- If there is no cycle, the
- Null Pointer Check: If the list is linear and has no cycle, the last node's
Understand the 0-1 Knapsack Problem
masterThe 0-1 Knapsack problem is a classic optimization problem where you have a backpack with a maximum weight capacitybwandnitems, each with a specific weight. The goal is to select a subset of items such that their total weight does not exceedbwand 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).Understand the Frog Jump Problem (LeetCode 70)
masterThis 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
nsteps, 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
nis the sum of the ways to reach stepn-1(by taking a 1-step jump) and the ways to reach stepn-2(by taking a 2-step jump). This follows the Fibonacci sequence pattern.Understand Reverse Nodes in k-Group
masterThe 'Reverse Nodes in k-Group' problem involves reversing a linked list in segments of size
k. If the number of nodes remaining is less thank, those nodes should remain in their original order.Logic Overview
- Identify Segments: Iterate through the list using a pointer (
cur) and a counter (count) to find segments of lengthk. - Reverse Segment: Once
knodes are identified, use a reversal method (similar to reversing a standard singly linked list) to flip the direction of the pointers within that segment. - 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.
- 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.javain the same directory.- Identify Segments: Iterate through the list using a pointer (
Reverse a Singly Linked List using Iteration
masterTo reverse a singly linked list, use an iterative approach with three pointers:
pre(previous),cur(current), andnext(temporary storage for the next node).Implementation Steps
- Edge Case Check: If the
headisnullorhead.nextisnull, the list is empty or has only one node. Returnheadimmediately. - Pointer Initialization:
pre: Initialized tonull(this will become the new tail).cur: Initialized tohead(the starting point of traversal).
- Iteration Loop: While
curis notnull, 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
prepointer forward to the current node:pre = cur; - Advance Current: Move the
curpointer forward to the saved next node:cur = next;
- Store Next: Save the next node to prevent losing the reference:
- Return: Once the loop finishes,
prewill 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 theprenode to thecur.nextpointer, effectively reversing the direction.
- Edge Case Check: If the
Solve 0-1 Knapsack using Backtracking and Memoized Recursion
masterThis 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
bwor 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 件物品 }- Base Case: If the current weight equals
Solve the 0/1 Knapsack Problem using Backtracking and Dynamic Programming
masterThe repository provides detailed guides on solving the classic 0/1 Knapsack problem using two primary algorithmic approaches:
- Backtracking: An exhaustive search approach.
- 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.mdExplore Theoretical Foundations of Data Structures and Algorithms
masterThe 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 (复杂度分析)Find the entry point of a linked list cycle (LeetCode 142)
masterThis guide explains the mathematical approach to solving LeetCode 142: finding the specific node where a cycle begins in a linked list.
Algorithm Logic
- Detect the Cycle: Use two pointers,
fast(moves two steps) andlow(moves one step). If they meet, a cycle exists. - 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
fastandlowat the head. - Move
fastby 2 andlowby 1 until they meet. - If they meet, reset
fastto the head node. - Move both
fastandlowby 1 step at a time. The node where they meet is the entry point of the cycle.
- Detect the Cycle: Use two pointers,
Review high-frequency LeetCode problems by category
masterThis 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
Solve 0-1 Knapsack using Dynamic Programming
masterDynamic Programming (DP) solves the problem by tracking all possible reachable weights at each stage (each item).
Implementation Details:
- Use a 2D boolean array
s[n][bw + 1]wheres[i][j]istrueif weightjcan be achieved using a subset of the firstiitems. - Initialization: Set
s[0][0] = true(not picking the first item) and, if the first item's weight is $\le$bw, sets[0][weights[0]] = true(picking the first item). - 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 weightjreachable in the previous stage, markj + weights[i]as reachable in the current stage, provided it doesn't exceedbw.
- Exclude item
- Result: After processing all items, iterate backwards from
bwto0in the last row of the DP table. The first indexiwheres[n-1][i]istrueis 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; }- Use a 2D boolean array