leetcode 880. 索引处的解码字符串方法详解(含错误与正确代码)

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;           
        }
    }
}

你可能感兴趣的:(ACM算法)