vì chỉ có 2 số 6 và 9, mà A và B có tối đa 12 chữ số, vậy chỉ có tổng cộng 2 + 4 + 8 + 16 + … + 4096 = 8190 số chỉ có số 6 và 9 thôi. Viết 1 hàm tạo mảng X chứa 8190 số này theo thứ tự, coi như là constant time. Sau đó binary search A trong mảng X ra vị trí i sao cho X[i] nhỏ nhất và >= A, binary search B ra vị trí j sao cho X[j] lớn nhất và <= B. Kết quả là j - i + 1. Tuy tìm nhị phân thì có độ phức tạp là log(n) nhưng n ở đây là constant (8190) nên cũng coi như constant time O(1).
#include <iostream>
#include <vector>
#include <algorithm>
long long to69(unsigned i, int digit)
{
long long n = 0;
for (unsigned mask = 1 << (digit-1); digit--; mask >>= 1)
n = 10*n + (mask&i ? 9 : 6);
return n;
}
std::vector<long long> getAll69Numbers(int maxDigit)
{
std::vector<long long> result;
unsigned max = 2;
for (int digit = 1; digit <= maxDigit; ++digit, max <<= 1)
for (unsigned i = 0; i < max; ++i)
result.push_back(to69(i, digit));
return result;
}
int GetTotalNumber(long long a, long long b)
{
static const std::vector<long long> N69 = getAll69Numbers(12); //
int i = std::lower_bound(N69.begin(), N69.end(), a) - N69.begin();
int j = std::upper_bound(N69.begin(), N69.end(), b) - N69.begin();
return j - i;
}
int main()
{
std::cout << "[5, 70]: " << GetTotalNumber(5, 70) << "\n";
std::cout << "[3, 100]: " << GetTotalNumber(3, 100) << "\n";
std::cout << "[65, 68]: " << GetTotalNumber(65, 68) << "\n";
std::cout << "[0, 999999999999]: " << GetTotalNumber(0, 999999999999) << "\n";
}
up thêm cái code, nếu xài C++11 thì có cái auto thì xài std::distance để tính khoảng cách giữa iterator i và j, khỏi mất công trừ N69.begin() để lấy index:
auto i = std::lower_bound(N69.begin(), N69.end(), a);
auto j = std::upper_bound(N69.begin(), N69.end(), b);
return std::distance(i, j);