880. 索引处的解码字符串
给定一个编码字符串 S。为了找出解码字符串并将其写入磁带,从编码字符串中每次读取一个字符,并采取以下步骤:
如果所读的字符是字母,则将该字母写在磁带上。
如果所读的字符是数字(例如 d),则整个当前磁带总共会被重复写 d-1 次。
现在,对于给定的编码字符串 S 和索引 K,查找并返回解码字符串中的第 K 个字母。
示例 1:
输入:S = “leet2code3”, K = 10
输出:”o”
解释:
解码后的字符串为 “leetleetcodeleetleetcodeleetleetcode”。
字符串中的第 10 个字母是 “o”。
示例 2:
输入:S = “ha22”, K = 5
输出:”h”
解释:
解码后的字符串为 “hahahaha”。第 5 个字母是 “h”。
示例 3:
输入:S = “a2345678999999999999999”, K = 1
输出:”a”
解释:
解码后的字符串为 “a” 重复 8301530446056247680 次。第 1 个字母是 “a”。
提示:
- 2 <= S.length <= 100
- S 只包含小写字母与数字 2 到 9 。
- S 以字母开头。
- 1 <= K <= 10^9
- 解码后的字符串保证少于 2^63 个字母。**
思路
首先阅读题目要求
- 每次读取一个字符
- 读取字符为字母,记录该字母
读取为数字d,前面记录的字符串会复制d-1次,并加上末端
读了上述要求后,自然而然地想到直接的算法:按照输入字符串进行遍历,遍历到字母, 则存储; 遍历到数字,则将前面储存的字符串以d-1次循环加在原字符串后方。代码如下:
string decodeAtIndex(string S, int K) {
const char * s = S.data();
int length = S.length();
vector<char> output;
int i = 0;
while (s[i] != '\0')
{
if (s[i] - 'a' >= 0 && s[i] - 'z' <= 0) //字母则存储
{
output.push_back(s[i]);
i++;
}
else //如果是数字
{
int count = s[i] - '0'- 1; //将char数字转化为int并-1
int length0 = output.size();
while (count > 0)
{
for (int i = 0; i < length0; i++) //将原字符串的内容加在末尾
{
output.push_back(output[i]);
}
count--;
}
i++;
}
}
string res = {output[K-1]};
return res;
}
这样的代码符合一般思维,可以轻松地过示例一与示例二。
但是,上面的代码实际上是错误的,没有考虑到出题人意图的!
这样是过不了示例三的, “a” 重复 8301530446056247680 次无疑会造成存储的字符串对象的溢出,leetcode会提示超出内存限制。那么该怎么优化我们的代码呢,
其实题目已经给出提示了,就是索引Index
,我们只需要输出下标对应的字母,也就是说我们将K值还原成对应S字符串中某个下标i
,再输出S[i]
就是我们的输出值了
我们用curIndex
记录当前decode字符串长度,i
记录对应S中的字符位置,过程如下:
首先对S[i]一个个遍历,如果是字母,就将curIndex+1
,如果碰到数字,就将curIndex
乘以这个数字,当然同时要判断,索引与K的关系。如果索引小于K,就一直遍历下去,如果大于等于K,这时可以停止遍历,因为K对应的下标已经在我们的decode字符串之前了,后面的工作是没必要的,笔者看见有些解法是遍历到结束,实际上这部分工作是可以省略的。
确定了我们已经decode了足够的长度之后,将curIndex
往回退,如果是数字,就要除以这个数字,变成单倍数的字符串,相应的,第K个也要变成单倍数的,最后找到对应的s[i],并输出。
代码如下:
string decodeAtIndex(string S, int K) {
const char * s = S.data();
long curIndex = 0; //注意这里是long,不然有测试案例会长度溢出
int i = 0;
for (; curIndex < K; i++)
{
if (s[i]>='a' && s[i]<='z')
curIndex++;
else
curIndex = curIndex*(s[i]-'0');
}
while (i--)
{
if (s[i] >= '2' && s[i] <= '9')
{
curIndex = curIndex / (s[i] - '0');
K = K % curIndex;
}
else if (K % (curIndex--)==0)
{
string res = {s[i]};
return res;
}
}
}