home writings uses think in code

πŸ” Solving 'Two Sum' with HashMap in Kotlin

Apr 16, 2025

tl;dr: An elegant approach to finding two numbers that add up to a target value

πŸ” Solving 'Two Sum' with HashMap in Kotlin

πŸ“ Problem Statement

Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

You can return the answer in any order.


πŸ’‘ My Initial Thought Process

When I first approached this problem, I thought about using a HashMap to efficiently find the solution:

  1. Iterate through each number in the array
  2. For each number, calculate the difference between the target and the current number
  3. Check if this difference exists in our HashMap
  4. If it does, we’ve found our pair! Return the indices
  5. If not, add the current number and its index to the HashMap and continue

This approach ensures we only need to go through the array once, giving us an O(N) time complexity.


πŸ† My Initial Solution

class Solution { fun twoSum(nums: IntArray, target: Int): IntArray { val hm = HashMap<Int, Int>() nums.forEachIndexed {index, v -> val rem = target - v if(hm.contains(rem)){ return intArrayOf(hm[rem]!!,index) } hm.put(v,index) } return intArrayOf() } } fun main() { val solution = Solution() // Example 1 val nums1 = intArrayOf(2, 7, 11, 15) val target1 = 9 val result1 = solution.twoSum(nums1, target1) println("Example 1:") println("Input: nums = [2, 7, 11, 15], target = 9") println("Output: [${result1[0]}, ${result1[1]}]") println("Explanation: nums[${result1[0]}] + nums[${result1[1]}] = ${nums1[result1[0]]} + ${nums1[result1[1]]} = $target1") // Example 2 val nums2 = intArrayOf(3, 2, 4) val target2 = 6 val result2 = solution.twoSum(nums2, target2) println("\nExample 2:") println("Input: nums = [3, 2, 4], target = 6") println("Output: [${result2[0]}, ${result2[1]}]") println("Explanation: nums[${result2[0]}] + nums[${result2[1]}] = ${nums2[result2[0]]} + ${nums2[result2[1]]} = $target2") }

This solution works correctly and efficiently, but I felt there was room for improvement in terms of readability and Kotlin idioms.


πŸš€ Improved Solution with Kotlin Idioms

class Solution { fun twoSum(nums: IntArray, target: Int): IntArray { val seen = HashMap<Int, Int>() nums.forEachIndexed {i, num -> seen[target - num]?.let { return intArrayOf(i, it) } seen[num] = i } return intArrayOf() } } fun main() { val solution = Solution() // Example 1 val nums1 = intArrayOf(2, 7, 11, 15) val target1 = 9 val result1 = solution.twoSum(nums1, target1) println("Example 1:") println("Input: nums = [2, 7, 11, 15], target = 9") println("Output: [${result1[0]}, ${result1[1]}]") println("Explanation: nums[${result1[0]}] + nums[${result1[1]}] = ${nums1[result1[0]]} + ${nums1[result1[1]]} = $target1") // Example 2 val nums2 = intArrayOf(3, 2, 4) val target2 = 6 val result2 = solution.twoSum(nums2, target2) println("\nExample 2:") println("Input: nums = [3, 2, 4], target = 6") println("Output: [${result2[0]}, ${result2[1]}]") println("Explanation: nums[${result2[0]}] + nums[${result2[1]}] = ${nums2[result2[0]]} + ${nums2[result2[1]]} = $target2") }

πŸ”₯ What I Learned

Through this process, I picked up some valuable Kotlin idioms and best practices:

  1. Meaningful Variable Names: Using seen instead of hm makes the code more readable and self-documenting.

  2. Safe Call with Let: The ?.let operator is a concise way to handle nullable values. Instead of:

    if(hm.contains(rem)){
        return intArrayOf(hm[rem]!!,index)
    }
    

    We can use:

    seen[target - num]?.let { return intArrayOf(i, it) }
    

    This eliminates the need for the null assertion operator (!!) and makes the code more elegant.

  3. Direct Map Access: Instead of using contains() followed by a lookup, we can directly access the map with the safe call operator.

⏳ Time Complexity Analysis

  • Building and searching the HashMap β†’ O(N)
  • Overall Complexity: O(N) πŸš€ (Fast & Efficient!)

🧠 Key Insights

  • The HashMap approach allows us to find the complement in O(1) time
  • By storing each number as we go, we’re essentially β€œremembering” what we’ve seen before
  • This problem demonstrates how data structures can dramatically improve algorithm efficiency

Let’s continue exploring elegant solutions to classic problems! If you have any questions or want to discuss other approaches to this problem, feel free to reach out.

Want to learn more about DSA and efficient algorithms? Let's connect and solve problems together!