有效地查找由整数重复的子字符串组成的字符串中的字符

时间:2019-02-22 07:21:37

标签: algorithm memory-efficient

给出字符串s和整数k。用以下规则(以示例为例)在由s组成的新字符串中找到第k个(第0个索引)字符的最节省空间的方法是什么:

从左到右迭代s中的每个char时,每当遇到整数(保证介于2到9之间)时,都将子字符串重复到该点为止。

ex)(s ='a2',k = 1): 从s->'aa',返回'a',因为它在新形成的字符串的索引1处

ex)(s ='a2b3',k = 2): 从s->'aabaabaab',返回'b'

很显然,幼稚的解决方案是先生成新字符串并在其中索引。但是,考虑到存在大量数字且字符串达到巨大尺寸的情况,肯定有更好的解决方案仅返回第k个字符。我为此苦苦挣扎太久了,任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:4)

如果您知道某个字符串s是另一个字符串t重复了n次,则字符串k中索引为s的字符等于字符串k2 = k mod t.length中索引为t的字符。我们可以用它来解决此任务:

  1. 确定结果字符串的长度:

    len = 0
    for each character ch in s
        if ch is digit
            len = len * digit
        else
            len = len + 1
    
  2. 以相反的顺序遍历字符串

     reverseS = reverse(s)
     curLen = len
     for each character ch in reverseS
         if ch is digit
             curLen = curLen / digit
             k = k mod curLen 
         else 
             if k == (curLen-1) then return ch as answer
             curLen = curLen - 1
    

因此,您根本不需要额外的内存(实际上O(1)),并且算法具有O(n)的时间复杂度,其中n是输入字符串的大小。

示例C ++代码:https://ideone.com/l8JxdQ

答案 1 :(得分:0)

我能想到的最好的办法是仅部分生成字符串。给定一个子字符串并重复多次,您当然可以使用modulo并确定要放在子字符串中的位置。这里的问题是,您要重复整个子字符串,直到看到一个数字为止,包括以前的任何子字符串重复项。

基本上,我想不出一种数学方法来执行此操作,我认为您将始终需要生成字符串,直到进行迭代之前,该字符串将导致s.length() > k或其中的最后一位数字输入字符串,以先到者为准。然后,您可以k%s.length()来找到正确的字符。

在C ++中看起来像这样:

char getK(string s, int k){
  string genString = "";
  string tempString = "";
  string digits = "0123456789";
  char c = '\0';
  const char * cc = &c;
  for (int i = 0; i < s.length(); i++){
    c = s[i];
    if (digits.find(c) != std::string::npos ){ // Digit
      if (i == s.length()-1 || k < genString.length()*atoi(cc)){ // Final digit or the next substring will contain genString[k]
        return genString[k%genString.length()]; // Modulo to find character location
      }
      tempString = genString;
      genString = "";
      for (int i = 0; i < atoi(cc); i++){
        genString += tempString;
      }
    } else { // Not a digit
      genString += c;
    }
    if (genString.length() > k) return genString[k]; // genString contains genString[k]
  }

  return genString[k]; // Silence compiler warnings
}

并且可以这样使用:

int main()
{
  string s = "a2b3c7g3g8r4w5rf5";
  for (int k = 0; k < 20; k++){
    cout << i << ": " << getK(s, k) << endl;
  }
}

如果在循环中放入一些cout语句,您会发现它只会生成所需数量的字符串。