1633 - Smallest String With A Given Numeric Value (Medium)
Problem Link
https://leetcode.com/problems/smallest-string-with-a-given-numeric-value/
Problem Statement
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
Approach 1: Build from the right
To obtain lexicographically smallest string, we should put from the left and from the right if possible and put what's left in the middle. Therefore, we initialise the answer with all s. Starting from the right, the best case is to make it to (i.e. ). If we cannot do it, then we can only make it to the max one (i.e. ).
class Solution {
public:
string getSmallestString(int n, int k) {
// init s with all 'a's
string s(n, 'a');
// since we put n times, update k
k -= n;
// 0-index
n -= 1;
// fill character until k <= 0
while (k > 0) {
// we either put a + 25 (z) or a + k
s[n] += min(k, 25);
// update k
k -= 25;
// shift the pointer to the left
n -= 1;
}
return answer
return s;
}
};
Approach 2: Three segments
The answer can be potentially constructed by three segments. The first segment contains only . The last segment contains only . The middle segment contains a character. This approach is to calculate each character in each segment given and .
First we calculate the number of characters that are not , i.e. the total number of characters in the second and the third segment. Let's call it . Then we know that there would be a in the first segment and z in the third segment (minus one because we need one for the second segment). So how to get ? We can use above condition to find out . That is which gives .
For the middle segment, how many left we can use? We've used for the first segment and for the last segment. The index of the character in the middle segment would be .
class Solution {
public:
string getSmallestString(int n, int k) {
// total number of characters in 2nd & 3rd segment
int nonA = ((k - n) + 25 - 1) / 25;
// 1st segment: there is (n - nonA) 'a's
// 2nd segment: one character with index k - (n - nonA) - (nonA - 1) * 26
// 3rd segemnt: there is (nonA - 1) 'z's
return string(n - nonA, 'a') +
char(k - (n - nonA) - (nonA - 1) * 26 + 'a' - 1) +
string(nonA - 1, 'z');
}
};