I'm trying to print the numbers from 1 to N in lexicographic order, but I get a failed output. for the following input 100, I get the 100, but its shifted and it doesn't match with the expected output, there is a bug in my code but I can not retrace it.
class Solution {
public:
vector<int> lexicalOrder(int n) {
vector<int> result;
for(int i = 1; i <= 9; i ++){
int j = 1;
while( j <= n){
for(int m = 0; m < j ; ++ m){
if(m + j * i <= n){
result.push_back(m+j*i);
}
}
j *= 10;
}
}
return result;
}
};
Input:
100
Output:
[1,10,11,12,13,14,15,16,17,18,19,100,2,20,21,22,23,24,25,26,27,28,29,3,30,31,32,33,34,35,36,37,38,39,4,40,41,42,43,44,45,46,47,48,49,5,50,51,52,53,54,55,56,57,58,59,6,60,61,62,63,64,65,66,67,68,69,7,70,71,72,73,74,75,76,77,78,79,8,80,81,82,83,84,85,86,87,88,89,9,90,91,92,93,94,95,96,97,98,99]
Expected:
[1,10,100,11,12,13,14,15,16,17,18,19,2,20,21,22,23,24,25,26,27,28,29,3,30,31,32,33,34,35,36,37,38,39,4,40,41,42,43,44,45,46,47
When applied to numbers, lexicographic order is increasing numerical order, i.e. increasing numerical order (numbers read left to right). For example, the permutations of {1,2,3} in lexicographic order are 123, 132, 213, 231, 312, and 321. When applied to subsets, two subsets are ordered by their smallest elements.
Approach: Find a string which is lexicographically greater than string S and check if it is smaller than string T, if yes print the string next else print “-1”. To find string, iterate the string S in the reverse order, if the last letter is not 'z', increase the letter by one (to move to next letter).
Lexicographical order is nothing but the dictionary order or preferably the order in which words appear in the dictonary. For example, let's take three strings, "short", "shorthand" and "small". In the dictionary, "short" comes before "shorthand" and "shorthand" comes before "small". This is lexicographical order.
Lexicographical order In Python is achieved by using sort() and sorted() function. sort() function sorts data elements in lexicographical order by performing operations on the input list. sorted() function sorts data elements in lexicographical order by replicating the input list and keeping the input list as it is.
Think about when i=1
,j=10
what will happen in
for(int m = 0; m < j ; ++ m){
if(m + j * i <= n){
result.push_back(m+j*i);
}
}
Yes,result
will push_back 10(0+10*1),11(1+10*1),12(2+10*1)..
Here is a solution:
#include <iostream>
#include <vector>
#include <string>
std::vector<int> fun(int n)
{
std::vector<std::string> result;
for (int i = 1; i <= n; ++i) {
result.push_back(std::to_string(i));
}
std::sort(result.begin(),result.end());
std::vector<int> ret;
for (auto i : result) {
ret.push_back(std::stoi(i));
}
return ret;
}
int main(int argc, char *argv[])
{
std::vector<int> result = fun(100);
for (auto i : result) {
std::cout << i << ",";
}
std::cout << std::endl;
return 0;
}
You are looping through all 2 digit numbers starting with 1 before outputting the first 3 digit number, so your approach won't work.
One way to do this is to output the digits in base 11, padded out with leading spaces to the maximum number of digits, in this case 3. Output 0 as a space, 1 as 0, 2 as 1 etc. Reject any numbers that have any non-trailing spaces in this representation, or are greater than n when interpreted as a base 10 number. It should be possible to jump past multiple rejects at once, but that's an unnecessary optimization. Keep a count of the numbers you have output and stop when it reaches n. This will give you a lexicographical ordering in base 10.
Example implementation that uses O(1) space, where you don't have to generate and sort all the numbers up front before you can output the first one:
void oneToNLexicographical(int n)
{
if(n < 1) return;
// count max digits
int digits = 1, m = n, max_digit11 = 1, max_digit10 = 1;
while(m >= 10)
{
m /= 10; digits++; max_digit11 *= 11; max_digit10 *= 10;
}
int count = 0;
bool found_n = false;
// count up starting from max_digit * 2 (first valid value with no leading spaces)
for(int i = max_digit11 * 2; ; i++)
{
int val = 0, trailing_spaces = 0;
int place_val11 = max_digit11, place_val10 = max_digit10;
// bool valid_spaces = true;
for(int d = 0; d < digits; d++)
{
int base11digit = (i / place_val11) % 11;
if(base11digit == 0)
{
trailing_spaces++;
val /= 10;
}
else
{
// if we got a non-space after a space, it's invalid
// if(trailing_spaces > 0)
// {
// valid_spaces = false;
// break; // trailing spaces only
// }
val += (base11digit - 1) * place_val10;
}
place_val11 /= 11;
place_val10 /= 10;
}
// if(valid_spaces && (val <= n))
{
cout << val << ", ";
count++;
}
if(val == n)
{
found_n = true;
i += 10 - (i % 11); // skip to next number with one trailing space
}
// skip past invalid numbers:
// if there are multiple trailing spaces then the next run of numbers will have spaces in the middle - invalid
if(trailing_spaces > 1)
i += (int)pow(11, trailing_spaces - 1) - 1;
// if we have already output the max number, then all remaining numbers
// with the max number of digits will be greater than n
else if(found_n && (trailing_spaces == 1))
i += 10;
if(count == n)
break;
}
}
This skips past all invalid numbers, so it's not necessary to test valid_spaces
before outputting each.
The inner loop can be removed by doing the base11 -> base 10 conversion using differences, making the algorithm O(N) - the inner while loop tends towards a constant:
int val = max_digit10;
for(int i = max_digit11 * 2; ; i++)
{
int trailing_spaces = 0, pow11 = 1, pow10 = 1;
int j = i;
while((j % 11) == 0)
{
trailing_spaces++;
pow11 *= 11;
pow10 *= 10;
j /= 11;
}
int output_val = val / pow10;
if(output_val <= n)
{
cout << output_val << ", ";
count++;
}
if(output_val == n)
found_n = true;
if(trailing_spaces > 1)
{
i += (pow11 / 11) - 1;
}
else if(found_n && (trailing_spaces == 1))
{
i += 10;
val += 10;
}
else if(trailing_spaces == 0)
val++;
if(count == n)
break;
}
Demonstration
The alternative, simpler approach is just to generate N strings from the numbers and sort them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With