Search an ascending String array interspersed with empty Strings

Print This Post Print This Post

The problem is stated as:

Given a String array arr, where all the strings in it is pre-sorted in ascending order, however, there are indefinite number of empty strings in it as well. For example,

arr={"", "", "", "36b", "ich099tb", "yi", "zrdy46", "", "", "", ""}

We can tackle this problem by using a modified binary search, and I came up with one recursion solution as well as an iterative one. The code is again simple. I first provide the test code, the implementation follows.

Test Code

	Random r = new Random();
	/**
	 * Return a randomly generated String array follows the rule
	 *
	 * @param size
	 * @return
	 */
	private String[] getAscendingStringArrayWithEmpty(int size){
		int emptyStringCount = r.nextInt(size+1);
		int count = size-emptyStringCount;
		String[] result = new String[size];
		HashSet<String> set = new HashSet<String>();
		ArrayList<String> nonEmptyStrings = new ArrayList<String>();
		while(set.size()<=count){
			set.add(StringHelper.randomStringGenerator(r.nextInt(10)));
		}
		nonEmptyStrings.addAll(set);
		Collections.sort(nonEmptyStrings);
		while(count+emptyStringCount>0){
			boolean b = r.nextBoolean();
			if(b && count>0){	//insert a non-empty string
				result[count+emptyStringCount-1] = nonEmptyStrings.get((count--)-1);
			}else{	//insert an empty string
				result[count+(emptyStringCount--)-1] = "";
			}
		}
		return result;
	}
	@Test
	public void testSearchArrayWithEmptyString(){
		for(int j=0; j<100; j++){
			String[] arr = getAscendingStringArrayWithEmpty(1<<15);
			for(int i=0; i<arr.length; i++){
				if(arr[i].trim().length()!=0){
					Assert.assertEquals(i, SortingQuestions.searchArrayWithEmpty(arr, arr[i]));
				}
			}
		}
	}

Implementation: Recursion

	/**
	 * Given a sorted array of strings which is interspersed with empty strings,
	 * write a method to find the location of a given string.
	 */
	public static int searchArrayWithEmptyString(String[] arr, String t){
		if(arr==null || t==null)
			return -1;
		return searchArrayWithEmptyString(arr, t, 0, arr.length-1);
	}
	private static int searchArrayWithEmptyString(String[] arr, String t, int left, int right){
		if(left>right)
			return -1;
		int mid = (left+right)>>1;
		if(arr[mid].equals(t))
			return mid;
		int a=-1, b=-1;
		if(mid>left)
			a = searchArrayWithEmptyString(arr, t, left, mid-1);
		if(mid<right)
			b = searchArrayWithEmptyString(arr, t, mid+1, right);
		/**
		 * if a==-1, means not found on the left;
		 * if b==-1, means not found on the right;
		 */
		if(a!=-1)
			return a;
		else if(b!=-1)
			return b;
		else
			return -1;
	}

Implementation: Iterative

	/**
	 * Iterative approach
	 *
	 * @param arr The given string array must in ascending order excludes whitespace
	 * @param t Given string to search
	 * @return index of the target if found; -1 otherwise
	 * @throws NullPointerException if either array or given string is null
	 * @throws IllegalArgumentException If 1) given string is empty; 2) given array is not in order
	 */
	public static int searchArrayWithEmpty(String[] arr, String t){
		if(arr==null || t==null)
			throw new NullPointerException("Either array or given string is null");
		if(arr.length==0)
			return -1;
		if(t.trim().length()==0)
			throw new IllegalArgumentException("Search terms can not be empty");
		int left = 0;
		int right = arr.length-1;
		while(left<=right){
			int mid = (left+right)>>>1;
			int mid1 = mid;
			if(arr[mid].equals(t))
				return mid;
			/*
			 * find the first non-empty string to the right,
			 * if all the strings on the right are empty, mid will end up with
			 * larger than right(out of bound)
			 */

			while(mid<=right && arr[mid].trim().length()==0)
				mid++;
			/*
			 * find the first non-emptyp string to the left,
			 * if all the strings on the left are empty, mid1 will end up with
			 * smaller than left(out of bound)
			 */
			while(mid1>=left && arr[mid1].trim().length()==0)
				mid1--;
			//if both pointers are out of bound, target not found
			if(mid>right && mid1<left)
				return -1;
			else if(mid<=right && mid1>=left){
				int difLeft = t.compareTo(arr[mid1]);
				int difRight = t.compareTo(arr[mid]);
				if(difLeft==0)
					return mid1;
				if(difRight==0)
					return mid;
				if(difLeft>0 && difRight>0)
					left = mid+1;
				else if(difLeft<0 && difRight<0)
					right = mid1-1;
				else if(difLeft>0 && difRight<0){
					right = mid-1;
					left = mid1+1;
				}else{
					throw new IllegalArgumentException("The given array is not in ascending order.");
				}
			}else if(mid<=right){	//no left
				int dif = t.compareTo(arr[mid]);
				if(dif==0)
					return mid;
				if(dif>0)
					left = mid+1;
				else
					right = mid-1;
			}else{		//no right
				int dif = t.compareTo(arr[mid1]);
				if(dif==0)
					return mid1;
				if(dif>0)
					left = mid1+1;
				else
					right = mid1-1;
			}
		}
		return -1;
	}

Clap

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading ... Loading ...

Leave a comment

Your comment