题目:
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.
Example 1:
Input: n = 3, k = 27 Output: "aay" Explanation: The numeric value of the string is 1 + 1 + 25 = 27, and it is the smallest string with such a value and length equal to 3.
Example 2:
Input: n = 5, k = 73 Output: "aaszz"
Constraints:
1 <= n <= 10^5
n <= k <= 26 * n
思路1:
题意大概是给出n和k两个整数,n表示字符串长度,k表示字母总和,返回字典序列最小的符合n和k的字符串。k的总和是通过字符串中的字符计算的,'a'=1,'b'=2,依此类推'z'=26。很明显字典序列最小那开头肯定尽量是字母’a‘了,所以我们应该从最后一位开始考虑。我的方法是从26,即'z'开始,如果分出i个z,剩下的全是a,这种情况的总和等于k,则我们找到了解;如果大于k,说明位数n给的太小,字母‘z’太大了,但是n是定值,只能'z'退一位变成'y',然后再重新计算,这里每次更换字符,i的大小要变成原本给定的n,并且要从大到小递减,否则可能会超时;如果小于k,说明当前的方案是可以的,但是剩下的位数不能全是'a',比如k=30和n=3,减了个26还剩4,但是不可以剩下2位都是‘a',这样的话k就是26+1+1=28不符合30了,这种情况下我们把能分配的'z'先分配了,分配出去i个,然后'z'退格,然后更新i的大小,以及n和k,更新i的大小和上面一种情况一样。这种方法比较繁琐,但是能够通过,大概是80ms。
代码1:
class Solution {
public:
string getSmallestString(int n, int k) {
string ans = "";
int c = 26;
int num = n;
for (int i = n; i >=1; i--)
{
if (c * i + n - i > k)
{
if (i == 1)
{
c--;
i = num;
}
}
else if (c * i + n - i < k)
{
k -= i*c;
n-=i;
char temp = c + 'a'-1;
string s(i, temp);
ans = s + ans;
i = num;
c--;
}
else
{
n-=i;
char temp = c + 'a' - 1;
string s(i, temp);
ans = s + ans;
break;
}
}
string add(n, 'a');
ans = add + ans;
return ans;
}
};
思路2:
看了大神的做法,大概是60ms即可通过。首先是分配一个长为n,每一位都是'a’的string,然后从最后一位,假设为i,开始更新,只要k大于0,那么这一轮在i位要加上的就是
,这里25是因为本来就是'a',只要加25即可变成’z‘。这样无论是不是剩下的k是不是超出了26,只要一轮一轮比较,都可以按照比较得到的值去分配,不用像思路1中考虑三种情况了。
代码2:
class Solution {
public:
string getSmallestString(int n, int k) {
string ans(n,'a');
k-=n;
int i=n-1;
while(k>0)
{
int add = min(k, 25);
ans[i]+=add;
k-=add;
i--;
}
return ans;
}
};