问题描述
- 有一个字符串集合,所有字符串的长为 n, 只由 ‘a’, ‘b’, ‘c’ 三种字符组成,而且每个字符串中,所有相邻字符都是不同的。
请编写一个程序,返回这个字符串集合中,字典序第 k 小的字符串。 - 1≤n≤105
1≤k≤1018
如果所有可组成的字符串个数小于 k,返回一个空串。
样例
样例输入:
n = 3
k = 6
样例输出:
"bac"
- 说明
在样例中,长为 3 的字符串的集合如下:
[“aba”, “abc”, “aca”, “acb”
,“bab”, “bac”, “bca”, “bcb”
.“cab”, “cac”, “cba”, “cbc”]
所以字典序第 6 小的字符串为 “bac”。
思路
-
需要注意题目的条件限制
总可能性为3*2n-1,需要和k进行比较 -
需要观察abc串的性质来编写算法
当n>62时,k始终会小于总的可能性。 -
具体算法如下,该算法的时间复杂度 O(n) 空间复杂度为O(n).
python实现
class Solution:
"""
@param n: the length of the string.
@param k: the kth Lexicographically smallest that result should be.
@return: return the kth Lexicographically smallest string.
"""
def kthString(self, n, k):
# write your code here.
maxL = 2**62*3 if n>62 else 2**(n-1)*3
if k > maxL :
return ""
temp = []
a = 'a'
b = 'b'
c = 'c'
maxL //= 3
if k <= maxL:
temp.append(a)
elif k <= maxL*2:
temp.append(b)
k -= maxL
else:
temp.append(c)
k -= maxL*2
for i in range(1,n):
if n-i < 62:
maxL //=2
if k < maxL:
temp.append(b if temp[i-1] == a else a)
elif k > maxL:
temp.append(b if temp[i-1] == c else c)
k -= maxL
else:
temp.append(b if temp[i-1] == a else a)
if k != maxL:
k -= maxL
return ''.join(temp)
java实现
public class Solution {
/**
* @param n: the length of the string.
* @param k: the kth Lexicographically smallest that result should be.
* @return: return the kth Lexicographically smallest string.
*/
public String kthString(int n, long k) {
// write your code here.
long maxL =(n>62)? (long)(3*Math.pow(2, 62)):(long)(3*Math.pow(2, n-1));
if (k > maxL){
return "";
}
char[] temp = new char[n];
char a = 'a',b = 'b',c = 'c';
maxL /=3;
if (k <= maxL){
temp[0] = a;
}else if (k <= maxL*2){
temp[0] =b;
k -= maxL;
}else{
temp[0] =c;
k -=maxL*2;
}
for (int i =1;i<n ;i++ ){
if(n-i <62)
maxL /=2;
if(k < maxL){
temp[i] = (temp[i-1] == a)? b:a;
}else if(k>maxL){
temp[i] = (temp[i-1] == c)? b:c;
k -= maxL;
}else{
temp[i] = (temp[i-1] == a)? b:a;
if (k != maxL) k -= maxL;
}
}
return String.valueOf(temp);
}
}
Tips:
- 本地测试完全通过,但lintCode上传后验证未能通过,原因未知,非超时问题。
2021.01.26更新!
- 由于对这个题念念不忘,想到解决办法后终于解决问题了
- 之前过不了大概率是因为每次需要做除法计算重复值耗时略多,而且有些冗余部分存在。
- 使用一个数组存放索引值,每次无需再做除法。
- 具体代码如下:该算法的时间复杂度 O(n) 空间复杂度为O(n).
java实现
public class Solution {
/**
* @param n: the length of the string.
* @param k: the kth Lexicographically smallest that result should be.
* @return: return the kth Lexicographically smallest string.
*/
public String kthString(int n, long k) {
// write your code here.
long[] maxTemp = new long[63];
maxTemp[0] = 1;
int pos =0;
for(int i = 1; i < 63; i++){
maxTemp[i] = maxTemp[i-1]*2;
if (n >= i){
pos =i;
}else{
break;
}
}
pos -=1;
if (k > maxTemp[pos]*3){
return "";
}
char[] temp = new char[n];
if (k <= maxTemp[pos]){
temp[0] = 'a';
}else if (k <= maxTemp[pos]*2){
temp[0] ='b';
k -= maxTemp[pos];
}else{
temp[0] ='c';
k -=maxTemp[pos]*2;
}
for (int i =1;i<n ;i++ ){
if(n-i <=pos) pos -=1;
if(k <= maxTemp[pos]){
temp[i] = (temp[i-1] == 'a')? 'b':'a';
}else{
temp[i] = (temp[i-1] == 'c')? 'b':'c';
k -= maxTemp[pos];
}
}
return String.valueOf(temp);
}
}
python实现
class Solution:
"""
@param n: the length of the string.
@param k: the kth Lexicographically smallest that result should be.
@return: return the kth Lexicographically smallest string.
"""
def kthString(self, n, k):
# write your code here.
maxTemp = [1]
pos = 0
for i in range(1,63):
maxTemp.append(maxTemp[i-1]*2)
if n >=i :
pos = i
else :
break
pos -=1
if k > maxTemp[pos]*3 :
return ""
temp = []
if k <= maxTemp[pos] :
temp.append('a')
elif k <= maxTemp[pos] * 2:
temp.append('b')
k -= maxTemp[pos]
else:
temp.append('c')
k -= maxTemp[pos]*2
for i in range(1,n):
if n-i <= pos:
pos -=1
if k <= maxTemp[pos]:
temp.append('b' if temp[i-1] == 'a' else 'a')
else:
temp.append('b' if temp[i-1] == 'c' else 'c')
k -= maxTemp[pos]
return ''.join(temp)