用字符串前缀实现二进制搜索?

时间:2012-03-03 03:04:51

标签: java arrays string

如何实现二进制搜索以在通用数组中查找具有特定前缀的字符串(在本例中为字符串[])。我试过compareTo,但这无济于事,因为我必须使用字符串前缀。例如字符串前缀“Bi”bill,bilards ......等..

实现以下方法以返回以给定pre fi x开头的按字母顺序排序的数组中的所有字符串。例如,给定一个pre fi x“bi”,返回的字符串是“Bill Clinton”,“Bill Gates”和“Bill Joy”。请注意,所有字符串比较都应为case INSENSITIVE。返回列表中的字符串必须按它们在数组中出现的顺序排列。您的实现必须基于二进制搜索,并且必须在最坏情况下运行O(log n + k)时间,其中n是数组的长度,k是匹配字符串的数量。假设数组没有重复的条目。如果没有匹配项,则可以返回null或空数组列表。

您可以使用以下String方法(除了您可能记得的任何其他方法): boolean startsWith(String s) int compareTo(String s) int compareToIgnoreCase(String s) String toLowerCase(String s) 字符串toUpperCase(String s) (对于ArrayList,您只需使用add方法将项添加到数组列表的末尾。) 您可以根据需要编写辅助方法(完全实现)。您可能不会调用任何您自己未实现的方法

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;
    }

4 个答案:

答案 0 :(得分:2)

我认为你现在有这样的东西? :

arrayElement.compareTo(prefix)

如果是这样,您可以将其更改为:

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

答案 1 :(得分:2)

您可以使用自定义比较器作为基础的默认二进制搜索,然后自行处理我们的范围。我认为正确的算法是:

  1. 在给定阵列上执行二进制搜索。使用比较器检查作为前缀。
  2. 结果,您将获得以您的前缀
  3. 开头的字符串索引
  4. 向左走,找到与前缀匹配的第一个字符串,记住位置。
  5. 向右走,找到与前缀匹配的第一个字符串,记住位置。
  6. 将元素从范围开始复制到范围从原始数组结束。这将是您所需的具有前缀匹配条件的所有元素的数组。
  7. 以下是java中的实现。它适用于快乐的情况,但如果(我将这些检查留下来使代码看起来很简单)会崩溃:

    • 原始数组
    • 中不存在具有给定前缀的字符串
    • 字符串的长度小于前缀长度

    此外,如果您需要二进制搜索实现,您可以查看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);
        }
    }
    

答案 2 :(得分:0)

我建议查看API代码。有一个Arrays类,您可以在java.lang包中查看并从那里学习。

答案 3 :(得分:0)

立即解决类似问题。我相信伪代码会像你的一样。我创建了一个pojo类Song。一首歌由三个字符串艺术家,标题和歌词组成。

创建歌曲对象时,您会得到:

     //     Artist             Title                     Lyrics..

歌曲a = [“农夫布朗”,“哦'麦克纳达德',”哦,有一个农场呃,我哦,哦,哦)“

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;
   }

这是你的方法,它将采用歌曲数组和你的前缀,并使用比较方法来查看它们是否匹配。如果它们匹配compareTo方法返回0.如果你得到0然后你知道你找到了你的歌曲所以返回arrayOfSongs [找到歌曲的索引]。

我还没有对我的搜索进行编码,但我修改了你的搜索以匹配我的代码。我还没有测试过。我认为您甚至不需要compareTo方法,但您可以使用它。此外,对于缩放二进制搜索,应返回可能匹配的歌曲列表,因为您可能有多首以“xyz”开头的歌曲。当你开始在google上搜索前缀为“do”时,你会得到一个“dog,donut,double”的下拉菜单,它可以让用户选择像搜索引擎一样的东西。

    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;
}

一旦你有一个listOfMatches可能的歌曲嫌疑人你想要你可以以某种方式使用compareTo方法。