【问题标题】:How to find elements that start with a sub strings inside a sorted ArrayList?如何在已排序的 ArrayList 中查找以子字符串开头的元素?
【发布时间】:2016-07-31 06:32:53
【问题描述】:

我有一个使用 java 的 33000 个元素的排序 arrayList,我怎样才能只列出以子字符串开头的元素。

例如: 我有一个字符串“空气”。所以我需要每个以“air”开头的单词(“airplane”、“airforce”、“airline”等)

有没有一种方法可以做到这一点而无需逐个迭代?

【问题讨论】:

  • 是的,有多种方法。到目前为止,您尝试过什么?
  • 如果列表没有排序,那么它将涉及遍历整个列表!
  • For 循环与正则表达式模式,但我在另一个循环中使用它。对每个循环进行大量搜索也是如此......
  • ArrayList 已排序
  • 然后二进制搜索你的前缀的插入索引,然后从那里开始。

标签: java search arraylist


【解决方案1】:

Stream API怎么样?

List<String> list = Arrays.asList("airplane", "airforce", "airline", "etc.");
List<String> prefixWords = list.stream()
            .filter(word -> word.startsWith("air"))
            .collect(Collectors.toList());

prefixWords.forEach(System.out::println);

【讨论】:

  • 这是 java 8 最简单的解决方案。
【解决方案2】:

所以,假设你有一个排序的ArrayList&lt;String&gt;words,你可以这样做:

String prefix = "air";
int start = Collections.binarySearch(words, prefix);  
// index of prefix OR -(insertion point) - 1
if (start < 0)  // prefix is not contained as a whole word
    start = -start - 1;
int end = start;
while (end < words.size() && words.get(end).startsWith(prefix))
    end++;
List<String> prefixWords = words.subList(start, end);

二分查找是O(log(N)),切片是O(K),其中K 是子列表的长度(以“air”为前缀的单词数)。所以,这应该比遍历列表要好得多,至少在不同的前缀上摊销(最坏的情况是所有单词都以前缀开头)。

【讨论】:

  • 什么是结束?是我的 arrayList 的结束索引吗?
  • 已更新。 end 是子列表的结束索引(不包括)。
【解决方案3】:

二分搜索会首先像goto一样

    public static int binarySearch(ArrayList<String> sortedArray,String find){
        int lowerBound=0;
        int upperBound=sortedArray.size()-1;

        while(true){
            int midIndex=lowerBound+((upperBound-lowerBound)/2);
            String curr=sortedArray.get(midIndex);
            if(upperBound<lowerBound){
                System.out.println("word not found");
                return -1;
            }

            if (curr.equals(find))
                return midIndex;

            if(curr.compareTo(find)>0)
                upperBound=midIndex-1;

            if(curr.compareTo(find)<0)
                lowerBound=midIndex+1;
        }
    }

然后,在您获得索引后,向左和向右遍历列表,直到您到达列表/开头的结尾或与您正在搜索的前缀不同的前缀

       public static ArrayList<String> makeList(ArrayList<String> sortedArray,String startingWith){
        ArrayList<String> result=new ArrayList<>();
        ArrayList<String> temp=new ArrayList<>(sortedArray.size());            

        for(int i=0;i<sortedArray.size();i++){
            temp.add(" ");
        }

        //copy sortedArray to temp
        for(String s: sortedArray){
            if(s.length()>startingWith.length()) {
                temp.set(sortedArray.indexOf(s), s.substring(0, startingWith.length()));
            } else temp.set(sortedArray.indexOf(s),s);

        }


        int index=binarySearch(temp,startingWith);
        result.add(sortedArray.get(index));

        int leftIndex=index;
        int rightIndex=index;         
        while(true){

            //if left and right index dont go out of bounds cont. iterating
            if ((leftIndex - 1) >= 0) leftIndex--;
            if ((rightIndex + 1) < sortedArray.size()) rightIndex++;

            //if left and right index are at end of list return
            if( (rightIndex>=sortedArray.size()) && (leftIndex<0) ) return result;

            boolean isLeft;
            boolean isRight;

            if( sortedArray.get(leftIndex).length()>startingWith.length() ) {
                isLeft = sortedArray.get(leftIndex).substring(0,startingWith.length()).equals(startingWith);
            }else isLeft=false;


            if( sortedArray.get(rightIndex).length()>startingWith.length() ) {
                isRight = sortedArray.get(rightIndex).substring(0,startingWith.length()).equals(startingWith);
            }else isRight=false;

            if(!isLeft && !isRight) return result;


            if( isRight ) result.add(sortedArray.get(rightIndex));
            if( isLeft ) result.add(sortedArray.get(leftIndex));

        }

    } 

【讨论】:

    【解决方案4】:

    如果您事先不知道以“air”开头的元素的数量,您的搜索将是 O(n) 的数量级。没有蛮力方法或平衡树搜索可以在少于 O(n) 的时间内实现。

    【讨论】:

      猜你喜欢
      • 2011-11-30
      • 2012-10-11
      • 1970-01-01
      • 2023-04-01
      • 2010-09-16
      • 2012-06-30
      • 2013-02-07
      • 2022-08-11
      相关资源
      最近更新 更多