难度困难
题目描述
给定一个表示整数的字符串 n ,返回与它最近的回文整数(不包括自身)。如果不止一个,返回较小的那个。
“最近的”定义为两个整数差的绝对值最小。
示例 1:
输入: n = "123"
输出: "121"
示例 2:
输入: n = "1"
输出: "0"
解释: 0 和 2是最近的回文,但我们返回最小的,也就是 0。
提示:
1 <= n.length <= 18 n 只由数字组成 n 不含前导 0 n 代表在 [1, 1018 - 1] 范围内的整数
解法
方法一
思考
要找与 \(n\) 数值最接近且不等于 \(n\) 的回文数。在附近枚举整数再判断回文,范围漫无边界。
最近回文只可能来自「镜像前半」及其 \(\pm 1\),再加上位数变化的 \(99\ldots9\) 与 \(100\ldots001\)。对前半加减一后按长度镜像,丢掉 \(n\) 本身,再按距离、再按数值选取。候选只有常数个。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | class Solution:
def nearestPalindromic(self, n: str) -> str:
x = int(n)
l = len(n)
res = {10 ** (l - 1) - 1, 10**l + 1}
left = int(n[: (l + 1) >> 1])
for i in range(left - 1, left + 2):
j = i if l % 2 == 0 else i // 10
while j:
i = i * 10 + j % 10
j //= 10
res.add(i)
res.discard(x)
ans = -1
for t in res:
if (
ans == -1
or abs(t - x) < abs(ans - x)
or (abs(t - x) == abs(ans - x) and t < ans)
):
ans = t
return str(ans)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 | import java.math.BigInteger;
class Solution {
public String nearestPalindromic(String n) {
BigInteger x = new BigInteger(n);
int l = n.length();
Set<BigInteger> res = new HashSet<>();
res.add(BigInteger.TEN.pow(l - 1).subtract(BigInteger.ONE));
res.add(BigInteger.TEN.pow(l).add(BigInteger.ONE));
BigInteger left = new BigInteger(n.substring(0, (l + 1) / 2));
for (int d = -1; d <= 1; ++d) {
BigInteger i = left.add(BigInteger.valueOf(d));
BigInteger j = l % 2 == 0 ? i : i.divide(BigInteger.TEN);
while (j.signum() > 0) {
i = i.multiply(BigInteger.TEN).add(j.mod(BigInteger.TEN));
j = j.divide(BigInteger.TEN);
}
res.add(i);
}
res.remove(x);
BigInteger ans = null;
for (BigInteger t : res) {
BigInteger dist = t.subtract(x).abs();
if (ans == null || dist.compareTo(ans.subtract(x).abs()) < 0
|| (dist.compareTo(ans.subtract(x).abs()) == 0 && t.compareTo(ans) < 0)) {
ans = t;
}
}
return ans.toString();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 | using i128 = __int128_t;
class Solution {
public:
string nearestPalindromic(string n) {
i128 x = parse(n);
int l = n.size();
set<i128> res;
res.insert(pow10(l - 1) - 1);
res.insert(pow10(l) + 1);
i128 left = parse(n.substr(0, (l + 1) / 2));
for (int d = -1; d <= 1; ++d) {
i128 i = left + d;
i128 j = l % 2 == 0 ? i : i / 10;
while (j) {
i = i * 10 + j % 10;
j /= 10;
}
res.insert(i);
}
res.erase(x);
i128 ans = -1;
for (i128 t : res) {
i128 dt = iabs(t - x);
i128 da = iabs(ans - x);
if (ans == -1 || dt < da || (dt == da && t < ans)) {
ans = t;
}
}
return toStr(ans);
}
private:
i128 parse(const string& s) {
i128 x = 0;
for (char c : s) {
x = x * 10 + (c - '0');
}
return x;
}
i128 pow10(int k) {
i128 x = 1;
while (k--) {
x *= 10;
}
return x;
}
i128 iabs(i128 x) {
return x < 0 ? -x : x;
}
string toStr(i128 x) {
if (x == 0) {
return "0";
}
string s;
while (x) {
s.push_back(char('0' + x % 10));
x /= 10;
}
reverse(s.begin(), s.end());
return s;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 | func nearestPalindromic(n string) string {
x := new(big.Int)
x.SetString(n, 10)
l := len(n)
ten := big.NewInt(10)
base := new(big.Int).Exp(ten, big.NewInt(int64(l-1)), nil)
res := []*big.Int{
new(big.Int).Sub(new(big.Int).Set(base), big.NewInt(1)),
new(big.Int).Add(new(big.Int).Mul(new(big.Int).Set(base), ten), big.NewInt(1)),
}
left := new(big.Int)
left.SetString(n[:(l+1)/2], 10)
for d := int64(-1); d <= 1; d++ {
i := new(big.Int).Add(left, big.NewInt(d))
j := new(big.Int).Set(i)
if l&1 == 1 {
j.Quo(j, ten)
}
for j.Sign() > 0 {
i.Mul(i, ten)
i.Add(i, new(big.Int).Mod(j, ten))
j.Quo(j, ten)
}
res = append(res, i)
}
var ans *big.Int
for _, t := range res {
if t.Cmp(x) == 0 {
continue
}
dist := new(big.Int).Abs(new(big.Int).Sub(t, x))
if ans == nil {
ans = new(big.Int).Set(t)
continue
}
best := new(big.Int).Abs(new(big.Int).Sub(ans, x))
if dist.Cmp(best) < 0 || (dist.Cmp(best) == 0 && t.Cmp(ans) < 0) {
ans = new(big.Int).Set(t)
}
}
return ans.String()
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 | /**
* @param {string} n
* @return {string}
*/
function nearestPalindromic(n) {
const x = BigInt(n);
let ans = null;
for (const t of getCandidates(n)) {
if (
ans === null ||
absDiff(t, x) < absDiff(ans, x) ||
(absDiff(t, x) === absDiff(ans, x) && t < ans)
) {
ans = t;
}
}
return ans.toString();
}
function getCandidates(n) {
const length = n.length;
const res = new Set();
res.add(10n ** BigInt(length - 1) - 1n);
res.add(10n ** BigInt(length) + 1n);
const left = BigInt(n.substring(0, Math.ceil(length / 2)));
for (let i = left - 1n; i <= left + 1n; i++) {
const prefix = i.toString();
const t =
prefix +
prefix
.split('')
.reverse()
.slice(length % 2)
.join('');
res.add(BigInt(t));
}
res.delete(BigInt(n));
return res;
}
function absDiff(a, b) {
return a > b ? a - b : b - a;
}
|