GuilinDev

Lc2081

05 August 2008

2081. Sum of k-Mirror Numbers

k 镜像数字的和

一个 k 镜像数字 指的是一个在十进制和 k 进制下从前往后读和从后往前读都一样的 没有前导 0 的 正 整数。

比方说,9 是一个 2 镜像数字。9 在十进制下为 9 ,二进制下为 1001 ,两者从前往后读和从后往前读都一样。 相反地,4 不是一个 2 镜像数字。4 在二进制下为 100 ,从前往后和从后往前读不相同。 给你进制 k 和一个数字 n ,请你返回 k 镜像数字中 最小 的 n 个数 之和 。

 

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
示例 1:

输入:k = 2, n = 5
输出:25
解释:
最小的 5 个 2 镜像数字和它们的二进制表示如下:
  十进制       二进制
    1          1
    3          11
    5          101
    7          111
    9          1001
它们的和为 1 + 3 + 5 + 7 + 9 = 25 。

示例 2:

输入:k = 3, n = 7
输出:499
解释:
7 个最小的 3 镜像数字和它们的三进制表示如下:
  十进制       三进制
    1          1
    2          2
    4          11
    8          22
    121        11111
    151        12121
    212        21212
它们的和为 1 + 2 + 4 + 8 + 121 + 151 + 212 = 499 。

迭代获取下一个对称10进制数

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
class Solution {

    // 得到比 str 大的下一个 10 进制对称的数字,例如 1->2, 4->5, 9->11
    public String next(String str) {
        int len = str.length();

        StringBuilder sb = new StringBuilder();
        // 将 str 截断一半,然后 + 1   最后把另一半缺失的数字补齐即可
        long num = Long.parseLong(str.substring(0, (len + 1) / 2));

        // 发生进位,则表示下一个数字的位数是 len + 1 位, 比如 99 下一个对称数字 101 就发生了进位
        if (Long.toString(num + 1).length() != Long.toString(num).length()) {
            for (int i = 0; i <= len; i++) {
                if (i == 0 || i == len) {
                    sb.append(1);
                } else {
                    sb.append(0);
                }
            }
        } else {
            sb.append(num + 1);
            for (int i = (len + 1) / 2; i < len; i++) {
                sb.append(sb.charAt(len - 1 - i));
            }
        }

        return sb.toString();
    }

    public long kMirror(int k, int n) {
        long result = 0;

        String str = "1";
        while (n > 0) {
            long i = Long.parseLong(str);
            if (symmetry(Long.toString(i, k))) {
                result += i;
                n--;
            }
            str = next(str);
        }

        return result;
    }

    // 检查字符串是对称
    public boolean symmetry(String str) {
        int n = str.length();
        int s = 0, e = n - 1;
        while (s < e) {
            if (str.charAt(s) != str.charAt(e)) return false;

            s++;
            e--;
        }

        return true;
    }
}
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
class Solution {
    
    // Long.toString(int n, int k) 获取数字n的k进制的字符串
    // 于是问题的关键在于怎么快速的找到下一个回文数
    public long kMirror(int k, int n) {
        long res = 0;
        String start = "1";
        while(n != 0) {
            Long cur = Long.parseLong(start);
            if(isPaddle(Long.toString(cur, k))) {
                res += cur;
                n--;
            }
            start = nextPaddle(start);
        }

        return res;
    }
    // 找到比s大的第一个回文数
    // 想法是把当前的数给截半,比如当前的数是121,那么下一个回文数是131
    // 做法就是将121 变成12  将12加1,变成13,再把后面的部分补齐即可
    // 对于99的下一个回文数应该是101,具体为将99变成9, 然后加一得到10,然后补全
    public String nextPaddle(String s) {
        int n = s.length();
        StringBuilder sb = new StringBuilder();
        // 截取一半,注意substring(int i, int j)截取的是[i, j),所以需要加一
        long num = Long.parseLong(s.substring(0, (n + 1) / 2));
        // 如果当前是9的话,那么加1的话会产生进位,也就是99的下一个回文数为101
        if(Long.toString(num + 1).length() != Long.toString(num).length()) {
            for(int i = 0; i <= n; i++) {
                if(i == 0 || i == n) {
                    sb.append('1');
                }else {
                    sb.append('0');
                }
            } 
        }else {//不发生进位的话,形如121变成131
            sb.append(num + 1);
            for(int i = (n + 1)/2; i < n; i++){
                sb.append(sb.charAt(n - 1 - i));
            }

        }
        return sb.toString();
    }

    // 判断是否是回文数
    public boolean isPaddle(String x) {
        int n = x.length();
        for(int i = 0; i < n / 2; i++) {
            if(x.charAt(i) != x.charAt(n - i - 1)) {
                return false;
            }
        }

        return true;
    }
}