题目:https://leetcode-cn.com/problems/decoded-string-at-index/
思路:
看到 数据范围 "解码后的字符串保证少于 2^63
个字母",单纯地拼接字符串不实际,即使不考虑时间问题,就连内存也会爆掉,所以应该是找规律,找规律最基本的就是找循环节(比如说abc3d4,其中有"a","ab" , "abc","abc abc abc","abc abc abcd","abcabcabcd....abcabcabcd" 六个循环节,后一个循环节是由前一个循环节得到的)。
循环节跟我们要求的第K位的字符有什么关系?因为,最终得到的字符串的每一个字符 就是 某个循环节中的一个字符(因为最终的字符串都是由 循环节不断循环循环得到的.),自然第K个字符,也是某个循环节的一个字符,我们要确定第K个字符最先出现在哪个循环节,我们就能得出这个字符是什么,分两步就可以求出结果。
第一步:求出每个循环节长度放到数组arr[],和 每个循环节对应的最后一个字符放到数组recordChar[]
定义一个 int arr[] , arr[i] 表示前i个字符的循环节长度。recordChar[]记录该循环节的最后一个字符。
那么 "abc3d4" 的arr数组就是 arr[] = [1,2,3,9,10,40], recordChar[] = ['a','b','c','c','d','d'];
i=0 "a" 循环1次,所以循环节长度arr[0]=1,recordChar[0]='a'; i=1 "ab"循环一次,循环节长度arr[1]=2,recordChar[1]='b';
i=2 "abc" 循环1次,循环节长度arr[2]=3,recordChar[2]=‘c’; i=3 "abc" 循环3次, 循环节长度 arr[3] = arr[2]*3 =9,recordChar[3]=recordChar[2]='c';
i=4 "abc3"循环3次加上"d",循环节长度arr[4] = arr[3]+1 = 10,recordChar[4]='d';
i=5 "abc3d"循环4次,循环节长度arr[5] = arr[4]*4 = 40,recordChar[5]='d';
第二步:根据K的值,确定K位置的这个字符最先出现在哪个循环节中,这个循环节最后一个字符就是我们要求的字符。
很明显,字符 ch 最先出现在哪个循环节,那么这个循环节的最后一个字符一定是 ch ,仔细想想。
前面的例子S = "abc3d4",我们已经得出:arr[]=[1,2,3,9,10,40],recordChar[] = ['a','b','c','c','d','d'];
比如说 'a' 这个字符就是最开始出现在arr[0]这个循环节 , 所以recordChar[0] = 'a';字符'd'最开始出现在arr[4]这个循环节中,所以recordChar[4] = 'd'。
现在我要求S = "abc3d4" K=13的字符:
从后往前(40->10->....->1)遍历数组arr[]=[1,2,3,9,10,40],recordChar[] = ['a','b','c','c','d','d'];
从arr[5]开始遍历,长度比K大的循环节全部跳过(因为我们要知道K最先出现在哪个循环节!K=13 的字符一定存在于arr[5]=40这个循环节中,而arr[5]是由 arr[4]得到的,那么我们可以进一步缩小范围,走到arr[4] .....,直到我们找到arr[i]<=K的情况),
接下来找到arr[4]=10 (此时K>=arr[4]),
求余:K=K%arr[4]=3,K!=0 ,说明不是这个循环节最后一个字符record[4]='d',应该是更前面的循环节,所以可以缩小范围"abc3"(本来是"abc3d",现在缩小范围"abc3"),继续寻找;
此时问题转化为:我们要求 S="abc3" K=3的字符,同样地,
我们只需要 继续往前遍历,找到 arr[2]=3 (K>=arr[2]) , K=K%arr[2] = 0,说明最先出现在arr[2]这个循环节,字符就是recordChar[2] , 所以 位置 K=13 对应的字符 就是 recordChar[2] = 'c'; 答案就是'c' 。
class Solution {
public String decodeAtIndex(String S, int K) {
long k = K;
int len = S.length();
long arr[] = new long [len];
char recordChar [] = new char [len];
arr[0] = 1;
recordChar[0] = S.charAt(0);
int i = 1;
long c = 1;
for(;i<len;i++)
{
char tmp = S.charAt(i);
if(tmp>='a' && tmp<='z'){
c = (c+1l);
arr[i] = c;
recordChar[i] = tmp;
}else{
c = c*(tmp-'0');
arr[i] = c;
recordChar[i] = recordChar[i-1];
}
}
i = i - 1;
String rs = "";
while(i>=0)
{
if(k>=arr[i])
{
k = k % arr[i];
if(k==0)
{
rs = recordChar[i]+"";
break;
}
}
i--;
}
return rs;
}
}
我想尽力讲清楚,可能导致有些部分冗余了,如果看不懂,可以查阅其他题解,谢谢。