Two Sum

 

My Java Journey with LeetCode's Two Sum:

Yo, what’s good? Today, I dove into the Two Sum problem on LeetCode, and it was a wild ride. I’m jotting this down as part of my coding journal to track my thought process, the mistakes I made, and how I cracked it with some help from my virtual coding buddy, Grok. This isn’t just about getting the answer—it’s about learning how to think through problems like a pro. Let’s break it down, Java style!

The Problem

Two Sum is pretty chill at first glance. You’re given an array of integers nums and a target sum, and you need to return the indices of two numbers that add up to the target. For example, if nums = [2, 7, 11, 15] and target = 9, you return [0, 1] because nums[0] + nums[1] = 2 + 7 = 9. The rules? You can’t use the same element twice, and there’s exactly one solution.

My First Stab: Brute-Force with Nested Loops

When I read the problem, my brain was like, “Easy, just check every pair of numbers!” So, my first instinct was to write a nested loop to try every combination of numbers in the array. In Java, that’d look something like:

                        public int[] twoSum(int[] nums, int target) {

 for (int i = 0; i < nums.length; i++) {
    for (int j = i + 1; j < nums.length; j++) {
       if (nums[i] + nums[j] == target) {
          return new int[] {i, j};
            }
        }
    }

                               return new int[] {}; // Problem guarantees a solution, so this is just for safety 

}

This made sense to me because it’s like manually flipping through every pair of numbers. For nums = [2, 7, 11, 15] and target = 9, it checks:

  • 2 + 7 (boom, that’s 9!), and returns [0, 1].

But then I realized this approach is sloooow. With an array of length n, I’m doing roughly n * (n-1) / 2 checks, which is O(n²). If the array’s huge, like thousands of elements, this is gonna crawl. Plus, it felt wasteful—why check every pair when the answer might be right at the start?

My HashMap Idea: Close, But a Big Flaw

I knew I could do better, so I thought, “What about a hashmap? Those are fast for lookups!” My initial plan was:

  1. Dump all the numbers into a HashMap.
  2. Loop through the array again, compute target - nums[i], and check if that difference is in the hashmap.

I figured this would be faster because hashmap lookups are O(1) on average. But then I hit a snag, and I’m glad I caught it. If I add all numbers to the hashmap first, I lose track of the indices properly, and I might accidentally use the same element twice. For example, if nums = [3, 3] and target = 6, I’d find 3 in the hashmap when processing the first 3, but that’s a no-go since the problem says I can’t reuse elements. I was so focused on the numbers that I forgot the output needs to be the indices of the two numbers.

This was a wake-up call. I needed to store number: index pairs in the hashmap to keep track of where each number lives in the array. Back to the drawing board!

The Breakthrough: One-Pass HashMap

After bouncing ideas with Grok, I landed on a slicker approach. Instead of adding all numbers to the hashmap first, I could build the hashmap while looping through the array. Here’s the game plan:

  • Loop through the array once.
  • For each element nums[i]:
    • Calculate the difference: diff = target - nums[i].
    • Check if diff is in the hashmap. If it is, I’ve got my pair: the index stored in hashmap.get(diff) and the current index i.
    • If not, add nums[i] as the key and i as the value to the hashmap.

This approach is clean because it ensures I never use the same element twice (since I only add nums[i] after checking for the difference). Let’s see it in action with nums = [2, 7, 11, 15] and target = 9:

  1. Start with an empty hashmap: {}.
  2. At i = 0, nums[0] = 2:
    • diff = 9 - 2 = 7.
    • Is 7 in the hashmap? Nope, it’s empty.
    • Add 2: 0 to the hashmap: {2=0}.
  3. At i = 1, nums[1] = 7:
    • diff = 9 - 7 = 2.
    • Is 2 in the hashmap? Yup! hashmap.get(2) = 0.
    • Return [0, 1].

Done! Found the solution in one pass.

The Java Code

Here’s the final Java code I settled on:

public class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer, Integer> hashmap = new HashMap<>(); // Key: number, Value: index
        for (int i = 0; i < nums.length; i++) {
            int diff = target - nums[i];
            if (hashmap.containsKey(diff)) {
                return new int[] {hashmap.get(diff), i};
            }
            hashmap.put(nums[i], i);
        }
        return new int[] {}; // Problem guarantees a solution, so this is just for safety
    }
}

Let me explain one line in my own words:

  • hashmap.put(nums[i], i);
    This line adds the current number nums[i] as a key and its index i as the value to the hashmap. I do this after checking for the difference, so I’m only storing numbers I’ve already processed. This way, if I find a match later, I know it’s from a previous index, avoiding the “same element” trap.

Why This Solution Slaps

This one-pass hashmap approach is fire because:

  • Time Complexity: O(n). I loop through the array once, and hashmap operations (containsKey and put) are O(1) on average.
  • Space Complexity: O(n) for storing the hashmap, which is a fair trade for the speed.
  • No Double-Dipping: By adding elements to the hashmap after checking for the difference, I ensure I never use the same element twice.

Compared to my brute-force O(n²) idea, this is way faster and more elegant.

Lessons I’m Taking Away

This problem was a goldmine for learning:

  • Focus on the Output: I initially got hung up on finding numbers, not indices. Always clarify what the problem wants!
  • Edge Cases Matter: My first hashmap idea didn’t handle cases like nums = [3, 3], target = 6. Writing down edge cases helps catch these bugs early.
  • Iterate and Optimize: My brute-force solution worked, but it was clunky. Talking through it helped me see the hashmap trick.
  • HashMaps Are My New BFF: They’re perfect for problems involving pairs or lookups. I’m already eyeing other problems where this pattern might pop up.

What’s Next for Me

I’m hyped to keep this going. I think I’ll tackle 3Sum or Contains Duplicate next to practice the hashmap pattern more. I’m also loving this journaling thing—it’s like talking to my future self about what I learned. My big takeaway? Don’t just code—think. Break the problem down, talk it out, and let the solution unfold.

Shoutout to Grok for helping me work through this without spoon-feeding me the answer. Here’s to crushing more LeetCode problems and becoming a Java problem-solving beast!

Comments