【问题标题】:First Index of String in Infinite String - Java无限字符串中字符串的第一个索引 - Java
【发布时间】:2023-04-07 10:37:02
【问题描述】:

简介

我有一个无限的字符串。这个字符串的长度在我们的想象中是无限的,不能被限制。假设我们在String中有一个这样的序列:

“123456789...”

数字 9 后面的 实际上代表下一个序列。所以,它会是这样的:

“...7891011121314...”

要求

在本节中,我想解释一下需求。要求是找到输入字符串第一次出现的索引(称为n)。举个例子吧:

示例 1

n = "3"

n = 2 的第一个索引

示例 2

n = "910"

n = 8 的第一个索引

问题

我已经编写了算法来查找字符串 n 的索引。但是该算法只是一个while循环来检查n的索引,如果没有找到n的索引,则一个接一个地添加下一个序列号。我想要一个更好的算法来找到 n 的第一次出现的索引,而不依赖于循环或更少的循环。至少,如果 n 的值很大(例如:123456790 或 62716855),算法的运行时间不会超过 2 秒。

---编辑---

我的代码片段:

while(!num.contains(s)){
    num +=start.toString();
    start = start.add(BigInteger.ONE);
} 

这是我的完整代码:My Full Code

【问题讨论】:

  • 显示你已有的代码。
  • 很好的练习,但是……你试过什么?
  • 说算法运行时间超过 2 秒是没有意义的。根据使用的机器和代码的质量,相同的算法可能需要非常不同的时间才能找到解决方案。你应该在这里考虑的是time complexity。还请提供您的代码,以便我们了解除代码复杂性之外的其他导致性能下降的潜在原因。
  • 我已经编辑了问题和我的代码和完整代码。请看一下。

标签: java string algorithm sequence indexof


【解决方案1】:

以下是有关如何解决此问题的一般说明。将其翻译成 Java 仍然具有挑战性。

您的输入字符串基本上是所有自然数的无限序列 1 2 3 4 5 6 7 8 9 10 11 12 13 ....

我认为练习的重点是识别子字符串n 所属的输入字符串的第一个自然数子序列,然后在不实际构造大的“无限”字符串的情况下计算其索引。

为此,您必须尝试将子字符串n 拆分为数字尽可能少的递增序列。

首先您必须检查子字符串n 是否创建了一个数字序列。就是这种情况,例如,如果 n == 345678(请注意,n 可能同时包含一位数和两位数,例如 n == 345678910,您也应该能够识别)。

如果您在该步骤中失败,您应该寻找一个两位数的序列。例如,n == 33343536 就是这种情况。现在,这可能会变得更棘手,因为 n == 2333435363 也是一个两位数字的序列,但序列的前导和尾随数字(32 和 37)被截断。

如果再次失败,则查找 3 位数字序列。

如果没有找到任何序列,则将整个子字符串 n 视为大字符串中的单个数字。

现在,假设n199319941995,并且您在上一步中发现序列中的第一个数字是1993。剩下的工作是计算输入字符串中数字1993 的索引。您知道单个数字采用 1*9 索引。两位数采用 2*90 索引。三位数字采用 3*900 索引。 1000 到 1993 之间的 3 位数字采用 4*993 索引。因此 1993 的索引是 1*9+2*90+3*900+4*993,这是子字符串199319941995 的第一个索引。

【讨论】:

  • 那么,当数字是随机的并且不形成任何序列时,我是否可以通过循环找到索引?
  • @fairyhunter 这个数字永远不会是随机的。它总是形成一个序列(一个或多个数字)。查找索引始终相同 - 计算较短数字占用的索引 + 长度相同的数字占用的索引,这些数字小于您要查找的索引的数字。
  • 很好的解释,恐怕字符串 n 并不总是序列号。字符串 n 可以是随机数。不过,无限字符串始终是自然序列号。
  • @fairyhunter 62716855 是一个只有一个数字的序列,所以你必须在无限字符串中找到数字 62716855 的索引(使用我描述的相同方法 - 1*9 + 2*90 + 3*900 + 4*9000 + 5*90000 + 6+900000 + 7*9000000 + 8 * 52716855 - 1)
  • @fairyhunter 我减了一个,因为第一个索引是 0,但无限字符串中的第一个数字是 1。也许我计算错了什么。哦,我知道我现在错了。谢谢。
【解决方案2】:

使用String,我们可以这样做,

String largeValue  = "2323254534534642342354346876985374";
String searchValue = "32545345346423423543468769";
if(largeValue.contains(searchValue)){
    System.out.println("The index is : "+largeValue.indexOf(searchValue));
}

注意:- 我们只能使用largeValue.indexOf(searchValue),如果它返回-1意味着searchValue不在largeValue中,否则你会得到特定的索引。

【讨论】:

  • 是的,我想知道为什么不简单地使用indexOf,因为字符串是“无限的”,如果方法在第一次出现时停止,我会搜索它是否在任何地方(这没有意义继续寻找......)。注意:我不会调用contains 后跟indexOf,只存储返回的索引;)
  • 如果 n 的长度达到 15,就会出现问题。所以,恐怕代码会运行得更久。
  • @fairyhunter 方法在寻找第一个字符,然后检查下面,如果匹配,则到此结束,如果不匹配,则继续搜索第一个字符,依此类推...非常有效...我不知道您在运行什么代码,但是迭代 15 个字符的 String 真的没那么长...
  • @AxelH 固定注释 - 15个字符是指子字符串的长度,不是输入字符串的长度,但可以更长。
  • 序列不应该在增加吗?您的字符串是随机的,并且不正确。此外,如果说它是无限的,我认为它更像是一个字符流,而不是一个字符串
【解决方案3】:

据我了解,您可以使用String.indexOf 方法:

int found = longString.indexOf(searchString);
if(found != -1) System.out.println("Found index is: " + found);

【讨论】:

    【解决方案4】:

    除了实现一些高级算法,如另一个答案中提到的 Knuth-Morris-Pratt,您还可以使用有限状态机进行字符串匹配。这样做的好处是回溯成本远低于 while 循环的幼稚解决方案,但可以轻松地与标准 javas 正则表达式一起使用。解决方案是:

    CharSequence text = // the long sequence of text
    String search = // whatever you want to search
    Matcher matcher = Pattern.compile(Pattern.quoute(search)).matcher(text);
    matcher.find();
    int startIndex = matcher.match();
    

    【讨论】:

      【解决方案5】:

      我的理解是:你有一个像 String sequence = "1234567891011121314"; 这样的序列字符串。 您想在其中找到输入字符串 say ("910") 的第一次出现的索引。 如果我的理解是正确的,我们在 Java 中有内置函数来执行此操作 - sequence.indexOf(input_string) -String str = "1234567891011121314"; String sub = "910"; System.out.println(str.indexOf(sub));

      【讨论】:

        【解决方案6】:

        我的想法是对数据进行统计,其中一种方法是拥有每个数字(0到9)的所有索引位置并根据索引数据进行搜索,因为输入文本很大并且搜索速度会太慢了,所以下面会导致在同一个大文本上快速搜索多个搜索输入:

        使用 C# 的示例: (在 Java 中使用:

        HashMap<K, V> and ArrayList<T> and Character.getNumericValue(c)
        

        )

        string input = "................";
        
        Dictionary<int, List<int>> numIndex = new Dictionary<int, List<int>>(10);
        
        for(int index = 0; index < 10; index++)
             numIndex.Add(index , new List<int>(20));
        
        for(int charIndex = 0; charIndex < input.Length; charIndex++){
             for(int index = 0; index < 10; index++){
                  int value = Convert.ToInt32(input[charIndex]);
                  if(value == index)
                        numIndex[value].Add(charIndex);
             }
        } 
        
        int FindIndex(string nValue){
            // nValue = "213654789";
        
            foreach(int indexValue in numIndex[Conver.ToInt32(nValue[0])])
            {
                 if(nValue == input.Substring(indexValue, nValue.Length))
                      return indexValue; // First Index Value Found
            }
            return -1;
        }
        

        编辑添加无限缓冲区的想法,没有缓冲区关闭检查逻辑的伪代码逻辑,我留给用户添加它:

        int charIndex = -1
        char charValue 
        string textValue = "456321587"
        char[] textCompare = new char[textValue.Length]
        while charValue = charsBuffer.ReadChar()
        BEGIN
             charIndex = charIndex + 1 
             if textValue[0] == charValue 
             BEGIN
                  int count = 1
                  textCompare[0] = charValue 
                  while count < textValue.Length
                  BEGIN
                      textCompare[count] = charsBuffer.ReadChar()
                      count = count + 1
                  END
                  if textValue == new string(textCompare)
                      return charIndex
                  charIndex = charIndex + textValue.Length 
             END
        END
        return -1
        

        charsBuffer.ReadChar() 可能是大文本文件缓冲区或网络文本缓冲区或任何大文本缓冲区

        【讨论】:

        • 不错的代码,但问题仍然存在。输入是无限的,所以长度不是固定的。如果将索引存储到字典中,它仍然需要迭代以获得真正的索引。
        猜你喜欢
        • 2020-01-08
        • 1970-01-01
        • 2011-05-29
        • 2017-09-21
        • 2016-04-13
        • 1970-01-01
        • 1970-01-01
        • 2021-04-29
        • 2013-10-02
        相关资源
        最近更新 更多