Single Element in a Sorted Array

Ventured into LeetCode and randomly selected the Single Element in a Sorted Array challenge. The requirements are very straight forward. Make sure you pay attention to the following Note: Your solution should run in O(log n) time and O(1) space.

Thought about the linear O(n) brute force approach. I did not bother playing with it given that it was not going to work. Doodle for a few minutes with the numbers and their indices in the array. The solution smelled like a binary search which requires a sorted array of elements.

The following screen capture is from the Eclipse IDE using sample data provided by the challenge and some that I made up:

1,1,2,3,3,4,4,8,8
3,3,7,7,10,11,11
1,1,9
1,8,8
3,3,9,9,10,13,13
1,1,8,10,10
1,1,2,2,8,10,10
-1

main <<< str ==>1,1,2,3,3,4,4,8,8<==
main <<< nums:  1  1  2  3  3  4  4  8  8 
                0  1  2  3  4  5  6  7  8 
2
main <<< str ==>3,3,7,7,10,11,11<==
main <<< nums:  3  3  7  7 10 11 11 
                0  1  2  3  4  5  6 
10
main <<< str ==>1,1,9<==
main <<< nums:  1  1  9 
                0  1  2 
9
main <<< str ==>1,8,8<==
main <<< nums:  1  8  8 
                0  1  2 
1
main <<< str ==>3,3,9,9,10,13,13<==
main <<< nums:  3  3  9  9 10 13 13 
                0  1  2  3  4  5  6 
10
main <<< str ==>1,1,8,10,10<==
main <<< nums:  1  1  8 10 10 
                0  1  2  3  4 
8
main <<< str ==>1,1,2,2,8,10,10<==
main <<< nums:  1  1  2  2  8 10 10 
                0  1  2  3  4  5  6 
8
main <<< str ==>-1<==

The sequence is terminated by a line with a -1. I display the values in the nums array separated by a space. The following line is the index in the nums array. The number left justified is the missing number.

My solution and test code written in Java 8 follows:

import java.util.Scanner;

public class Solution {

	/**
	 * Given a sorted array consisting of only integers where every element appears 
	 * twice except for one element which appears once. Find this single element 
	 * that appears only once.
	 */
	static int singleNonDuplicate(int[] nums) {
		int lo 	= 0;
		int hi 	= nums.length - 1;
		int mid	= 0;
		
		// **** ****
		
		while (lo <= hi) {
			mid = lo + (hi - lo) / 2;
			
			// **** ****
			
			if (lo == hi) {
				return nums[mid];
			}
			
			// **** ****
			
			if ((nums[mid - 1] != nums[mid]) &&
				(nums[mid] != nums[mid + 1])) {
				return nums[mid];
			}
			
			
			// **** ****
			
			if ((mid % 2) == 0) {		// even
				if (nums[mid] == nums[mid - 1]) {
					hi = mid + 1;		// go up
				} else {
					lo = mid - 1;		// go down
				}
			} else {					// odd
				if (nums[mid] == nums[mid - 1]) {
					lo = mid + 1;		// go up
				} else {
					hi = mid - 1;		// go down
				}
			}
		}

		// **** ****
		
		return -1;
	}

	/**
	 * Test code.
	 */
	public static void main(String[] args) {
	
		// ***** open scanner ****
		
		Scanner sc = new Scanner(System.in);
	
		// **** loop until told to exit ****
		
		Boolean done = false;
		while (!done) {
		
			// **** ****
			
			String str = sc.nextLine();
			System.out.println("main <<< str ==>" + str + "<==");
			
			// **** check if we are done ****
			
			if (str.equals("-1")) {
				done = true;
				continue;
			}
			
			// **** build array of integers ****
			
			String ints[] = str.split(",");
			int[] nums = new int[ints.length];
			System.out.print("main <<< nums: ");
			for (int i = 0; i < ints.length; i++) {
				nums[i] = Integer.parseInt(ints[i]);
				System.out.printf("%2d ", nums[i]);
			}
			System.out.println();
			System.out.print("               ");
			for (int i = 0; i < ints.length; i++) {
				System.out.printf("%2d ", i);
			}
			System.out.println();
			
			// **** call method ****
			
			System.out.println(singleNonDuplicate(nums));
		}
		
		// **** close scanner ****
		
		sc.close();

	}

}

If you have comments or questions regarding this or any other post in this blog, please do not hesitate and send me a message. Will reply as soon as possible and will not use your name unless you explicitly allow me to do so.

Enjoy;

John

john.canessa@gmail.com

Follow me on Twitter:  @john_canessa

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.