力扣2081

题目

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

比方说,9 是一个 2 镜像数字。9 在十进制下为 9 ,二进制下为 1001 ,两者从前往后读和从后往前读都一样。

相反地,4 不是一个 2 镜像数字。4 在二进制下为 100 ,从前往后和从后往前读不相同。

给你进制 k 和一个数字 n ,请你返回 k 镜像数字中 最小 的 n 个数 之和 。

示例 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 。

示例 3:

输入:k = 7, n = 17

输出:20379000

解释:17 个最小的 7 镜像数字分别为:

1, 2, 3, 4, 5, 6, 8, 121, 171, 242, 292, 16561, 65656, 2137312, 4602064, 6597956, 6958596

提示:

2 <= k <= 9

1 <= n <= 30

java 复制代码
import java.util.*;

public class test {

    // 核心方法:找前n个k镜像数并返回和
    public static long kMirror(int k, int n) {
        List<Long> result = new ArrayList<>(n);
        long sum = 0;
        int length = 1; // 从1位回文数开始构造

        System.out.println("寻找前 " + n + " 个 " + k + " 镜像数字 (优化版):");
        System.out.println("======================================");

        while (result.size() < n) {
            // 构造当前长度的所有十进制回文数(按升序)
            List<Long> palindromes = generatePalindromes(length);
            for (long pal : palindromes) {
                if (result.size() >= n) break;
                // 检查k进制是否回文
                if (isKBasePalindrome(pal, k)) {
                    result.add(pal);
                    sum += pal;
                    // 打印日志
                    String kStr = Long.toString(pal, k);
                    System.out.printf("%d. 10进制: %d | %d进制: %s%n",
                            result.size(), pal, k, kStr);
                }
            }
            length++;
        }

        System.out.println("======================================");
        System.out.println("前" + n + "个" + k + "镜像数字之和: " + sum);
        return sum;
    }

    /**
     * 构造指定长度的十进制回文数(升序)
     * 例如:length=3 → 101,111,...,191,202,...,999
     */
    private static List<Long> generatePalindromes(int length) {
        List<Long> palindromes = new ArrayList<>();
        long start = (long) Math.pow(10, (length - 1) / 2); // 左半部分起始值
        long end = (long) Math.pow(10, (length + 1) / 2) - 1; // 左半部分结束值

        for (long left = start; left <= end; left++) {
            StringBuilder sb = new StringBuilder();
            String leftStr = String.valueOf(left);
            sb.append(leftStr);
            // 构造右半部分(奇数长度去掉最后一位,偶数长度直接反转)
            String rightPart = new StringBuilder(leftStr)
                    .reverse()
                    .substring(length % 2); // 奇数长度跳过最后一位
            sb.append(rightPart);
            // 转换为数字
            palindromes.add(Long.parseLong(sb.toString()));
        }
        return palindromes;
    }

    /**
     * 检查数字在k进制下是否回文(优化版:避免完整转换字符串)
     */
    private static boolean isKBasePalindrome(long num, int k) {
        if (num < 0) return false;
        if (num < k) return true; // 1位数必然回文

        // 直接计算k进制的各位数字,同时检查回文(减少字符串操作)
        List<Integer> digits = new ArrayList<>();
        long temp = num;
        while (temp > 0) {
            digits.add((int) (temp % k));
            temp /= k;
        }

        // 双指针检查回文
        int left = 0, right = digits.size() - 1;
        while (left < right) {
            if (!digits.get(left).equals(digits.get(right))) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }

    public static void main(String[] args) {
        // 测试用例
        System.out.println("=== 测试 k=2, n=5 ===");
        kMirror(2, 5);
        System.out.println();

        System.out.println("=== 测试 k=3, n=7 ===");
        kMirror(3, 7);
        System.out.println();

        System.out.println("=== 测试 k=7, n=17 ===");
        kMirror(7, 17);
        System.out.println();
    }
}

比较关键的是如何寻找回文数字,该代码是寻找10进制的回文数字,并判断其k进制是否是回文数字。在寻找过程中,如果采用暴力方法,很难应对较大的k和n,所以要优化一下寻找过程。

java 复制代码
    private static List<Long> generatePalindromes(int length) {
        List<Long> palindromes = new ArrayList<>();
        long start = (long) Math.pow(10, (length - 1) / 2); // 左半部分起始值
        long end = (long) Math.pow(10, (length + 1) / 2) - 1; // 左半部分结束值

        for (long left = start; left <= end; left++) {
            StringBuilder sb = new StringBuilder();
            String leftStr = String.valueOf(left);
            sb.append(leftStr);
            // 构造右半部分(奇数长度去掉最后一位,偶数长度直接反转)
            String rightPart = new StringBuilder(leftStr)
                    .reverse()
                    .substring(length % 2); // 奇数长度跳过最后一位
            sb.append(rightPart);
            // 转换为数字
            palindromes.add(Long.parseLong(sb.toString()));
        }
        return palindromes;
    }

我采取的是构造一半的数字,再反转到另一半。如果是偶数,可以直接反转,如果是奇数,则不要最后一位数字,反转过去。

相关推荐
ANYOLY4 小时前
Sentinel 限流算法详解
算法·sentinel
No0d1es5 小时前
电子学会青少年软件编程(C/C++)六级等级考试真题试卷(2025年9月)
c语言·c++·算法·青少年编程·图形化编程·六级
AndrewHZ5 小时前
【图像处理基石】图像去雾算法入门(2025年版)
图像处理·人工智能·python·算法·transformer·cv·图像去雾
Knox_Lai5 小时前
数据结构与算法学习(0)-常见数据结构和算法
c语言·数据结构·学习·算法
橘颂TA5 小时前
【剑斩OFFER】算法的暴力美学——矩阵区域和
算法·c/c++·结构与算法
不会c嘎嘎5 小时前
每日一练 -- day1
c++·算法
hansang_IR6 小时前
【记录】网络流最小割建模三题
c++·算法·网络流·最小割
xwill*6 小时前
Helix: A Vision-Language-Action Model for Generalist Humanoid Control
人工智能·算法
blammmp6 小时前
算法专题二十:贪心算法
数据结构·算法·贪心算法
Dream it possible!6 小时前
LeetCode 面试经典 150_二叉树层次遍历_二叉树的层序遍历(83_102_C++_中等)
c++·leetcode·面试·二叉树