给定一个编码字符串 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 个字母。
思路:我们定义两个数组sum和sum2分别存储当前总字符串长度和当前的串是否是上一次得到的串的重复(若sum2=0代表不是),然后我们通过对sum数组不断二分从而缩小k值,当遇到索引k所对应的字母是新加的,则直接返回答案即可。
class Solution {
public String decodeAtIndex(String S, int K) {
long num=0,k=K;
int n=S.length();
long[] sum=new long[n];
long[] sum2=new long[n];
Map<Integer,String> map=new HashMap<>();
for(int i=0;i<n;i++) {
if(S.charAt(i)>='a' && S.charAt(i)<='z') {
num++;
map.put(i, S.substring(i, i+1));
sum2[i]=0;
}
else {
sum2[i]=num;
num=num*(S.charAt(i)-'0');
}
sum[i]=num;
}
while(k>=0) {
int l=0,r=n-1,p=0;
while(l<=r) {
int mid=(l+r)/2;
if(sum[mid]>=k) {
p=mid;
r=mid-1;
}
else
l=mid+1;
}
if(sum2[p]==0)
return map.get(p);
k=k%sum2[p];
if(k==0) k=sum2[p];
}
return "";
}
}