Find the Duplicate Number

java dev.to

Problem Statement

Given an array nums containing n + 1 integers where:

  • Each integer is in the range [1, n]
  • There is only one repeated number
  • Return that duplicate number

Example

Input: nums = [1,3,4,2,2]
Output: 2
Enter fullscreen mode Exit fullscreen mode

Brute Force Approach

Interview Explanation

The most straightforward solution is to compare every element with every other element. If two numbers are equal, we have found the duplicate.

Since we check all possible pairs, the duplicate is guaranteed to be found.

Time & Space Complexity

  • Time Complexity: O(N²)
  • Space Complexity: O(1)

Java Code

class Solution {
    public int findDuplicate(int[] nums) {

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

        return -1;
    }
}
Enter fullscreen mode Exit fullscreen mode

Better Approach – HashSet

Interview Explanation

Instead of repeatedly searching for duplicates, we can store already seen numbers inside a HashSet.

Before inserting a number, check whether it already exists in the set.

If it does, that's our duplicate.

Why HashSet?

HashSet provides nearly O(1) lookup time, eliminating the need for nested loops.

Time & Space Complexity

  • Time Complexity: O(N)
  • Space Complexity: O(N)

Java Code

class Solution {
    public int findDuplicate(int[] nums) {

        HashSet<Integer> seen = new HashSet<>();

        for(int num : nums) {
            if(seen.contains(num)) {
                return num;
            }

            seen.add(num);
        }

        return -1;
    }
}
Enter fullscreen mode Exit fullscreen mode

Optimal Approach – Floyd's Cycle Detection

Most interviewers won't stop at HashSet.

They'll ask:

Can you solve it in O(1) extra space?

This is where the real trick begins.


Observation

Every number in the array lies between 1 and n.

Think of each value as a pointer to the next index.

index -> nums[index]
Enter fullscreen mode Exit fullscreen mode

For:

nums = [1,3,4,2,2]
Enter fullscreen mode Exit fullscreen mode

we get:

0 -> 1
1 -> 3
3 -> 2
2 -> 4
4 -> 2
Enter fullscreen mode Exit fullscreen mode

Visualized:

0 → 1 → 3 → 2 → 4
          ↑     ↓
          ← ← ←
Enter fullscreen mode Exit fullscreen mode

A cycle appears.

And what creates this cycle?

The duplicate number.

This transforms the problem into:

Find the starting point of the cycle in a linked list.

Exactly what Floyd's Algorithm does.


Phase 1: Detect the Cycle

Use two pointers:

  • Slow moves one step
  • Fast moves two steps
slow = nums[slow];
fast = nums[nums[fast]];
Enter fullscreen mode Exit fullscreen mode

Eventually they meet inside the cycle.


Phase 2: Find the Duplicate

Move one pointer back to the beginning.

Now move both one step at a time.

Where they meet again is the duplicate number.


Dry Run

Input

nums = [1,3,4,2,2]
Enter fullscreen mode Exit fullscreen mode

Initial State

slow = 1
fast = 1
Enter fullscreen mode Exit fullscreen mode

Iteration 1

slow = nums[1] = 3

fast = nums[nums[1]]
     = nums[3]
     = 2
Enter fullscreen mode Exit fullscreen mode

Iteration 2

slow = nums[3] = 2

fast = nums[nums[2]]
     = nums[4]
     = 2
Enter fullscreen mode Exit fullscreen mode

Pointers meet at:

2
Enter fullscreen mode Exit fullscreen mode

Cycle detected.


Reset Slow

slow = nums[0]
Enter fullscreen mode Exit fullscreen mode

Move both one step at a time:

slow = nums[slow]
fast = nums[fast]
Enter fullscreen mode Exit fullscreen mode

They meet again at:

2
Enter fullscreen mode Exit fullscreen mode

This is the duplicate number.


Optimal Java Solution

class Solution {
    public int findDuplicate(int[] nums) {

        int slow = nums[0];
        int fast = nums[0];

        do {
            slow = nums[slow];
            fast = nums[nums[fast]];
        } while (slow != fast);

        slow = nums[0];

        while (slow != fast) {
            slow = nums[slow];
            fast = nums[fast];
        }

        return slow;
    }
}
Enter fullscreen mode Exit fullscreen mode

Complexity Analysis

Time Complexity

  • Phase 1: O(N)
  • Phase 2: O(N)

Overall:

O(N)
Enter fullscreen mode Exit fullscreen mode

Space Complexity

O(1)
Enter fullscreen mode Exit fullscreen mode

No extra data structures are used.


Interview Takeaway

Whenever you see:

  • Array values limited to a range
  • Numbers acting like references
  • Need to find duplicates
  • O(1) space requirement

Think:

Index = Node
Value = Next Pointer
Enter fullscreen mode Exit fullscreen mode

The moment you see that transformation, the problem becomes:

Find the entrance of a cycle in a linked list.

And Floyd's Tortoise and Hare algorithm solves it beautifully.

GitHub: https://github.com/codewithjaspreet

LinkedIn: https://www.linkedin.com/in/jaspreetsodhi482/

Medium: https://medium.com/@jaspreet.dev

Source: dev.to

arrow_back Back to Tutorials