【问题标题】:Efficient searching according to "starts with"根据“开始于”进行高效搜索
【发布时间】:2018-01-29 04:08:00
【问题描述】:

我面临以下问题的写入逻辑问题。

我有两个字符串数组列表:

  • List1:包含 500 万个字符串

  • List2:将根据用户输入创建并包含一些字符串/字符(例如 a、b、c、g、l、pd、sp、mta)

现在我必须根据 list2 中的startsWith 字符串将list1 拆分为多个列表,就像上面的情况一样。我需要创建 8 个以 'a'、'b'、'c'、'g 开头的列表>'、'l'、'pd'、'sp' 和 'mta'

但上面的条件是我只需要迭代 List1 或 List2 一次。即算法的最差复杂度应该是 List1(500 万)的大小。

允许使用 collections.sort() 方法

我尝试过的代码

    // Create List for search strings.
    List<String> CharList = new ArrayList<String>();
    CharList.add("a");
    CharList.add("b");
    CharList.add("e");
    CharList.add("z");
    CharList.add("4");
    CharList.add("1");
    CharList.add("zi");

    List<String> recordList = new ArrayList<String>();

    // Creating dummy data with 100 character in live environment it can be
    // around 50 lakhs strings
    for (int i = 0; i < 100; i++) {
        char[] chars = "abcdefghijklmnopqrstuvwxyzABCGDKL0123456789".toCharArray();
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i1 = 0; i1 < 6; i1++) {
            char c = chars[random.nextInt(chars.length)];
            sb.append(c);
        }
        String output = sb.toString();
        recordList.add(output);
    }

    // Adding some data mannually
    recordList.add("zink");
    recordList.add("zebra");
    recordList.add("zzzzzz");
    Collections.sort(CharList, String.CASE_INSENSITIVE_ORDER);
    Collections.sort(recordList, String.CASE_INSENSITIVE_ORDER);

    System.out.println("RECORDLIST ===>" + recordList);
    System.out.println("***************************************************");
    System.out.println("Charlist ===>" + CharList);
    System.out.println("***************************************************");

    List<List> lists = new ArrayList<List>();

    int startIndex = 0, charPointer = 0;
    while (startIndex < recordList.size() && charPointer < CharList.size()) {
        List<String> temp = new ArrayList<String>();

        boolean isHit = false;
        String currentRecord = recordList.get(startIndex);
        String partitionSattement = CharList.get(charPointer);
        while (currentRecord.startsWith(partitionSattement.toUpperCase())
                || currentRecord.startsWith(partitionSattement.toLowerCase())) {
            temp.add(recordList.get(startIndex));
            isHit = true;
            startIndex++;
        }
        if (!isHit) {
            startIndex++;
        }
        if (!temp.isEmpty()) {
            lists.add(temp);
            System.out.println(CharList.get(charPointer) + "====>" + temp);
        }
        charPointer++;
    }

【问题讨论】:

  • 你的代码在哪里?

标签: java algorithm loops search


【解决方案1】:

在这种情况下,仅使用 String startsWith 方法将不起作用。考虑一下如果第一个模式与任何输入都不匹配会发生什么 - 您将遍历输入列表中的所有字符串而找不到匹配项,即使后续模式匹配确实存在。

我们需要做的是将每个模式与每个输入字符串的初始字符进行比较并进行相应的处理。假设我们有一个输入字符串str 和一个模式pat。让subStr 成为str 的第一个pat.length() 字符。现在我们可以使用String compareToIgnoreCase 方法比较subStrpat。需要考虑三种情况:

subStr &lt; pat 移动到下一个输入字符串。

subStr == patstr 添加到pat 的输出并移至下一个输入字符串。

subStr &gt; pat 移动到下一个模式。

这里有一些代码来说明(我尽可能保留了你的变量名)。

List<List<String>> output = new ArrayList<>();
for(int i=0; i<CharList.size(); i++) output.add(new ArrayList<String>());

int startIndex=0;
int charPointer=0;              
while(startIndex < recordList.size() && charPointer < CharList.size())
{
    String charStr = CharList.get(charPointer);
    String recStr = recordList.get(startIndex);

    int cmp;
    if(recStr.length() < charStr.length()) 
    {
        cmp = -1;
    }
    else
    {
        String recSubStr = recStr.substring(0, charStr.length());           
        cmp = recSubStr.compareToIgnoreCase(charStr);           
    }

    if(cmp <= 0)
    {
        if(cmp == 0) output.get(charPointer).add(recStr);
        startIndex++;
    }
    else 
    {
        charPointer++;
    }
}

for(int i=0; i<CharList.size(); i++)
{
    System.out.println(CharList.get(i) + " : " + output.get(i));
}

另外,您应该注意,当您包含一个本身以另一个模式(例如"zi""z")开头的模式时,将永远不会匹配较长的模式,因为较短的模式将捕获所有输入。

【讨论】:

    【解决方案2】:

    我可以在您的代码中看到两个问题:

    1. 您应该删除以下部分:

      if (!isHit) {
          startIndex++;
      }
      

      实际上,您根本不需要 isHit 变量。如果一个字符串与一个模式不匹配,那么你仍然需要将它与下一个模式进行比较。

    2. 您应该按降序对数组进行排序。正如 SirRaffleBuffle 在另一个答案中指出的那样,您应该首先将字符串与较长的模式进行比较。对字符串和模式进行降序排序会自动解决这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-07
      • 1970-01-01
      • 1970-01-01
      • 2015-12-07
      • 2015-02-15
      相关资源
      最近更新 更多