Skip to content

Commit 91516f3

Browse files
Add solution for finding single element in sorted array
Implemented a binary search-based function to find the single non-duplicate element in a sorted array. Added several unit tests to verify functionality across various edge cases, including large inputs and invalid input constraints.
1 parent 0cb1599 commit 91516f3

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# https://leetcode.com/problems/single-element-in-a-sorted-array
2+
3+
import unittest
4+
from typing import List
5+
6+
# Key observation is that this algorithm will still work even if the array
7+
# isn't fully sorted. As long as pairs are always grouped together in the array
8+
# (for example, [10, 10, 4, 4, 7, 11, 11, 12, 12, 2, 2]), it doesn't matter what
9+
# order they're in. Binary search worked for this problem because we knew the subarray
10+
# with the single number is always odd-lengthed, not because the array was fully sorted
11+
# numerically. We commonly call this an invariant, something that is always true
12+
# (i.e. "The array containing the single element is always odd-lengthed"). Be on the lookout
13+
# for invariants like this when solving array problems, as binary search is very flexible!
14+
15+
16+
def single_non_duplicate(nums: List[int]) -> int:
17+
n = len(nums)
18+
19+
left = 0
20+
right = n - 1
21+
22+
while left < right:
23+
mid = (left + right) // 2
24+
25+
# Ensure 'mid' is even for comparison with its pair
26+
if mid % 2 == 1:
27+
mid -= 1 # Make it even
28+
29+
# Check if the pair is valid
30+
if nums[mid] == nums[mid + 1]:
31+
# If the pair is valid, move the search space to the right
32+
left = mid + 2
33+
else:
34+
# Otherwise, move the search to the left
35+
right = mid
36+
37+
# The left pointer will point at the single non-duplicate element
38+
return nums[left]
39+
40+
41+
class TestSingleNonDuplicate(unittest.TestCase):
42+
def test_single_element(self):
43+
"""Test with a single-element array"""
44+
self.assertEqual(single_non_duplicate([1]), 1)
45+
46+
def test_single_in_middle(self):
47+
"""Test with an odd-length array, single element in the middle"""
48+
self.assertEqual(single_non_duplicate([1, 1, 2, 3, 3]), 2)
49+
50+
def test_single_at_start(self):
51+
"""Test with a single element at the start of the array"""
52+
self.assertEqual(single_non_duplicate([2, 3, 3, 4, 4]), 2)
53+
54+
def test_single_at_end(self):
55+
"""Test with a single element at the end of the array"""
56+
self.assertEqual(single_non_duplicate([1, 1, 2, 2, 3]), 3)
57+
58+
def test_longer_array(self):
59+
"""Test with a larger array"""
60+
self.assertEqual(single_non_duplicate([1, 1, 2, 2, 3, 3, 4, 5, 5]), 4)
61+
62+
def test_consecutive_numbers(self):
63+
"""Test with a numerical sequence as pairs and single"""
64+
self.assertEqual(single_non_duplicate([0, 0, 1, 1, 2, 3, 3]), 2)
65+
66+
def test_invalid_input(self):
67+
"""Test with input that doesn't meet constraints (all paired elements)"""
68+
with self.assertRaises(IndexError):
69+
single_non_duplicate([1, 1, 2, 2])
70+
71+
def test_large_input(self):
72+
"""Test with very large input"""
73+
nums = list(range(1, 20000)) * 2
74+
nums.append(1000000)
75+
nums.sort()
76+
self.assertEqual(single_non_duplicate(nums), 1000000)

0 commit comments

Comments
 (0)