在由整数重复子串形成的字符串中有效地查找字符
Efficiently find character in a string formed by repeated substring by integer
给定一个字符串 s 和整数 k。什么是最 space 在由 s 形成的新字符串中使用以下规则(作为示例演示)查找第 k(0 索引)字符的最有效方法:
从左到右迭代 s 中的每个字符时,每当遇到一个整数(保证在 2 到 9 之间)时,您将重复该整数到该点的子字符串。
ex) (s = 'a2', k = 1) :
从 s -> 'aa', return 'a' 因为它在新形成的字符串
中位于索引 1
ex) (s = 'a2b3', k = 2) :
从 s -> 'aabaabaab', return 'b'
显然,天真的解决方案是先生成新字符串并对其进行索引。但是,考虑到数字很多并且字符串达到巨大大小的情况,当然必须有更好的解决方案 return 只是第 k 个字符。我已经为此苦苦挣扎了太久,我们将不胜感激!
我能想到的最好的办法就是只生成部分字符串。给定一个子字符串和重复它的次数,您当然可以只使用 modulo
并确定您将落在子字符串中的位置。这里的问题是,您要重复整个子串,直到您看到一个数字,包括任何先前的子串重复。
基本上,我想不出一种数学方法来执行此操作,我认为您始终需要生成字符串,直到导致 s.length() > k
的迭代之前的迭代或最后一次迭代输入字符串中的数字,以先到者为准。然后你可以k%s.length()
找到正确的字符。
在 C++ 中看起来像这样:
char getK(string s, int k){
string genString = "";
string tempString = "";
string digits = "0123456789";
char c = '[=10=]';
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
语句,您可以看到它只生成所需的字符串。
如果您知道某个字符串 s
是另一个字符串 t
重复 n
次,那么字符串 s
中索引为 k
的字符相等到字符串 t
中索引为 k2 = k mod t.length
的字符。我们可以用它来解决这个任务:
判断结果字符串的长度:
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
给定一个字符串 s 和整数 k。什么是最 space 在由 s 形成的新字符串中使用以下规则(作为示例演示)查找第 k(0 索引)字符的最有效方法:
从左到右迭代 s 中的每个字符时,每当遇到一个整数(保证在 2 到 9 之间)时,您将重复该整数到该点的子字符串。
ex) (s = 'a2', k = 1) : 从 s -> 'aa', return 'a' 因为它在新形成的字符串
中位于索引 1ex) (s = 'a2b3', k = 2) : 从 s -> 'aabaabaab', return 'b'
显然,天真的解决方案是先生成新字符串并对其进行索引。但是,考虑到数字很多并且字符串达到巨大大小的情况,当然必须有更好的解决方案 return 只是第 k 个字符。我已经为此苦苦挣扎了太久,我们将不胜感激!
我能想到的最好的办法就是只生成部分字符串。给定一个子字符串和重复它的次数,您当然可以只使用 modulo
并确定您将落在子字符串中的位置。这里的问题是,您要重复整个子串,直到您看到一个数字,包括任何先前的子串重复。
基本上,我想不出一种数学方法来执行此操作,我认为您始终需要生成字符串,直到导致 s.length() > k
的迭代之前的迭代或最后一次迭代输入字符串中的数字,以先到者为准。然后你可以k%s.length()
找到正确的字符。
在 C++ 中看起来像这样:
char getK(string s, int k){
string genString = "";
string tempString = "";
string digits = "0123456789";
char c = '[=10=]';
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
语句,您可以看到它只生成所需的字符串。
如果您知道某个字符串 s
是另一个字符串 t
重复 n
次,那么字符串 s
中索引为 k
的字符相等到字符串 t
中索引为 k2 = k mod t.length
的字符。我们可以用它来解决这个任务:
判断结果字符串的长度:
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