【每日一题Day99】LC1663具有给定数值的最小字符串 | 贪心

简介: 如果k−(n−i)∗26<=1,那么表示尾部全部插入z,没有分数剩余甚至还有同于,那么第i个字符可以插入的最小字符'a',贡献的分数为1

具有给定数值的最小字符串【LC1663】


The numeric value of a lowercase character is defined as its position (1-indexed) in the alphabet, so the numeric value of a is 1, the numeric value of b is 2, the numeric value of c is 3, and so on.


The numeric value of a string consisting of lowercase characters is defined as the sum of its characters’ numeric values. For example, the numeric value of the string "abe" is equal to 1 + 2 + 5 = 8.


You are given two integers n and k. Return the lexicographically smallest string with length equal to n and numeric value equal to k.


Note that a string x is lexicographically smaller than string y if x comes before y in dictionary order, that is, either x is a prefix of y, or if i is the first position such that x[i] != y[i], then x[i] comes before y[i] in alphabetic order.


  • 思路:贪心


局部最优:在保证字符串长度一定,优先在字符串尾部插入数值最大的字符,即使首部字符串尽可能为a、尾部字符串尽可能为z


全局最优:字符串的字典顺序最小


  • 实现【总体超时】


从尾部开始插入字符,当n和k一定时,前n−1个字符需要的分数最少为n−1,那么可供第n个字符使用的分数为k−(n−1),因此第n个字符一定


。如果k−(n−1)>=26,那么尾部可以插入的最小字符为z='a'+25,贡献的分数为26

。如果k−(n−1)<26,那么尾部可以插入的最小字符为'a' + k-n,贡献的分数为k−n+1


class Solution {
    public String getSmallestString(int n, int k) {
        StringBuilder sb = new StringBuilder();      
        while (n > 0){
            if (k - n + 1 >= 26){
                sb.insert(0, (char)('a' + 25));
                k -= 26;
            }else{
                sb.insert(0, (char)('a' + k - n));
                k -= k - n + 1;
            }
            n--;
        }
        return sb.toString();
    }
}


。复杂度


  • 时间复杂度:O ( n 2 ) ,每构造一位字符需要将字符串后移一位,需要的时间复杂度为O(n),因此总时间复杂度为O ( n 2 )


  • 空间复杂度:O ( 1 )


  • 实现


从头部开始插入字符,当n 和k一定时,使前面的字符尽可能为a,后面的字符尽可能为z。当构造第i个字符时,后n−i个字符全为z需要的分数为(n−i)∗26,那么第i个字符需要贡献的分数为max(1,k−(n−i)∗26)


。如果k−(n−i)∗26>1,那么表示尾部全部插入z,仍有分数剩余,那么第i个字符应插入'a'+k-(n-i)*26-1,贡献的分数为k−(n−i)∗26


。如果k−(n−i)∗26<=1,那么表示尾部全部插入z,没有分数剩余甚至还有同于,那么第i个字符可以插入的最小字符'a',贡献的分数为1


class Solution {
    public String getSmallestString(int n, int k) {
        StringBuilder sb = new StringBuilder();      
        while (n > 0){
            int lower = Math.max(1, k - (n - 1) * 26);
            sb.append((char)('a'+ lower - 1));
            k -= lower;
            n--;
        }
        return sb.toString();
    }
}


。复杂度


  • 时间复杂度:O ( n )
  • 空间复杂度:O ( 1 )
目录
相关文章
|
5月前
【每日一题Day342】LC2578最小和分割 | 贪心
【每日一题Day342】LC2578最小和分割 | 贪心
43 0
|
5月前
【每日一题Day289】LC1749任意子数组和的绝对值的最大值 | dp
【每日一题Day289】LC1749任意子数组和的绝对值的最大值 | dp
42 0
|
5月前
【每日一题Day159】LC1638统计只差一个字符的子串数目 | 枚举
【每日一题Day159】LC1638统计只差一个字符的子串数目 | 枚举
36 0
|
5月前
【每日一题Day161】LC1641统计字典序元音字符串的数目 | 数位dp
【每日一题Day161】LC1641统计字典序元音字符串的数目 | 数位dp
46 0
|
5月前
【每日一题Day225】LC2559统计范围内的元音字符串数 | 前缀和 二分查找
【每日一题Day225】LC2559统计范围内的元音字符串数 | 前缀和 二分查找
48 0
|
5月前
|
索引
【每日一题Day131】LC1144递减元素使数组呈锯齿状 | 贪心+枚举
【每日一题Day131】LC1144递减元素使数组呈锯齿状 | 贪心+枚举
44 0
|
11月前
|
算法
【代码随想录】LC 209. 长度最小的子数组
利用两层循环,第一层循环枚举子数组的起点位置,第二层循环枚举子数组的终点位置,第二层循环中可以同时来统计当前子数组的和,如果符合题目条件则更新length,否则继续循环,直至两层循环结束,返回题目要求的值,算法结束。
51 0
|
5月前
【每日一题Day204】LC1330翻转子数组得到最大的数组值 | 数学
【每日一题Day204】LC1330翻转子数组得到最大的数组值 | 数学
41 1
|
5月前
|
机器学习/深度学习 存储 算法
数据结构与算法面试题:给定非负整数 m 和 n,计算不大于 m 的数字中,素数的个数。(提示:算法原理为埃氏筛、线性筛)
数据结构与算法面试题:给定非负整数 m 和 n,计算不大于 m 的数字中,素数的个数。(提示:算法原理为埃氏筛、线性筛)
81 0
|
5月前
【每日一题Day358】LC2698求一个整数的惩罚数 | 递归
【每日一题Day358】LC2698求一个整数的惩罚数 | 递归
50 0