给出字符串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个字符。我为此苦苦挣扎太久了,任何帮助将不胜感激!
答案 0 :(得分:4)
如果您知道某个字符串s
是另一个字符串t
重复了n
次,则字符串k
中索引为s
的字符等于字符串k2 = k mod t.length
中索引为t
的字符。我们可以用它来解决此任务:
确定结果字符串的长度:
len = 0
for each character ch in s
if ch is digit
len = len * digit
else
len = len + 1
以相反的顺序遍历字符串
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
语句,您会发现它只会生成所需数量的字符串。