当前位置: 首页 > news >正文

leetcode每日一题:统计好整数的数目

题目

给你两个 整数 nk

如果一个整数 x 满足以下条件,那么它被称为 k 回文 整数 。

  • x 是一个 回文整数 。

  • x 能被 k 整除。

如果一个整数的数位重新排列后能得到一个 k 回文整数 ,那么我们称这个整数为 整数。比方说,k = 2 ,那么 2020 可以重新排列得到 2002 ,2002 是一个 k 回文串,所以 2020 是一个好整数。而 1010 无法重新排列数位得到一个 k 回文整数。

请你返回 n 个数位的整数中,有多少个 整数。

注意 ,任何整数在重新排列数位之前或者之后 都不能 有前导 0 。比方说 1010 不能重排列得到 101 。

示例 1:

输入:n = 3, k = 5

输出:27

解释:

部分好整数如下:

  • 551 ,因为它可以重排列得到 515 。

  • 525 ,因为它已经是一个 k 回文整数。

示例 2:

输入:n = 1, k = 4

输出:2

解释:

两个好整数分别是 4 和 8 。

示例 3:

输入:n = 5, k = 6

输出:2468

提示:

  • 1 <= n <= 10

  • 1 <= k <= 9

思路

        本题其实可以分成2个部分:1、求出长度为n且可以被k的回文数字;2、计算第1步求出来数字重新排列后的所有排列可能。

        对于第1步,如果直接遍历判断数字是否是回文肯定会超时,我们尝试构造回文数字。由于回文数字的特点,前半部分和后半部分是对称的,根据长度的奇偶性不同,我们可以分成2种情况:

  • n是奇数,前(n-1)/2 和 后(n-1)/2是对称的,最中间1位是任意的

  • n是偶数,前 n/2 和后 n/2 是对称的

        上述2种情况,在构造的时候,可以统一:我们枚举左半部分的开始,1开头,后面跟(n-1)/2个0,如果n是奇数,后半部分是左半部分反转后去掉首字符,如果是偶数,后半部分直接就是左半部分反转。构造出回文后,我们再判断1次是否可以被k整除,排除掉不能整除的回文数。

        接下来,对于每一个长度为n的整除k的回文,我们要计算排列组合。对于相同数字组合的回文,我们要去重,避免重复计算。例如,n = 4,k = 2,此时 2442 和 4224 都是符合条件的,但是计算的时候,我们只要计算1个数的所有排列即可。去重的方法可以把这个数字组成的字符数组进行排序,排序后的字符串唯一即可。

        对于一个给定的数字,求出全排列的数量,在另外一题有推导过,这里直接使用那一题的结论。

代码

private static final int[] FAC;
​
static {
    FAC = new int[11];
    FAC[0] = 1;
    for (int i = 1; i < FAC.length; i++) {
        FAC[i] = FAC[i - 1] * i;
    }
}
​
public long countGoodIntegers(int n, int k) {
    long ans = 0;
    Set<String> seen = new HashSet<>();
    int begin = (int) Math.pow(10, (n-1)/2);
    for (int left = begin; left < begin * 10; left++) {
        String leftStr = String.valueOf(left);
        String full = leftStr + new StringBuilder(leftStr).reverse().substring(n % 2);
        if (Long.parseLong(full) % k != 0) {
            continue;
        }
        char[] chars = full.toCharArray();
        Arrays.sort(chars);
        if (seen.contains(String.valueOf(chars))) {
            continue;
        }
        ans += cnt(chars);
        seen.add(String.valueOf(chars));
    }
    return ans;
}
​
private long cnt(char[] chars) {
    int[] cnt = new int[10];
    for (char c : chars) {
        cnt[c - '0']++;
    }
    int n = chars.length;
    long ans = (long) (n - cnt[0]) * FAC[n - 1];
    for (int c : cnt) {
        ans /= FAC[c];
    }
    return ans;
}
耗时

相关文章:

  • 路由策略/策略路由之PBR
  • Hyprnote开源程序是一款记录和转录您会议的 AI 记事本。 本地优先且可扩展 。
  • 学习海康VisionMaster之平行线查找
  • 【PowerPoint专栏】PowerPoint的背景设置
  • 每天学一个 Linux 命令(13):touch
  • 图像预处理-插值方法
  • 效率工具- git rebase 全解
  • 实现定长的内存池
  • 【C++】 —— 笔试刷题day_14
  • org.apache.spark.SparkException: Kryo serialization failed: Buffer overflow...
  • Java---抽象类与接口
  • 【C++】继承
  • 【ROS2】行为树:BehaviorTree
  • Spring Boot对接马来西亚股票数据源API
  • 【前端】CSS Grid 布局详解
  • 【PySpark大数据分析概述】03 PySpark大数据分析
  • 0x01、Redis 主从复制的实现原理是什么?
  • 《Vue Router实战教程》14.路由元信息
  • MySQL逻辑架构有什么?
  • JavaScript学习教程,从入门到精通,JavaScript 数组与引用类型语法知识点及案例代码(10)
  • 网站站外引流怎么做/短视频推广策略
  • 如何建立游戏网站/在百度做广告多少钱
  • 网站开发实训教程/没干过网络推广能干吗
  • 获取网站访客qq代码/腾讯朋友圈广告怎么投放
  • 昆明做网站优化/新闻发稿
  • 南宁中庭装饰公司电话/东莞百度搜索优化