How the leetcode‑master Repository Handles Edge Cases in Two‑Pointer Technique Problems

The leetcode‑master repository eliminates null‑pointer dereferences, duplicate counting, and off‑by‑one errors through a systematic workflow of sentinel initialization, pointer offset establishment, and synchronized traversal with duplicate‑skipping guards.

The leetcode‑master collection by youngyangyang04 treats two‑pointer solutions as a reusable architectural pattern rather than isolated algorithms. By examining the implementations in problems/0015.三数之和.md, problems/0019.删除链表的倒数第N个节点.md, and related files, we can extract a rigorous methodology for handling edge cases in two‑pointer technique problems. This approach guarantees O(1) extra space while safely managing empty inputs, boundary deletions, and duplicate elements.

The Five‑Step Edge‑Case Safety Workflow

Every two‑pointer solution in the repository follows a predictable lifecycle that hardens the algorithm against common failure modes.

Step 1: Sentinel Node Initialization for Linked Lists

When the data structure is a linked list, the code creates a dummy head node (sentinel) that points to the real head. This guarantees the slow pointer can always reference the node preceding the deletion target, even when the head itself must be removed.

In problems/0019.删除链表的倒数第N个节点.md, the implementation constructs ListNode dummy(0, head) before establishing the fast and slow pointers. This pattern eliminates special‑case branching for empty lists, single‑node lists, or when n equals the list length.

Step 2: Pointer Offset Establishment

The repository enforces a strict distance invariant between pointers before the main traversal begins. For the “remove nth node” pattern, the fast pointer advances n + 1 steps ahead of the slow pointer.

ListNode* fast = &dummy;
ListNode* slow = &dummy;
for (int i = 0; i <= n; ++i) fast = fast->next;

This offset ensures that when fast reaches NULL, slow points to the node immediately before the target, preventing off‑by‑one errors and null‑dereference crashes when deleting the final element.

Step 3: Synchronized Traversal Until Terminus

Both pointers advance in lockstep (while (fast) { fast = fast->next; slow = slow->next; }) until the fast pointer exits the container. This linear‑time scan handles arrays with single elements, already‑sorted inputs, and cases where the answer resides at either end.

For array problems like Three Sum in problems/0015.三数之和.md, the repository uses left and right pointers that converge toward the center, skipping duplicate values immediately after recording a valid result.

Step 4: Mutation or Computation

With the slow pointer (or left/right pointers) positioned safely, the algorithm performs the final update. In linked list deletion, slow->next is rewired; in the Trapping Rain Water problem (problems/0042.接雨水.md), the code calculates water volume using leftMax and rightMax invariants that correctly yield zero for monotonic or all‑zero height arrays.

Step 5: Optional Cleanup

For languages without garbage collection, the repository explicitly deletes detached nodes to prevent memory leaks, satisfying strict O(1) space constraints required by two‑pointer problem specifications.

Specific Edge‑Case Strategies by Problem

Duplicate Elimination in Three Sum (0015)

The Three Sum implementation handles the [0,0,0,0] edge case by advancing pointers past duplicate values immediately after finding a valid triplet.

while (left < right && nums[left]  == nums[left  + 1]) ++left;
while (left < right && nums[right] == nums[right - 1]) --right;
++left; --right;

The outer loop also contains an early termination guard—if (nums[i] > 0) break;—that stops processing when all remaining numbers are positive, preventing unnecessary iterations on large sorted arrays.

Head Deletion in Remove Nth Node (0019)

When n equals the list length, the node to delete is the head. The dummy node ensures slow remains on the sentinel, allowing slow->next = slow->next->next to remove the real head without conditional branches. For single‑node lists where n == 1, the fast pointer becomes NULL after the initial n+1 advances, the while‑loop is skipped, and the dummy’s next pointer is safely set to NULL.

Monotonic Sequences in Trapping Rain Water (0042)

The two‑pointer variant maintains leftMax and rightMax heights. When one side is lower, its pointer moves inward and the contribution is calculated as max(0, maxHeight - currentHeight). This logic correctly returns 0 for strictly increasing or decreasing sequences, as well as for arrays containing all zeros, without additional checks.

Empty Input Guards

In problems/0206.翻转链表.md (Reverse Linked List), the function checks if (!head) return nullptr; before entering the reversal loop. Similarly, problems/0028.实现strStr.md returns 0 immediately for an empty needle and handles the needle.size() > haystack.size() case by limiting the loop range to haystack.size() - needle.size() + 1, returning -1 when the range is negative.

Canonical Implementation Templates

The following C++ templates embody the repository’s defensive programming style for array and linked list scenarios.

Array Two‑Pointer Skeleton

class Solution {
public:
    vector<vector<int>> twoPointerTemplate(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        int left = 0;
        int right = static_cast<int>(nums.size()) - 1;
        
        while (left < right) {
            int sum = nums[left] + nums[right];
            if (sum == target) {
                ans.push_back({nums[left], nums[right]});
                
                // Skip duplicates to avoid double counting
                while (left < right && nums[left] == nums[left + 1]) ++left;
                while (left < right && nums[right] == nums[right - 1]) --right;
                
                ++left;
                --right;
            } else if (sum < target) {
                ++left;
            } else {
                --right;
            }
        }
        return ans;
    }
};

Linked List Fast‑Slow Skeleton

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode dummy(0, head);
        ListNode* fast = &dummy;
        ListNode* slow = &dummy;
        
        // Advance fast n+1 steps to create the offset
        for (int i = 0; i <= n; ++i) {
            fast = fast->next;
        }
        
        // Move both until fast reaches the end
        while (fast) {
            fast = fast->next;
            slow = slow->next;
        }
        
        // Safe deletion guaranteed by sentinel
        ListNode* toDelete = slow->next;
        slow->next = slow->next->next;
        delete toDelete;  // For non-GC languages
        return dummy.next;
    }
};

Summary

  • Sentinel nodes in linked list problems eliminate special‑case code for head deletion and empty inputs.
  • Pointer offset initialization (n + 1 steps) guarantees the slow pointer lands on the node preceding the target, preventing off‑by‑one errors.
  • Duplicate‑skipping loops immediately after matches ensure unique results in problems like Three Sum.
  • Early termination guards (e.g., if (nums[i] > 0) break) prevent unnecessary computation on sorted data.
  • Invariant maintenance (leftMax/rightMax, pointer distance) allows the algorithm to handle monotonic sequences and all‑zero inputs without branching logic.

Frequently Asked Questions

Why does leetcode‑master use a dummy head node in linked list two‑pointer problems?

The dummy head node acts as a sentinel that ensures the slow pointer always points to a valid node preceding the deletion target. According to the source code in problems/0019.删除链表的倒数第N个节点.md, this pattern removes the need for conditional branches when deleting the first node or handling single‑node lists, preventing null‑pointer dereferences.

How does the repository prevent duplicate triplets in the Three Sum problem?

After finding a valid triplet in problems/0015.三数之和.md, the algorithm advances the left pointer past all identical values using a while (left < right && nums[left] == nums[left + 1]) ++left; loop, and similarly for the right pointer. This guarantees that [0,0,0,0] produces only one unique result rather than four.

What prevents off‑by‑one errors when removing the nth node from the end?

The repository establishes a strict invariant by advancing the fast pointer n + 1 steps ahead of the slow pointer before the traversal loop begins. As implemented in problems/0019.删除链表的倒数第N个节点.md, this ensures that when the fast pointer reaches NULL, the slow pointer references the node immediately before the target, allowing safe removal without indexing errors.

How are empty inputs handled in two‑pointer implementations?

The repository places explicit guards at function entry points. For example, problems/0206.翻转链表.md checks if (!head) return nullptr; before entering the reversal loop, while problems/0028.实现strStr.md returns 0 immediately for empty needles and calculates a non‑negative loop range to handle cases where the needle exceeds the haystack length.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →