// Source : https://leetcode.com/problems/lexicographical-numbers/ // Author : Hao Chen // Date : 2016-08-23 /*************************************************************************************** * * Given an integer n, return 1 - n in lexicographical order. * * For example, given 13, return: [1,10,11,12,13,2,3,4,5,6,7,8,9]. * * Please optimize your algorithm to use less time and space. The input size may be as * large as 5,000,000. ***************************************************************************************/ class Solution { //Solution 1: convert the int to string for sort, Time complexity is high (Time Limited Error) public: vector<int> lexicalOrder01(int n) { vector<int> result; for (int i=1; i<=n; i++) { result.push_back(i); } sort(result.begin(), result.end(), this->myComp); return result; } private: static bool myComp(int i,int j) { static char si[32]={0}, sj[32]={0}; sprintf(si, "%d\0", i); sprintf(sj, "%d\0", j); return (strcmp(si, sj)<0); } //Solution 2 : using recursive way to solution the problem, 540ms public: vector<int> lexicalOrder02(int n) { vector<int> result; for (int i=1; i<=n && i<=9; i++) { result.push_back(i); lexicalOrder_helper(i, n, result); } return result; } private: void lexicalOrder_helper(int num, int& n, vector<int>& result) { for (int i=0; i<=9; i++) { int tmp = num * 10 + i; if (tmp > n) { break; } result.push_back(tmp); lexicalOrder_helper(tmp, n, result); } } //Solution 3: no recursive way, but the code is not easy to read public : vector<int> lexicalOrder03(int n) { vector<int> result; int curr = 1; while (result.size()<n) { // Step One // --------- //Adding all of the possible number which multiply 10 as much as possible // such as: curr = 1, then 1, 10, 100, 1000 ... // curr = 12, then 12, 120, 1200, ... for (; curr <= n; curr*=10 ) { result.push_back(curr); } // Step Two // --------- // After find the number which multiply 10 greater than `n`, then go back the previous one, // and keep adding 1 until it carry on to next number // for example: // curr = 100, then we need evalute: 11,12,13,14,15,16,17,18,19, but stop at 20 // curr = 230, then we need evaluate: 24,25,26,27,28,29, but stop at 30. curr = curr/10 + 1; for (; curr <= n && curr % 10 != 0; curr++) { result.push_back(curr); } // Step Three // ---------- // Now, we finished all of the number, we need go back for next number // Here is a bit tricky. // // Assuming the n is 234, and Step One evaluted 190, and Step Two, evaluted 191,192,...,199 // Now, the `curr` is 200, and we need start from 2 instead of 20, that's why need keep dividing 10 for (; curr%10 == 0; curr/=10); } return result; } //start point public: vector<int> lexicalOrder(int n) { srand(time(NULL)); if (rand()%2) return lexicalOrder02(n); // recursive way 560ms else return lexicalOrder03(n); // non-recursive way, 460ms } };