1

How can I implement binary search to find a string with a particular prefix in generic array (which in this case will be a string[]). I tried compareTo but that wouldn't help because i have to use a string prefix. eg String prefix "Bi" bill, bilards ...etc..

Implement the following method to return all strings in an alphabetically sorted array that start with a given prefix. For instance, given a prefix “bi”, the returned strings are ”Bill Clinton”, ”Bill Gates”, and ”Bill Joy”. Note that all string comparisons should be case INSENSITIVE. The strings in the returned list must be in the order in which they appear in the array. Your implementation must be based on binary search, and must run in worst case O(log n+k) time, where n is the length of the array, and k is the number of matching strings. Assume that the array has no duplicate entries. If there are no matches, you may either return null, or an empty array list.

You may use the following String methods (in addition to any others you may recall): boolean startsWith(String s) int compareTo(String s) int compareToIgnoreCase(String s) String toLowerCase(String s) String toUpperCase(String s) (As for ArrayList, you only need to use the add method to add an item to the end of the array list.) You may write helper methods (with full implementation) as necessary. You may not call any method that you have not implemented yourself

public static <T extends Comparable<T>> ArrayList prefixMatch(T[] list, String prefix) {

        ArrayList<T> result = new ArrayList<T>();
        int lo = 0;
        int hi = list.length - 1;

        while(lo <= hi) {

            int mid = (hi + lo) / 2;

            list[mid].startsWith(prefix) ? 0 : list[mid].compareTo((T) prefix));


        }   

        return null;
    }
2
  • 2
    An example would help making your question easier to understand. Commented Mar 3, 2012 at 3:07
  • given a array of names of people and a prefix say "bi" i want all the names to be added to a arraylist that the entire question but i want to find the name using binarysearch with a given prefix rest i can i take care Commented Mar 3, 2012 at 3:21

4 Answers 4

5

You can use default binary search with custom comparator as your base, and then work our range by your self. I think the right algorithm would be:

  1. Perform binary search on given array. Use comparator which checks only for prefix.
  2. As result you'll get index of string which starts with your prefix
  3. Walk to the left to find first string which matches prefix, remember position.
  4. Walk to the right to find first string which matches prefix, remember position.
  5. Copy elements from range start to range end from original array. That will be your desired array of all elements with prefix match condition.

Below is implementation in java. It works in happy case scenario but will crash if(I left those checks out to make code look simple):

  • No strings with given prefix exist in original array
  • There are string with length less then prefix length

Also if you need binary search implementation you could check source of Arrays.binarySearch

public class PrefixMatch {

    public static void main(String[] args) {

        final String[] prefixMathces = prefixMatch(new String[] { "Abc", "Abcd", "Qwerty", "Pre1", "Pre2", "Pre3", "Xyz", "Zzz" }, "pre");

        for (int i = 0; i < prefixMathces.length; i++)
            System.out.println(prefixMathces[i]);
    }

    public static String[] prefixMatch(final String[] array, final String prefix) {

        final Comparator<String> PREFIX_COMPARATOR = new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.substring(0, prefix.length()).compareToIgnoreCase(o2);
            }
        };

        final int randomIndex = Arrays.binarySearch(array, prefix, PREFIX_COMPARATOR);

        int rangeStarts = randomIndex, rangeEnds = randomIndex;

        while (rangeStarts > -1 && array[rangeStarts].toLowerCase().startsWith(prefix.toLowerCase()))
            rangeStarts--;

        while (rangeEnds < array.length && array[rangeEnds].toLowerCase().startsWith(prefix.toLowerCase()))
            rangeEnds++;

        return Arrays.copyOfRange(array, rangeStarts + 1, rangeEnds);
    }
}
Sign up to request clarification or add additional context in comments.

Comments

2

I assume that you currently have something like this? :

arrayElement.compareTo(prefix)

If so, you can change it to look like this:

arrayElement.startsWith(prefix) ? 0 : arrayElement.compareTo(prefix)

7 Comments

@KaranSingh: For information on the String.startsWith method, see its documentation. For full information on the conditional operator ? :, see section 15.25 of The Java Language Specification, Third Edition; but, in brief: if a is true, then a ? b : c means b, and if a is false, then it means c.
also i am getting a error for that statement above "type mismatch"
could you change your implementation to ifelse so i can understand it better
@KaranSingh: What you're trying to do doesn't really make sense. You can't compare a String instance to an instance of an arbitrary type T.
i know the question my instructor gave has this as a review question for an exam. I am just trying to implement what he asked me do. I only care about passing my exam
|
0

I suggest looking into the API code for this. There is an Arrays class that you can check out in the java.lang package and learn from there.

Comments

0

Working on a similar problem right now. I believe pseudo code will go something like yours. I created a pojo class Song. A song is made up up three strings artist,title, and lyrics.

When you create a song object you get :

     //     Artist             Title                     Lyrics..

Song a = ["Farmer Brown", "Oh' Mcdonalad", "Oh'mcdonal had a farm eh i oh i oh"]

public class Song implements Comparable<Song> {

private String _artist;  
private String _lyrics;
private String _title;

   // constructor
   public Song(String artist, String title, String lyrics) {
   this._artist = artist;
   this._title = title;
   this._lyrics = lyrics;
   }

   public String getArtist() {
       return _artist;
   }

   public String getLyrics() {
       return _lyrics;
   }

   public String getTitle() {
       return _title;
   }

   public String toString() {
       String s = _artist + ", \"" + _title + "\"";
    return s;
   }

   //This compare two song objects
   public int compareTo(Song song) {
       String currentSong = song.toString();
       int x = currentSong.compareToIgnoreCase(this.toString());  
       return x;
   }

This is your method here that will take in the array of songs and your prefix and use the compare method to see if they match. If they match the compareTo method returns a 0. If you get a 0 then you know you have found your song so return the arrayOfSongs[index where song is found].

I have not coded up my search yet but I modified yours to match my code. I have not tested it yet. I don't think you even need a compareTo method but you can use it. Also for scaling the binary search should return a list of songs that might match as you might have multiple songs that start with "xyz" . Kind of when you start searching on google with prefix "do" you get a drop down of "dog, donut,double" which gives the user something to choose like a search engine.

    public static ArrayList<Song> search (String[] arrayOfSongs , String enteredPrefix) {
     ArrayList<Song> listOfMatches = new ArrayList<Song>;
     int mid;
     int lo = 0;
     int hi = arrayOfSongs.length - 1;
     while(lo <= hi) 
     {
     mid = (hi + lo) / 2;
       if(arrayOfSongs[mid].startsWith(enteredPrefix))
       {
         System.out.println("Found a match, adding to list");
         listOfMatches.add(arrayOfSongs[mid]);
       }    
    }   
    return listOfMatches;
}

Once you have a listOfMatches of possible suspects of the song you want you can use the compareTo method in some way.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.