2081. Sum of k-Mirror Numbers
Problem Description
A k-mirror number is a positive integer with no leading zeros that is symmetrical; it reads the same forward and backward. This symmetry must hold true when the number is expressed in both base-10 (our standard numeral system) and base-k (a numeral system with base k). For example, the number 9 is the same whether read forwards or backwards in base-10, and when converted to base-2, it becomes '1001', which is also symmetrical.
However, not every number is k-mirror. For instance, the number 4 in base-10 becomes '100' in base-2. Since '100' isn't symmetrical, 4 is not a 2-mirror number.
The problem asks us to calculate the sum of the n smallest k-mirror numbers. In other words, we must find the first n numbers that are k-mirror numbers and add them together.
Intuition
The solution approach for finding k-mirror numbers involves generating potential mirror numbers in base-10 and then checking if they are also symmetrical in base-k. Instead of generating all numbers and checking each one, a more efficient approach is to generate numbers that are already palindromic in base-10. If a number is a palindrome in base-10, there's no need to check it for symmetry in this base.
To generate palindromes in base-10, we start by considering numbers of increasing lengths. For each length, we form the first half of a potential palindrome and then mirror it to create the second half, ensuring the entire number is symmetrical in base-10.
For example, if our first half is '123', the whole palindrome can be '12321' for odd lengths, and '123321' for even lengths. Note that we have to generate both even and odd length palindromes because they may both yield valid k-mirror numbers.
Once we create a base-10 palindrome, we convert it to base-k and then check if the base-k representation is also a palindrome. The check is straightforward: compare the first half of the array of characters to the second half and confirm they are identical.
The provided Java function kMirror(int k, int n)
initializes the answer to 0. It then enters a loop that continues until we find n k-mirror numbers. Inside the loop, we generate base-10 palindromes of increasing length using the loop variable l
. We use the just-generated palindrome as a long integer v
, convert v
to a string in base-k, and then use the check
helper method to determine if it is also a palindrome in base-k.
Each time we find a k-mirror number, we add it to the ans
variable and decrement n
. Once we've found n k-mirror numbers, we return the total sum ans
.
This approach is efficient because it sidesteps the need to check each base-10 number for palindromic properties—we create only numbers that are already palindromes in base-10. Then we only need to check for palindromic structure in base-k, significantly reducing the number of checks needed.
Learn more about Math patterns.
Solution Approach
The solution uses a mathematical approach to generate palindromes and a brute-force check to determine if those palindromes are k-mirror numbers. Let's break down the implementation into its main components:
-
Palindrome Generation: The outer loop, indicated by
for (int l = 1;; ++l)
, controls the lengthl
of the palindromes being generated. Thel
increases after each full iteration, allowing us to create larger palindromes. For half the length (rounded down), we useint x = (int) [Math](/problems/math-basics).pow(10, (l - 1) / 2)
, and for half the length (rounded up), we useint y = (int) Math.pow(10, (l + 1) / 2)
. -
Base-10 Palindrome Construction: Inside the loop,
for (int i = x; i < y; i++)
iterates through potential first halves of the palindromic numbers. The variablev
is then used to construct the full palindrome by appending the reverse ofi
, either including the last digit(l % 2 == 0 ? i : i / 10)
for even lengths or excluding it for odd lengths. -
Base-k Conversion: After creating a base-10 palindrome (
v
), we convert it to a string in the base-k numeral system withString ss = Long.toString(v, k)
. -
Palindrome Check in Base-k: The private helper function
check(char[] c)
takes in the char array of the base-k representation and uses two pointers (i
andj
) to check from both ends towards the center, ensuring that the string is the same forwards and backwards. -
Summation and Counting: When a k-mirror number is found (i.e., it passes the palindrome check in base-k), it is added to the running total
ans
, andn
is decremented. We continue generating palindromes and checking for k-mirror symmetry untiln
reaches zero—at which point we return the sumans
.
The algorithm demonstrates efficient use of mathematical properties to limit the search space only to valid palindromes, rather than iterating through all integers. By constructing palindromes of increasing length, we also ensure we are considering the smallest k-mirror numbers in ascending order, which fits the requirement of the problem. The combination of mathematical pattern recognition and brute-force checking results in a direct and effective solution to the problem.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's use k = 2
and n = 3
to illustrate the solution approach to finding the sum of the n
smallest k
-mirror numbers. We are looking for the sum of the first 3 numbers that are both palindromes in base-10 and base-2.
-
Palindrome Generation in Base-10: Our outer loop constructs base-10 palindromes of increasing length. We begin with the length
l = 1
. This means for half the length (rounded down)x=1
and half the length (rounded up)y=10
. -
Base-10 Palindrome Construction: Inside the loop, we iterate from
x
(in this case, 1) toy
(less than 10) to create the first half of the palindrome. Fori = 1
, we getv = 1
, because this is a length one (odd-length) palindromei
itself. For an even-length palindrome whenl = 2
, which is not applicable yet, we would mirror the whole digit(s). -
Base-k Conversion: Now, we convert
v
to base-k (base-2). The number1
in base-2 is '1', which is still a palindrome. -
Palindrome Check in Base-k: For our number
1
in base-2, it's clearly symmetrical, so no need to check further. -
Summation and Counting: Since
1
is a k-mirror number, we add it to the running totalans = 1
and decrementn
to 2. We now need to find two more k-mirror numbers.
Next, for i = 2
, repeating the steps above, we:
- Create the base-10 palindrome, which is still
2
since it's a single digit. - Convert
2
into base-2, which is '10', and this is not a palindrome. Hence, we skip it.
For i = 3
, we:
- Have
v = 3
, already a palindrome in base-10. - Convert
3
into base-2, which gives us '11'. It is a palindrome in base-2. - Since '11' passes the symmetry check, we add 3 to
ans
, resulting inans = 4
, and decrementn
to 1.
For l
greater than 1, let's say l = 2
, our process works as follows:
- Generate potential base-10 palindromes by considering
i
from 1 to 9 (the upper limity
here would be 10). - For
i = 1
, our even base-10 palindrome construction would yield11
. - Convert
11
into base-2, which gives us '1011', and this is not symmetrical. - Thus,
11
in base-10 is not added toans
and won't decrementn
.
This process repeats, increasing l
as needed, until we find 3 k-mirror numbers in base-10 and base-2. Once we find the required amount, we return the total sum ans
, which would be the sum of the first three smallest 2-mirror numbers.
The efficiency of this algorithm comes from the fact that rather than brute-forcing through consecutive integers, it constructs potential palindromes and then checks if those palindromes are symmetrical in another base, significantly narrowing the search space.
Solution Implementation
1class Solution:
2
3 def k_mirror(self, base: int, count: int) -> int:
4 sum_of_k_mirrors = 0 # Initialize sum of k-mirror numbers.
5
6 # Loops indefinitely until 'count' k-mirror numbers are found.
7 length = 1
8 while True:
9 # Determine the start and end range for constructing palindrome halves based on the length.
10 start = 10 ** ((length - 1) // 2)
11 end = 10 ** ((length + 1) // 2)
12
13 # Generate all possible palindrome numbers with current length.
14 for i in range(start, end):
15 # Construct the first half of the palindrome number.
16 palindrome = i
17
18 # Generate the second half of the palindrome number.
19 # If the length is even, include the middle digit; if it's odd, exclude it.
20 j = i if length % 2 == 0 else i // 10
21 while j > 0:
22 palindrome = palindrome * 10 + j % 10 # Append digits in reverse order.
23 j //= 10
24
25 # Convert the palindrome to its representation in the given base.
26 base_representation = self.to_base(palindrome, base)
27
28 # Check if the base representation is a palindrome.
29 if self.is_palindrome(base_representation):
30 sum_of_k_mirrors += palindrome # Add the k-mirror number to the sum.
31 count -= 1 # Decrement the count of k-mirrors we still need to find.
32 if count == 0: # Check if we've found the required number of k-mirror numbers.
33 return sum_of_k_mirrors # Return the sum if we have.
34
35 length += 1 # Increment length for the next iteration to generate larger palindromes.
36
37 def to_base(self, num: int, base: int) -> str:
38 # Convert an integer 'num' into a string representation of 'base'.
39 chars = []
40 while num > 0:
41 chars.append(str(num % base))
42 num //= base
43 # Since we build the base representation in reverse, we need to reverse it at the end.
44 return ''.join(reversed(chars))
45
46 def is_palindrome(self, s: str) -> bool:
47 # Check if a string 's' is a palindrome.
48 return s == s[::-1] # This uses Python's string slicing to reverse the string.
49
1class Solution {
2
3 // This method returns the sum of the first n k-mirror numbers.
4 public long kMirror(int base, int count) {
5 long sum = 0; // Initialize sum of k-mirror numbers
6
7 // Loops indefinitely until 'count' number of k-mirror numbers are found
8 for (int length = 1; ; ++length) {
9 // Find the start and end range based on the half-length to construct palindrome prefixes
10 int start = (int) Math.pow(10, (length - 1) / 2);
11 int end = (int) Math.pow(10, (length + 1) / 2);
12
13 // Loop to generate all palindrome numbers of the current length
14 for (int i = start; i < end; i++) {
15 long palindrome = i;
16
17 // Construct the second half of the palindrome number based on the length's parity
18 for (int j = length % 2 == 0 ? i : i / 10; j > 0; j /= 10) {
19 palindrome = palindrome * 10 + j % 10; // Append digits in reverse order to form the palindrome
20 }
21
22 // Convert palindrome to its representation in the given base
23 String baseRepresentation = Long.toString(palindrome, base);
24
25 // Check if the base representation is a palindrome
26 if (isPalindrome(baseRepresentation.toCharArray())) {
27 sum += palindrome; // Add current palindrome to sum
28 if (--count == 0) { // Decrement count and check if 'n' k-mirror numbers are found
29 return sum; // Return the sum if 'n' k-mirror numbers are found
30 }
31 }
32 }
33 }
34 }
35
36 // This method checks if the character array forms a palindrome
37 private boolean isPalindrome(char[] charArray) {
38 // Compare characters from opposite ends moving towards the center
39 for (int i = 0, j = charArray.length - 1; i < j; i++, j--) {
40 if (charArray[i] != charArray[j]) {
41 return false; // Return false if mismatch is found
42 }
43 }
44 return true; // Return true if the entire array is a palindrome
45 }
46}
47
1#include <cmath>
2#include <string>
3#include <vector>
4
5class Solution {
6public:
7 // This method returns the sum of the first 'count' k-mirror numbers in the given 'base'.
8 long long kMirror(int base, int count) {
9 long long sum = 0; // Initialize sum of k-mirror numbers
10
11 // Loops indefinitely until 'count' k-mirror numbers are found
12 for (int length = 1; count > 0; ++length) {
13 // Find the start and end range based on the half-length to construct palindrome prefixes
14 int start = static_cast<int>(std::pow(10, (length - 1) / 2));
15 int end = static_cast<int>(std::pow(10, (length + 1) / 2));
16
17 // Loop to generate all palindrome numbers of the current length
18 for (int i = start; i < end; i++) {
19 long long palindrome = i;
20
21 // Construct the second half of the palindrome number based on the length's parity
22 for (int j = (length % 2 == 0) ? i : i / 10; j > 0; j /= 10) {
23 palindrome = palindrome * 10 + j % 10; // Append digits in reverse order to form the palindrome
24 }
25
26 // Convert palindrome to its representation in the given base
27 std::string baseRepresentation = toBase(palindrome, base);
28
29 // Check if the base representation is a palindrome
30 if (isPalindrome(baseRepresentation)) {
31 sum += palindrome; // Add current palindrome to sum
32 --count; // Decrement count as one k-mirror number was found
33 if (count == 0) { // If 'count' k-mirror numbers have been found
34 return sum; // Return the sum of all k-mirror numbers found
35 }
36 }
37 }
38 }
39 }
40
41private:
42 // This method converts a 'number' into a string representing its value in 'base'.
43 std::string toBase(long long number, int base) {
44 std::string representation;
45 while (number > 0) {
46 int digit = number % base;
47 representation = static_cast<char>(digit < 10 ? '0' + digit : 'A' + (digit - 10)) + representation;
48 number /= base;
49 }
50 return representation.empty() ? "0" : representation;
51 }
52
53 // This method checks if the string 's' forms a palindrome.
54 bool isPalindrome(const std::string& s) {
55 // Compare characters from opposite ends moving towards the center
56 int i = 0, j = s.size() - 1;
57 while (i < j) {
58 if (s[i++] != s[j--]) {
59 return false; // Return false if mismatch is found
60 }
61 }
62 return true; // Return true if the entire string is a palindrome
63 }
64};
65
1// Initialize sum of k-mirror numbers
2let sum: number = 0;
3
4// This function returns the sum of the first 'count' k-mirror numbers in the given 'base'.
5function kMirror(base: number, count: number): number {
6 // Loops indefinitely until 'count' number of k-mirror numbers are found
7 for (let length = 1; ; ++length) {
8 // Find the start and end range based on the half-length to construct palindrome prefixes
9 const start: number = Math.pow(10, Math.floor((length - 1) / 2));
10 const end: number = Math.pow(10, Math.floor((length + 1) / 2));
11
12 // Loop to generate all palindrome numbers of the current length
13 for (let i = start; i < end; i++) {
14 let palindrome: number = i;
15
16 // Construct the second half of the palindrome number based on the length's parity
17 for (let j = length % 2 === 0 ? i : Math.floor(i / 10); j > 0; j = Math.floor(j / 10)) {
18 palindrome = palindrome * 10 + j % 10; // Append digits in reverse order to form the palindrome
19 }
20
21 // Convert palindrome to its representation in the given base
22 const baseRepresentation: string = palindrome.toString(base);
23
24 // Check if the base representation is a palindrome
25 if (isPalindrome(baseRepresentation)) {
26 sum += palindrome; // Add current palindrome to sum
27 if (--count === 0) { // Decrement count and check if 'count' k-mirror numbers are found
28 return sum; // Return the sum if 'count' k-mirror numbers are found
29 }
30 }
31 }
32 }
33}
34
35// This function checks if the given string is a palindrome
36function isPalindrome(str: string): boolean {
37 // Compare characters from opposite ends moving towards the center
38 for (let i = 0, j = str.length - 1; i < j; i++, j--) {
39 if (str[i] !== str[j]) {
40 return false; // Return false if mismatch is found
41 }
42 }
43 return true; // Return true if the entire string is a palindrome
44}
45
Time and Space Complexity
Time Complexity
The time complexity of the given code can be broken down as follows:
-
The outermost loop runs indefinitely (
for (int l = 1;; ++l)
), incrementingl
untiln
palindromes are found. The valuel
determines the length of the palindrome to be constructed. -
Inside the outermost
for
loop, calculations to set the boundsx
andy
are done usingMath.pow(10, (l - 1) / 2)
andMath.pow(10, (l + 1) / 2)
, which has a constant time complexity ofO(1)
as it is executed once per loop iteration. -
The next
for
loop (for (int i = x; i < y; i++)
) iterates fromx
toy
. The number of iterations depends onl
and is approximatelyO(10^(l/2))
. -
Inside this loop, the palindrome is constructed by appending the reverse of the number to itself or its prefix depending on whether
l
is even or odd. This operation has a time complexity ofO(l)
per iteration since reversing a number's digits is linear with the number of digits. -
The palindrome is then converted to its base-
k
representation (Long.toString(v, k)
). The conversion's time complexity isO((log(v)/log(k)) * log(v))
, where(log(v)/log(k))
is the length of the string in base-k
. -
The
check
function, which ensures the base-k
string is a palindrome, has a time complexity ofO(log(v)/log(k))
.
Considering that v
grows exponentially with l
, the dominant factor here is the construction and checking of base-k
palindromes which happen (10^{l/2}) times for each length l
. Thus, the total time complexity approximately can be expressed as:
O(n * l * (log(v)/log(k)) * log(v))
, as this represents the work done to find each of the n
palindromes.
Given that n
is the number of palindromes required and l
increases incrementally, this expression accounts for the increasing cost of producing and checking each palindrome as their lengths increase.
Space Complexity
The space complexity of the code can be analyzed as follows:
-
The variable
v
and the stringss
carry the largest values in this code. Since these are reused for each palindrome, they do not increase in space usage proportional to the input size. -
The
check
function uses a few variables for iteration, which does not significantly contribute to the space complexity. -
No additional arrays or data structures are used that grow with input size.
Thus, the space complexity is primarily driven by the call stack for each recursive call used in number conversion and checking, which yields:
O(l)
for the recursion in creating the palindrome.O(log(v))
for space required for base-k
conversion.
Since l
is linearly related to log(v)
(as the palindrome v
will have a length corresponding to l
), the space complexity is approximately O(log(v))
. However, because log(v)
is a constant relative to v
itself and does not grow with the input size n
, the overall space complexity of the code is O(1)
, i.e., constant space complexity assuming that k
is also constant.
Learn more about how to find time and space complexity quickly using problem constraints.
What does the following code do?
1def f(arr1, arr2):
2 i, j = 0, 0
3 new_arr = []
4 while i < len(arr1) and j < len(arr2):
5 if arr1[i] < arr2[j]:
6 new_arr.append(arr1[i])
7 i += 1
8 else:
9 new_arr.append(arr2[j])
10 j += 1
11 new_arr.extend(arr1[i:])
12 new_arr.extend(arr2[j:])
13 return new_arr
14
1public static List<Integer> f(int[] arr1, int[] arr2) {
2 int i = 0, j = 0;
3 List<Integer> newArr = new ArrayList<>();
4
5 while (i < arr1.length && j < arr2.length) {
6 if (arr1[i] < arr2[j]) {
7 newArr.add(arr1[i]);
8 i++;
9 } else {
10 newArr.add(arr2[j]);
11 j++;
12 }
13 }
14
15 while (i < arr1.length) {
16 newArr.add(arr1[i]);
17 i++;
18 }
19
20 while (j < arr2.length) {
21 newArr.add(arr2[j]);
22 j++;
23 }
24
25 return newArr;
26}
27
1function f(arr1, arr2) {
2 let i = 0, j = 0;
3 let newArr = [];
4
5 while (i < arr1.length && j < arr2.length) {
6 if (arr1[i] < arr2[j]) {
7 newArr.push(arr1[i]);
8 i++;
9 } else {
10 newArr.push(arr2[j]);
11 j++;
12 }
13 }
14
15 while (i < arr1.length) {
16 newArr.push(arr1[i]);
17 i++;
18 }
19
20 while (j < arr2.length) {
21 newArr.push(arr2[j]);
22 j++;
23 }
24
25 return newArr;
26}
27
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Don’t Miss This!