Single Element In Sorted Array
You are given a sorted array consisting of only integers where every element appears exactly twice,
except for one element which appears exactly once.
Return the single element that appears only once.
Your solution must run in O(log n)
time and O(1)
space.
package questions
import _utils.UseCommentAsDocumentation
import utils.shouldBe
/**
* You are given a sorted array consisting of only integers where every element appears exactly twice,
* except for one element which appears exactly once.
* Return the single element that appears only once.
* Your solution must run in `O(log n)` time and `O(1)` space.
*
* [Source](https://leetcode.com/problems/single-element-in-a-sorted-array/)
*/
@UseCommentAsDocumentation
private fun singleNonDuplicate(nums: IntArray): Int {
/**
* Theorem:
*
* If no single element exists till index i such that nums[i] == nums[i + 1], then i must be even.
* i.e. starting index must always be even.
*
* 0 1 2 3 4 5 6 7 8
* _________________________________
* 1 1 2 2 3 3 4 4 (5)
* (1) 2 2 3 3 4 4 5 5
*
* Using this fact, do binary search
*/
fun findSingleNonDuplicate(low: Int, high: Int): Int {
if (high == low && high > nums.lastIndex) {
return nums.last()
}
if (low < 0) {
return nums.first()
}
val midIndex = (low + high) / 2
val rightElemIndex = midIndex + 1
val leftElemIndex = midIndex - 1
if (nums[midIndex] == nums.getOrNull(rightElemIndex)) { // is mid == right element?
val startingIndex = midIndex // if yes, mid is the starting element
if (startingIndex % 2 == 0) { // if mid is even, then single element is at its right
return findSingleNonDuplicate(startingIndex + 2, high)
} else {
return findSingleNonDuplicate(low, startingIndex - 1) // else at its left
}
} else if (nums.getOrNull(leftElemIndex) == nums[midIndex]) { // if left is the starting index
val startingIndex = leftElemIndex
if (startingIndex % 2 == 0) { // is starting index even?
return findSingleNonDuplicate(startingIndex + 2, high) // if yes, then no single element at left
} else {
return findSingleNonDuplicate(low, startingIndex - 1) // single element must exists at left
}
} else {
return nums[midIndex] // found the single element
}
}
return findSingleNonDuplicate(0, nums.size)
}
fun main() {
singleNonDuplicate(nums = intArrayOf(1, 1, 2, 2, 3, 3, 4, 4, 5)) shouldBe 5
singleNonDuplicate(nums = intArrayOf(3, 3, 7, 7, 10, 11, 11)) shouldBe 10
singleNonDuplicate(nums = intArrayOf(1, 1, 2, 3, 3, 4, 4, 8, 8)) shouldBe 2
singleNonDuplicate(nums = intArrayOf(3, 3, 7, 10, 10, 11, 11)) shouldBe 7
singleNonDuplicate(nums = intArrayOf(3, 3, 7, 7, 10, 10, 11, 11, 12)) shouldBe 12
singleNonDuplicate(nums = intArrayOf(1, 3, 3, 7, 7, 10, 10, 11, 11)) shouldBe 1
}
Updated on 2021-11-21