LintCode算法挑战——abc串

问题描述

  • 有一个字符串集合,所有字符串的长为 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)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值