Skip to main content

1633 - Smallest String With A Given Numeric Value (Medium)

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 aa from the left and zz from the right if possible and put what's left in the middle. Therefore, we initialise the answer with all aas. Starting from the right, the best case is to make it to zz (i.e. s[i]+25s[i] + 25). If we cannot do it, then we can only make it to the max one (i.e. s[i]+ks[i] + k).

Written by @wingkwong
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 aa. The last segment contains only zz. The middle segment contains a character. This approach is to calculate each character in each segment given nn and kk.

First we calculate the number of characters that are not aa, i.e. the total number of characters in the second and the third segment. Let's call it nonAnonA. Then we know that there would be nnonAn - nonA a in the first segment and nonA1nonA - 1 z in the third segment (minus one because we need one for the second segment). So how to get nonAnonA? We can use above condition to find out nonAnonA. That is (nnonA)1+nonA26>=k(n - nonA) * 1 + nonA * 26 >= k which gives nonA>=(kn)/25nonA >= (k - n) / 25.

For the middle segment, how many kk left we can use? We've used (nnonA)1(n - nonA) * 1 for the first segment and (nonA1)26(nonA-1)* 26 for the last segment. The index of the character in the middle segment would be k(nnonA)(nonA1)26k - (n - nonA) - (nonA - 1) * 26.

Written by @wingkwong
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');
}
};