1346. Check If N and Its Double Exist
Problem Description
You are given an array arr
of integers. Your task is to check if there exist two different indices i
and j
in the array such that the value at index i
is exactly double the value at index j
.
In other words, you need to find if there are two elements in the array where one element is twice the value of another element. The two elements must be at different positions in the array (i.e., i != j
).
The conditions that must be satisfied are:
- The indices
i
andj
must be different (i != j
) - Both indices must be valid within the array bounds (
0 <= i, j < arr.length
) - The relationship between the values must be:
arr[i] == 2 * arr[j]
For example:
- If
arr = [10, 2, 5, 3]
, the function should returntrue
because10 = 2 * 5
- If
arr = [3, 1, 7, 11]
, the function should returnfalse
because no element is double of another
The solution uses a hash table to efficiently track elements we've already seen. As we traverse the array, for each element x
, we check if either 2 * x
(double of current element) or x / 2
(half of current element, when x
is even) exists in our hash table. If either condition is met, we've found our pair and return true
. Otherwise, we add the current element to the hash table and continue. If we finish traversing without finding such a pair, we return false
.
Intuition
The key insight is that for any element x
in the array, we need to find if there exists another element that is either 2 * x
or x / 2
. This is a classic "pair finding" problem where we need to check if a specific relationship exists between two elements.
The brute force approach would be to use two nested loops to check every pair of elements, which would take O(n²)
time. However, we can optimize this by recognizing that as we traverse the array, we only need to check if the "matching" element for the current element has already been seen.
Think of it this way: when we encounter an element x
, there are only two possibilities for it to form a valid pair:
- It could be the smaller element in the pair, meaning we need to find
2 * x
somewhere else - It could be the larger element in the pair, meaning we need to find
x / 2
somewhere else
By using a hash table to store elements we've already processed, we can check in O(1)
time whether the required counterpart exists. As we iterate through the array:
- For each element
x
, we check if2 * x
exists in our hash table (checking ifx
is the smaller element of a pair) - We also check if
x / 2
exists in our hash table, but only whenx
is even (checking ifx
is the larger element of a pair) - If either condition is true, we've found our answer
- If not, we add
x
to the hash table for future elements to check against
This approach reduces the time complexity from O(n²)
to O(n)
by trading space for time, using O(n)
additional space for the hash table.
Learn more about Two Pointers, Binary Search and Sorting patterns.
Solution Approach
We implement the solution using a hash table to track elements we've already visited while traversing the array.
Algorithm Steps:
-
Initialize an empty hash set
s
to store the elements we've seen so far. -
Iterate through each element
x
in the arrayarr
:- Check if
x * 2
exists in the hash sets
(this checks if the current element can be the smaller element in a valid pair) - Check if
x // 2
exists in the hash sets
, but only whenx % 2 == 0
(this checks if the current element can be the larger element in a valid pair, and we only check whenx
is even because odd numbers don't have integer halves) - If either condition is true, immediately return
True
as we've found a valid pair - If neither condition is met, add
x
to the hash sets
for future comparisons
- Check if
-
If we complete the entire traversal without finding a valid pair, return
False
.
Implementation Details:
class Solution:
def checkIfExist(self, arr: List[int]) -> bool:
s = set()
for x in arr:
if x * 2 in s or (x % 2 == 0 and x // 2 in s):
return True
s.add(x)
return False
The condition x * 2 in s
checks if we've previously seen an element that is double the current element. The condition (x % 2 == 0 and x // 2 in s)
first verifies that x
is even (using x % 2 == 0
) before checking if half of x
exists in the set.
Time and Space Complexity:
- Time Complexity:
O(n)
wheren
is the length of the array, as we traverse the array once and hash set operations areO(1)
on average - Space Complexity:
O(n)
in the worst case when all elements are unique and we store them all in the hash set
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with the array arr = [7, 1, 14, 11]
.
Initial State:
- Hash set
s = {}
- We'll check each element to see if its double or half exists in the set
Step 1: Process element 7
- Check if
7 * 2 = 14
is ins
? No,s
is empty - Check if
7 // 2 = 3
is ins
? No need to check (7 is odd) - No match found, add 7 to the set
s = {7}
Step 2: Process element 1
- Check if
1 * 2 = 2
is ins
? No, 2 is not in{7}
- Check if
1 // 2 = 0
is ins
? No need to check (1 is odd) - No match found, add 1 to the set
s = {7, 1}
Step 3: Process element 14
- Check if
14 * 2 = 28
is ins
? No, 28 is not in{7, 1}
- Check if
14 // 2 = 7
is ins
? Yes! 14 is even, and 7 exists in{7, 1}
- Match found! Return
True
We found that 14 = 2 * 7
, where 7 was seen at index 0 and 14 is at index 2, satisfying our condition that one element is exactly double another at different indices.
Solution Implementation
1class Solution:
2 def checkIfExist(self, arr: List[int]) -> bool:
3 """
4 Check if there exist two indices i and j such that:
5 - i != j
6 - arr[i] == 2 * arr[j] (i.e., one element is double of another)
7
8 Args:
9 arr: List of integers to check
10
11 Returns:
12 bool: True if such pair exists, False otherwise
13 """
14 # Set to store elements we've seen so far
15 seen_numbers = set()
16
17 # Iterate through each element in the array
18 for current_num in arr:
19 # Check if double of current number exists in seen numbers
20 # OR if current number is even and its half exists in seen numbers
21 if (current_num * 2 in seen_numbers or
22 (current_num % 2 == 0 and current_num // 2 in seen_numbers)):
23 return True
24
25 # Add current number to the set of seen numbers
26 seen_numbers.add(current_num)
27
28 # No valid pair found
29 return False
30
1class Solution {
2 /**
3 * Check if there exist two indices i and j such that:
4 * - i != j
5 * - arr[i] == 2 * arr[j]
6 *
7 * @param arr Input array of integers
8 * @return true if such pair exists, false otherwise
9 */
10 public boolean checkIfExist(int[] arr) {
11 // Use a HashSet to store previously seen numbers
12 Set<Integer> seenNumbers = new HashSet<>();
13
14 // Iterate through each element in the array
15 for (int currentNumber : arr) {
16 // Check if the double of current number exists in the set
17 // OR if current number is even and its half exists in the set
18 if (seenNumbers.contains(currentNumber * 2) ||
19 (currentNumber % 2 == 0 && seenNumbers.contains(currentNumber / 2))) {
20 // Found a valid pair where one is double of the other
21 return true;
22 }
23
24 // Add current number to the set for future comparisons
25 seenNumbers.add(currentNumber);
26 }
27
28 // No valid pair found
29 return false;
30 }
31}
32
1class Solution {
2public:
3 bool checkIfExist(vector<int>& arr) {
4 // Use hash set to store previously seen numbers
5 unordered_set<int> seen;
6
7 // Iterate through each element in the array
8 for (int num : arr) {
9 // Check if double of current number exists in the set
10 // OR if current number is even and its half exists in the set
11 if (seen.count(num * 2) || (num % 2 == 0 && seen.count(num / 2))) {
12 return true;
13 }
14
15 // Add current number to the set for future comparisons
16 seen.insert(num);
17 }
18
19 // No valid pair found
20 return false;
21 }
22};
23
1/**
2 * Checks if there exist two indices i and j such that arr[i] == 2 * arr[j]
3 * @param arr - The input array of numbers to check
4 * @returns true if such a pair exists, false otherwise
5 */
6function checkIfExist(arr: number[]): boolean {
7 // Set to store numbers we've already encountered
8 const seenNumbers: Set<number> = new Set();
9
10 // Iterate through each number in the array
11 for (const currentNumber of arr) {
12 // Check if either:
13 // 1. The double of current number exists in our set
14 // 2. The current number is even AND half of it exists in our set
15 if (seenNumbers.has(currentNumber * 2) ||
16 (currentNumber % 2 === 0 && seenNumbers.has(Math.floor(currentNumber / 2)))) {
17 return true;
18 }
19
20 // Add the current number to our set for future comparisons
21 seenNumbers.add(currentNumber);
22 }
23
24 // No valid pair found
25 return false;
26}
27
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the array arr
. This is because the algorithm iterates through the array exactly once, and for each element, it performs constant-time operations: checking membership in a set (x * 2 in s
and x // 2 in s
) and adding an element to the set (s.add(x)
), which are all O(1)
operations on average for hash sets.
The space complexity is O(n)
, where n
is the length of the array arr
. In the worst case, when no early return occurs (meaning no element satisfies the condition), all n
elements from the array will be added to the set s
, requiring O(n)
additional space to store them.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Handling Zero Values Incorrectly
The Problem:
When the array contains zeros, a subtle bug can occur. Since 0 * 2 = 0
and 0 // 2 = 0
, a single zero would satisfy the condition arr[i] == 2 * arr[j]
with itself. However, the problem requires two different indices, so we need at least two zeros in the array for this to be valid.
Example of the Issue:
arr = [0, 1, 3]
- Should returnfalse
(single zero can't pair with itself)arr = [0, 1, 0]
- Should returntrue
(two zeros at different indices)
Why the Current Solution Works: The hash set approach naturally handles this case correctly because:
- When we encounter the first
0
, we check if0 * 2 = 0
or0 // 2 = 0
exists in the set - Since the set is initially empty (or doesn't contain 0 yet), both checks fail
- We then add
0
to the set - If we encounter another
0
later, now the check succeeds and we returntrue
Pitfall 2: Integer Division vs Float Division
The Problem:
Using regular division /
instead of integer division //
could lead to incorrect comparisons when checking if half of a number exists.
Incorrect Implementation:
if x * 2 in s or (x % 2 == 0 and x / 2 in s): # Wrong: x / 2 returns float
Why It's Wrong:
x / 2
returns a float (e.g.,6 / 2 = 3.0
)- The set contains integers (e.g.,
3
) - In Python,
3.0 == 3
isTrue
, but3.0 in {3}
depends on hash equality - While this often works in Python due to hash equality between equivalent ints and floats, it's not semantically correct and could cause issues in other languages
Correct Implementation:
if x * 2 in s or (x % 2 == 0 and x // 2 in s): # Correct: x // 2 returns int
Pitfall 3: Forgetting to Check if Number is Even
The Problem: Attempting to check for half of an odd number without verifying it's even first.
Incorrect Implementation:
if x * 2 in s or x // 2 in s: # Wrong: doesn't check if x is even
Why It's Wrong:
- For
x = 5
, we getx // 2 = 2
- If
2
exists in the set, we'd incorrectly returntrue
- But
2 * 2 = 4
, not5
, so this is a false positive
Example:
arr = [2, 5]
would incorrectly returntrue
- When processing
5
, we'd check if5 // 2 = 2
is in the set - Since
2
was added first, the check succeeds incorrectly
Correct Implementation: Always verify the number is even before checking for its half:
if x * 2 in s or (x % 2 == 0 and x // 2 in s):
Is the following code DFS or BFS?
void search(Node root) { if (!root) return; visit(root); root.visited = true; for (Node node in root.adjacent) { if (!node.visited) { search(node); } } }
Recommended Readings
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
Binary Search Speedrun For each of the Speedrun questions you will be given a binary search related problem and a corresponding multiple choice question The multiple choice questions are related to the techniques and template s introduced in the binary search section It's recommended that you have gone through at
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Want a Structured Path to Master System Design Too? Don’t Miss This!