查找字符串中的排列索引

时间:2013-11-16 15:38:10

标签: java

我刚刚尝试了编程挑战,但我无法成功完成。规范是从System.in读取2行输入。

  1. 1-100个空格分隔的单词列表,长度相同且在1-10个字符之间。
  2. 长度不超过一百万字符的字符串,仅包含上述列表的一次排列。返回此排列开始于字符串中的索引。
  3. 例如,我们可能有:

    dog cat rat
    abcratdogcattgh
    3
    

    结果3的位置(由System.out打印)。

    在列表中包含重复的单词是合法的:

    dog cat rat cat
    abccatratdogzzzzdogcatratcat
    16
    

    我制作的代码提供了答案开头的单词以前没有发生过。在此处的第二个示例中,我的代码将失败,因为dog已经出现在答案从索引16开始之前。

    我的理论是:

    1. 找到字符串
    2. 中每个单词出现的索引
    3. 提取此子字符串(因为我们有许多已知长度的已知单词,这是可能的)
    4. 检查所有单词是否出现在子字符串
    5. 如果是,请返回此子字符串出现在原始字符串
    6. 中的索引

      这是我的代码(它应该是可编译的):

      import java.io.BufferedReader;
      import java.io.InputStreamReader;
      
      public class Solution {
          public static void main(String[] args) throws Exception {
              BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
      
              String line = br.readLine();
              String[] l = line.split(" ");
              String s = br.readLine();
      
              int wl = l[0].length();
              int len = wl * l.length;
              int sl = s.length();
      
              for (String word : l) {
                  int i = s.indexOf(word);
                  int z = i;
                  //while (i != -1) {
                      int y = i + len;
                      if (y <= sl) {
                          String sub = s.substring(i, y);
                          if (containsAllWords(l, sub)) {
                              System.out.println(s.indexOf(sub));
                              System.exit(0);
                          }
                      }
                      //z+= wl;
                      //i = s.indexOf(word, z);
                  //}
              }
              System.out.println("-1");
          }
      
          private static boolean containsAllWords(String[] l, String s) {
              String s2 = s;
      
              for (String word : l) {
                  s2 = s2.replaceFirst(word, "");
              }
      
              if (s2.equals(""))
                  return true;
              return false;
          }
      }
      

      我能够通过取消注释while循环来解决我的问题并使其通过第二个示例。然而,这具有严重的性能影响。当我们输入100个单词,每个单词10个字符,字符串为1000000个字符时,完成所需的时间非常糟糕。

      鉴于测试平台中的每个案例都有最大执行时间,添加while循环会导致测试因未及时完成执行而失败。

      什么是更好的方法来解决这个问题?我感到失败了。

3 个答案:

答案 0 :(得分:0)

如果将字符串连接在一起并使用新字符串进行搜索。

String a = "dog"
String b = "cat"
String c = a+b; //output of c would be "dogcat"

像这样你会克服狗出现在某个地方的问题。

但如果catdog也是一个有效的值,这将不起作用。

答案 1 :(得分:0)

这是一种方法(伪代码)

stringArray keys(n) = {"cat", "dog", "rat", "roo", ...};
string bigString(1000000);
L = strlen(keys[0]); // since all are same length
int indices(n, 1000000/L); // much too big - but safe if only one word repeated over and over

for each s in keys
  f = -1
  do:
    f = find s in bigString starting at f+1  // use bigString.indexOf(s, f+1)
    write index of f to indices
    until no more found

完成所有操作后,您将获得一系列索引(第一个匹配字母的位置)。现在是棘手的部分。由于单词长度都相同,我们在10个不同的“集合”中寻找一系列间隔相同的索引。这有点乏味但它应该在有限的时间内完成。请注意,这样做比继续比较字符串更快(比较数字比确保完整的字符串匹配更快)。我会再把它分成两部分 - 首先找到“10个匹配的任何序列”,然后“看看这是否是一个独特的排列”。

sIndx = sort(indices(:))
dsIndx = diff(sIndx);
sequence = find {n} * 10 in dsIndx
for each s in sequence
  check if unique permutation

我希望这能帮到你。

答案 2 :(得分:0)

也许不是最好的优化版本,但是如何遵循理论给你一些想法:

  1. 计算行中所有单词的长度。
  2. 从列表中随机输入单词并找到其第一个的起始索引 occurence。
  3. 在此之前和之后取一个上面计算长度的子字符串 索引(例如,如果索引是15和3个字母,4个字母长,请 子串从15-8到15 + 11)。
  4. 复制单词列表,删除之前的随机单词。
  5. 检查附加/前置[word_length]字母以查看它们 匹配列表中的新单词。
  6. 如果单词与列表副本匹配,请将其从列表副本中删除并进一步移动
  7. 如果发现所有单词,则打破循环。
  8. 如果找不到所有单词,请找到下一个出现的起始索引 早先的随机词然后回到3。
  9. 为什么会有所帮助:

    • 你选择哪个单词并不重要,因为每个单词都是如此 无论如何都需要参加成功的比赛。
    • 你不必手动循环遍历很多角色, 除非有很多近乎完整的假匹配。
    • 随着假设的匹配不断增长,您在列表副本上的字数会减少,以便与之比较。
    • 还可以跟踪或最远的索引,所以你可以 有时限制拾取子串的向后长度(因为它 如果出现的话,不能与您已经去过的地方重叠 彼此相近)。