import HeaderLink from './HeaderLink.astro';

Two Pointers

Java solutions with explanations, time and space complexity for Two Pointers problems.

Two Pointers

1. Valid Palindrome

Description:
Given a string s, return true if it is a palindrome, considering only alphanumeric characters and ignoring cases.

Java Solution:

class Solution {
    public boolean isPalindrome(String s) {
        if (s.isEmpty()) {
            return true;
        }
        int left = 0;
        int right = s.length() - 1;
        while (left < right) {
            char leftChar = s.charAt(left);
            char rightChar = s.charAt(right);

            if (!Character.isLetterOrDigit(leftChar)) {
                left++;
            } else if (!Character.isLetterOrDigit(rightChar)) {
                right--;
            } else {
                if (Character.toLowerCase(leftChar) != Character.toLowerCase(rightChar)) {
                    return false;
                }
                left++;
                right--;
            }
        }
        return true;
    }
}

Explanation:
We use two pointers, one starting from the beginning and one from the end. We move them inwards, skipping non-alphanumeric characters. We compare characters in a case-insensitive manner.

  • Time Complexity: O(n)
    We iterate through the string with two pointers, each pointer traversing at most n characters.
  • Space Complexity: O(1)
    No extra space is used beyond a few variables.

2. Two Sum II - Input Array Is Sorted

Description:
Given a 1-indexed array of integers numbers that is already sorted in non-decreasing order, find two numbers such that they add up to a specific target number.

Java Solution:

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int left = 0;
        int right = numbers.length - 1;

        while (left < right) {
            int sum = numbers[left] + numbers[right];
            if (sum == target) {
                return new int[] { left + 1, right + 1 };
            } else if (sum < target) {
                left++;
            } else {
                right--;
            }
        }
        return new int[] {}; // Should not reach here as per problem constraints
    }
}

Explanation:
Since the array is sorted, we can use two pointers. If the sum is too small, increment left; if too large, decrement right.

  • Time Complexity: O(n)
    The two pointers traverse the array at most once, performing constant time operations per step.
  • Space Complexity: O(1)
    Only a few variables are used.

3. 3Sum

Description:
Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.

Java Solution:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);

        for (int i = 0; i < nums.length - 2; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) continue; // Skip duplicates

            int left = i + 1;
            int right = nums.length - 1;
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if (sum == 0) {
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    while (left < right && nums[left] == nums[left + 1]) left++; // Skip duplicates
                    while (left < right && nums[right] == nums[right - 1]) right--; // Skip duplicates
                    left++;
                    right--;
                } else if (sum < 0) {
                    left++;
                } else {
                    right--;
                }
            }
        }
        return result;
    }
}

Explanation:
We sort the array first. Then, for each element, we use two pointers on the remaining array to find pairs that sum to the negative of the current element. Duplicates are handled to avoid redundant triplets.

  • Time Complexity: O(n^2)
    Sorting takes O(n log n). The nested loop with two pointers takes O(n^2). The dominant factor is O(n^2).
  • Space Complexity: O(log n) to O(n)
    This depends on the sorting algorithm used (e.g., quicksort uses O(log n) space for recursion stack; mergesort uses O(n)). Ignoring the output list.

4. Container With Most Water

Description:
Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which, together with the x-axis, forms a container, such that the container contains the most water.

Java Solution:

class Solution {
    public int maxArea(int[] height) {
        int maxArea = 0;
        int left = 0;
        int right = height.length - 1;

        while (left < right) {
            int currentArea = Math.min(height[left], height[right]) * (right - left);
            maxArea = Math.max(maxArea, currentArea);

            if (height[left] < height[right]) {
                left++;
            } else {
                right--;
            }
        }
        return maxArea;
    }
}

Explanation:
We use two pointers, starting at the ends. At each step, we calculate the area. We move the pointer from the shorter line inwards, as moving the taller line’s pointer would not increase the height and would only decrease the width.

  • Time Complexity: O(n)
    The two pointers traverse the array at most once.
  • Space Complexity: O(1)
    Only a few variables are used.

5. Trapping Rain Water

Description:
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.

Java Solution:

class Solution {
    public int trap(int[] height) {
        if (height == null || height.length == 0) return 0;

        int left = 0;
        int right = height.length - 1;
        int leftMax = 0;
        int rightMax = 0;
        int trappedWater = 0;

        while (left < right) {
            if (height[left] < height[right]) {
                if (height[left] >= leftMax) {
                    leftMax = height[left];
                } else {
                    trappedWater += leftMax - height[left];
                }
                left++;
            } else {
                if (height[right] >= rightMax) {
                    rightMax = height[right];
                } else {
                    trappedWater += rightMax - height[right];
                }
                right--;
            }
        }
        return trappedWater;
    }
}

Explanation:
We use two pointers, left and right, and keep track of the leftMax and rightMax heights encountered so far. At each step, we move the pointer from the shorter side. The amount of water trapped at a position is determined by the minimum of leftMax and rightMax minus the current bar’s height.

  • Time Complexity: O(n)
    The two pointers traverse the array at most once.
  • Space Complexity: O(1)
    Only a few variables are used.