LeetCode 479. Largest Palindrome Product
原题链接
困难
作者:
JasonSun
,
2020-02-11 13:19:11
,
所有人可见
,
阅读 717
Algorithm (Exhaustive Search)
- First, we note that for a given digit $n$, the two factors of the product can only be in range $[10^{n},10^{n+1}-1]$ and the corresponding palindrome has to be in range $[10^{2n},(10^{n+1}-1)^{2}]$, from which we can see that the length of the corresponing palindrome is in $[\log_{10}10^{2n},2\log_{10}(10^{n+1}-1)],$ which rounds to $2n$.
- Therefore, we can exhausively make palindrome of length $2n$ starting from the highest possible choice and for each palindrome check if can be written as the produce of two factors of $n$-digits.
- The checking procedure could be optimized by narrowing the search range to finding the other factor while assuming one of the factor is between $\lfloor x/(10^{n+1}-1)\rfloor$ and $\lceil\sqrt{x}\rceil$, where $x$ is the generated palindrome. This is because the former is the lowest factor possible and the latter is an upper bound for the lower factor.
- Note that we also need to check if the generated palindrome is within the range proposed at the begining.
Code
class Solution {
public:
int largestPalindrome(int n) {
typedef long long int64;
const auto mod = int64(1337);
const auto [factor_min, factor_max] = pair{int64(std::pow(10, n - 1)), int64(std::pow(10, n) - 1)};
const auto [range_min, range_max] = pair{factor_min * factor_min, factor_max * factor_max};
std::function<int(int)> digit_count = [&](int x) {
return x == 0 ? 0 : 1 + digit_count(x / 10);
};
auto reverse = [&](int64 x) {
std::function<int64(int64, int64)> go = [&](int64 x, int64 acc = 0) {
return x == 0 ? acc : go(x / 10, 10 * acc + x % 10);
};
return go(x, 0);
};
auto make_even_palindrome = [&](int64 left) {
return int64(left * (long long)std::pow(10, digit_count(left)) + reverse(left));
};
auto make_odd_palindrome = [&](int64 left) {
return int64(left * (long long)std::pow(10, digit_count(left) - 1) + reverse(left / 10));
;
};
auto has_two_n_digit_factors = [&](long long x) {
const auto [L, R] = pair{int64(double(x) / double(factor_max)),
int64(std::sqrt(x) + 1)};
for (int64 factor = L; factor <= R; ++factor)
if (x % factor == 0 and factor_min <= x / factor and x / factor <= factor_max)
return true;
return false;
};
const auto solution = [&] {
for (int64 seed = factor_max; seed >= factor_min; --seed) {
const auto peven = make_even_palindrome(seed);
if (range_min <= peven and peven <= range_max and has_two_n_digit_factors(peven))
return peven;
}
for (int64 seed = factor_max; seed >= factor_min; --seed) {
const auto podd = make_odd_palindrome(seed);
if (range_min <= podd and podd <= range_max and has_two_n_digit_factors(podd))
return podd;
}
throw std::domain_error("no solution!");
}();
return solution % mod;
}
};