Facebook Pixel

217. Contains Duplicate

Problem Description

You are given an integer array nums. Your task is to determine if there are any duplicate values in the array.

Return true if any value appears at least twice in the array. Return false if every element in the array is distinct (appears only once).

For example:

  • If nums = [1, 2, 3, 1], you should return true because the value 1 appears twice
  • If nums = [1, 2, 3, 4], you should return false because all elements are unique

The solution approach sorts the array first, then checks if any two adjacent elements are equal. After sorting, duplicate elements will be placed next to each other, making them easy to detect by comparing consecutive pairs. The pairwise function creates pairs of adjacent elements (a, b) from the sorted array, and any() returns true if at least one pair has equal elements.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

When we need to find duplicates in an array, we need a way to compare elements efficiently. One key observation is that if we arrange the array in sorted order, any duplicate elements will end up right next to each other.

Think about it: if we have the array [3, 1, 4, 1, 5] and sort it to get [1, 1, 3, 4, 5], the duplicate 1s are now adjacent. This property holds for any duplicates in the array - sorting brings identical values together.

Once sorted, we only need to check consecutive pairs of elements. If any two adjacent elements are equal, we know there's a duplicate. This reduces our problem from comparing every element with every other element (which would be inefficient) to just comparing neighbors.

The pairwise function generates these consecutive pairs (nums[0], nums[1]), (nums[1], nums[2]), and so on. We can then use any() to check if at least one pair has matching elements. As soon as we find one matching pair, we can return true. If we check all pairs and find no matches, all elements must be distinct.

This approach leverages the sorting operation to organize our data in a way that makes duplicate detection straightforward - transforming a potentially complex comparison problem into a simple linear scan of adjacent elements.

Solution Approach

The implementation follows the sorting-based approach to detect duplicates:

  1. Sort the array: We first sort the input array nums using Python's built-in sorted() function. This operation arranges all elements in ascending order, with the time complexity of O(n log n).

  2. Generate consecutive pairs: The pairwise() function (available in Python's itertools) creates an iterator of consecutive element pairs from the sorted array. For example, if the sorted array is [1, 2, 2, 3], pairwise generates: (1, 2), (2, 2), (2, 3).

  3. Check for equal pairs: We use a generator expression a == b for a, b in pairwise(sorted(nums)) to check if any pair has equal elements. This comparison is done lazily - it doesn't check all pairs upfront but evaluates them one by one.

  4. Early termination with any(): The any() function returns true as soon as it finds the first pair where a == b. This provides early termination - if duplicates are found early in the sorted array, we don't need to check the remaining pairs.

The entire solution is elegantly condensed into a single line:

return any(a == b for a, b in pairwise(sorted(nums)))

Time Complexity: O(n log n) due to sorting, where n is the length of the array.

Space Complexity: O(n) for creating the sorted array (or O(1) if we consider the sorting space as auxiliary).

This approach is efficient and clean, leveraging Python's built-in functions to create a concise solution that's easy to understand and maintain.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with the array nums = [4, 2, 7, 2, 1].

Step 1: Sort the array

  • Original array: [4, 2, 7, 2, 1]
  • After sorting: [1, 2, 2, 4, 7]
  • Notice how the duplicate 2s are now adjacent to each other

Step 2: Generate consecutive pairs using pairwise

  • From the sorted array [1, 2, 2, 4, 7], we create pairs:
    • Pair 1: (1, 2) - comparing indices 0 and 1
    • Pair 2: (2, 2) - comparing indices 1 and 2
    • Pair 3: (2, 4) - comparing indices 2 and 3
    • Pair 4: (4, 7) - comparing indices 3 and 4

Step 3: Check each pair for equality

  • Pair (1, 2): 1 == 2? No
  • Pair (2, 2): 2 == 2? Yes! Found a duplicate

Step 4: Return result

  • Since we found a matching pair (2, 2), the any() function immediately returns true
  • We don't need to check the remaining pairs (2, 4) and (4, 7) due to early termination

The function returns true, correctly identifying that the array contains duplicates.

Contrast with a non-duplicate example: If we had nums = [4, 2, 7, 1]:

  • After sorting: [1, 2, 4, 7]
  • Pairs: (1, 2), (2, 4), (4, 7)
  • None of these pairs have equal elements, so any() returns false

Solution Implementation

1from typing import List
2from itertools import pairwise
3
4class Solution:
5    def containsDuplicate(self, nums: List[int]) -> bool:
6        """
7        Check if the array contains any duplicate elements.
8      
9        Args:
10            nums: List of integers to check for duplicates
11          
12        Returns:
13            True if any value appears at least twice, False otherwise
14        """
15        # Sort the array so duplicate elements will be adjacent
16        sorted_nums = sorted(nums)
17      
18        # Check each pair of consecutive elements for equality
19        # pairwise() creates sliding window pairs: (a[0], a[1]), (a[1], a[2]), ...
20        # any() returns True if at least one pair has equal elements
21        return any(a == b for a, b in pairwise(sorted_nums))
22
1class Solution {
2    /**
3     * Determines if an array contains any duplicate elements.
4     * 
5     * @param nums The input array of integers
6     * @return true if any value appears at least twice, false otherwise
7     */
8    public boolean containsDuplicate(int[] nums) {
9        // Sort the array to place duplicate elements adjacent to each other
10        Arrays.sort(nums);
11      
12        // Iterate through the sorted array and check adjacent elements
13        for (int i = 0; i < nums.length - 1; i++) {
14            // If two adjacent elements are equal, we found a duplicate
15            if (nums[i] == nums[i + 1]) {
16                return true;
17            }
18        }
19      
20        // No duplicates found after checking all adjacent pairs
21        return false;
22    }
23}
24
1class Solution {
2public:
3    bool containsDuplicate(vector<int>& nums) {
4        // Sort the array in ascending order
5        sort(nums.begin(), nums.end());
6      
7        // Iterate through the sorted array and check adjacent elements
8        for (int i = 0; i < nums.size() - 1; ++i) {
9            // If two adjacent elements are equal, we found a duplicate
10            if (nums[i] == nums[i + 1]) {
11                return true;
12            }
13        }
14      
15        // No duplicates found
16        return false;
17    }
18};
19
1/**
2 * Checks if an array contains any duplicate elements
3 * @param nums - Array of numbers to check for duplicates
4 * @returns true if duplicates exist, false otherwise
5 */
6function containsDuplicate(nums: number[]): boolean {
7    // Sort the array in ascending order
8    nums.sort((a: number, b: number) => a - b);
9  
10    // Store the array length for iteration
11    const arrayLength: number = nums.length;
12  
13    // Iterate through the sorted array starting from index 1
14    for (let i: number = 1; i < arrayLength; i++) {
15        // Compare current element with previous element
16        // If they are equal, we found a duplicate
17        if (nums[i - 1] === nums[i]) {
18            return true;
19        }
20    }
21  
22    // No duplicates found after checking all adjacent pairs
23    return false;
24}
25

Time and Space Complexity

Time Complexity: O(n log n), where n is the length of the array nums.

The time complexity is dominated by the sorted() function, which uses Timsort algorithm with O(n log n) time complexity in the average and worst cases. After sorting, the pairwise() function iterates through the sorted array once, creating n-1 pairs, and the any() function checks these pairs for equality, both taking O(n) time. Since O(n log n) + O(n) = O(n log n), the overall time complexity is O(n log n).

Space Complexity: O(n), where n is the length of the array nums.

The sorted() function creates a new sorted list containing all elements from the input array, requiring O(n) additional space. The pairwise() function generates pairs on-the-fly as an iterator without storing all pairs simultaneously, so it only uses O(1) extra space. Therefore, the overall space complexity is O(n).

Common Pitfalls

1. Python Version Compatibility Issue with pairwise()

The pairwise() function was introduced in Python 3.10. If you're using an earlier version of Python, the code will raise an ImportError or AttributeError. This is a frequent issue in coding interviews or online judges that may use older Python versions.

Solution: Implement your own pairwise logic or use alternative approaches:

# Option 1: Manual pairwise implementation
class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        sorted_nums = sorted(nums)
        for i in range(len(sorted_nums) - 1):
            if sorted_nums[i] == sorted_nums[i + 1]:
                return True
        return False

# Option 2: Use zip with offset
class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        sorted_nums = sorted(nums)
        return any(a == b for a, b in zip(sorted_nums, sorted_nums[1:]))

2. Inefficiency for Large Arrays with Early Duplicates

While sorting provides a clean solution, it always takes O(n log n) time even if duplicates exist at the beginning of the array. For instance, if nums = [1, 1, 2, 3, ..., 1000000], we still sort the entire array despite finding duplicates immediately.

Solution: Use a HashSet approach for better average-case performance:

class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        seen = set()
        for num in nums:
            if num in seen:
                return True
            seen.add(num)
        return False
      
        # Or even simpler:
        # return len(nums) != len(set(nums))

3. Memory Overhead from Creating Sorted Copy

The sorted() function creates a new list, consuming O(n) additional space. In memory-constrained environments, this could be problematic for very large arrays.

Solution: If modifying the original array is acceptable, use in-place sorting:

class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        nums.sort()  # In-place sorting
        for i in range(len(nums) - 1):
            if nums[i] == nums[i + 1]:
                return True
        return False

4. Edge Case: Empty or Single-Element Arrays

While the current solution handles these correctly, developers might overlook testing these cases, especially when implementing manual iterations.

Solution: Always validate with edge cases:

  • Empty array [] should return False
  • Single element [1] should return False
  • Two identical elements [1, 1] should return True
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

What is an advantages of top-down dynamic programming vs bottom-up dynamic programming?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More