2023-05-02:如果一个正整数每一个数位都是 互不相同 的,我们称它是 特殊整数 。 给你一个正整数 n ,请你返回区间 [1, n] 之间特殊整数的数目。 输入:n = 20。 输出:19。
2023-05-02:如果一个正整数每一个数位都是 互不相同 的,我们称它是 特殊整数 。
给你一个正整数 n ,请你返回区间 [1, n] 之间特殊整数的数目。
输入:n = 20。
输出:19。
答案2023-05-02:
可以通过数字组合和状态压缩的动态规划算法来解决。具体过程如下:
1.对于给定的正整数 n,求出其位数 len。
2.枚举所有小于 len 位的数字,计算其中特殊整数的总数。如果数字为 i 位,则特殊整数个数为 9 * 8 * ... * (10 - i)。
3.对于第 len 位上的数字 x,在计算期间将其提取出来。
4.如果 x 是第一个数字,则区间 [1, n] 中,第 len 位之前的数字不受限制,因此可以选取任意一个非零数字,共有 9 种可能。
5.对于区间 [1, n] 中第 len 位之前的每个数字,考虑它们与 x 组合所能得到的所有特殊整数。如果某个数字已经在当前组合中出现过,则不能再重复使用。
6.递归求解所有满足要求的数字组合,每次处理一位,直到组合中所有数字都确定下来。
7.对于区间 [1, n] 中的每个数字,检查其是否为特殊整数,并统计个数。
8.返回特殊整数的总数。
该算法的时间复杂度为 O(n log n),空间复杂度为 O(log n)。由于需要进行大量的数字组合枚举和状态压缩操作,实现起来较为复杂。
rust完整代码如下:
const OFFSET: [i32; 11] = [
    0,     // 0位数,一共能解决几个位
    1,     // 1位数,一共能解决几个位
    10,    // 2位数,一共能解决几个位
    100,   // 3位数,一共能解决几个位
    1000,  // 4位数,一共能解决几个位
    10000, // 5位数,一共能解决几个位
    100000, 1000000, 10000000, 100000000, 1000000000,
];
fn count_special_numbers(n: i32) -> i32 {
    let len = len(n);
    let mut ans = 0;
    for i in 1..len {
        ans += all(i);
    }
    let first_number = n / OFFSET[len as usize];
    ans += (first_number - 1) * small(len - 1, 9);
    ans += process(n, len, len - 1, 1 << first_number);
    return ans;
}
// 返回n这个数字有几位
fn len(mut n: i32) -> i32 {
    let mut ans = 0;
    while n != 0 {
        ans += 1;
        n /= 10;
    }
    return ans;
}
// 返回所有bits位数,有几个特殊的
fn all(bits: i32) -> i32 {
    let mut ans = 9;
    let mut cur = 9;
    for _ in 1..bits {
        ans *= cur;
        cur -= 1;
    }
    return ans;
}
// bits : 8 7 6 5 4位
// candidates : 8 可能性
// bits : _ _ _ 3位
// candidates : 5 可能性
fn small(bits: i32, candidates: i32) -> i32 {
    let mut ans = 1;
    let mut cur_candidate = candidates;
    for _ in 0..bits {
        ans *= cur_candidate;
        cur_candidate -= 1;
    }
    return ans;
}
// num : 原始数 46531 固定
// len : 原始数有几位,5位,固定
// rest : 还剩几位没决定,可变参数
// num : 46531
//       4 _ _ _ _
//       4 0~5
//       4 6 _ _ _
// status : 4 6 _ _ _
// 哪些数字使用了,状态!在status里:
// 体系学习班,状态压缩的动态规划!
// int status 32位
// 9 8 7 6 5 4 3 2 1 0
//       1 0 1 0 0 0 0
// 4 6 _ _ _ 还有几个达标的!
// 哪些数字选了都在status里,用一个status变量表示数字选没选(位信息)
fn process(num: i32, len: i32, rest: i32, status: i32) -> i32 {
    if rest == 0 {
        return 1;
    }
    // 46531
    //   ___
    //   5
    // 46531 / 100 -> 465 % 10 -> 5
    // 比5小的有几股?0 1 2 3 4
    //
    // n : 454012
    //     45_
    //       0...
    //       1...
    //       2...
    //       3...
    //       4 _ _ _
    let cur = (num / OFFSET[rest as usize]) % 10;
    let mut cnt = 0;
    for i in 0..cur {
        if (status & (1 << i)) == 0 {
            cnt += 1;
        }
    }
    let mut ans = cnt * small(rest - 1, 9 - (len - rest));
    if (status & (1 << cur)) == 0 {
        ans += process(num, len, rest - 1, status | (1 << cur));
    }
    return ans;
}
fn main() {
    let n = 135;
    let ans = count_special_numbers(n);
    println!(
        "The number of special numbers between 1 and {} is {}",
        n, ans
    );
}

go完整代码如下:
package main
import "fmt"
var offset = []int{
	0,
	1,
	10,
	100,
	1000,
	10000,
	100000,
	1000000,
	10000000,
	100000000,
	1000000000,
}
func countSpecialNumbers(n int) int {
	len := len(n)
	ans := 0
	for i := 1; i < len; i++ {
		ans += all(i)
	}
	firstNumber := n / offset[len]
	ans += (firstNumber - 1) * small(len-1, 9)
	ans += process(n, len, len-1, 1<<firstNumber)
	return ans
}
func len(n int) int {
	ans := 0
	for n != 0 {
		ans++
		n /= 10
	}
	return ans
}
func all(bits int) int {
	ans := 9
	cur := 9
	for i := 1; i < bits; i++ {
		ans *= cur
		cur--
	}
	return ans
}
func small(bits int, candidates int) int {
	ans := 1
	for i := 0; i < bits; i++ {
		ans *= candidates
		candidates--
	}
	return ans
}
func process(num int, len int, rest int, status int) int {
	if rest == 0 {
		return 1
	}
	cur := (num / offset[rest]) % 10
	cnt := 0
	for i := 0; i < cur; i++ {
		if (status & (1 << i)) == 0 {
			cnt++
		}
	}
	ans := cnt * small(rest-1, 9-(len-rest))
	if (status & (1 << cur)) == 0 {
		ans += process(num, len, rest-1, status|(1<<cur))
	}
	return ans
}
func main() {
	n := 135
	ans := countSpecialNumbers(n)
	fmt.Printf("The number of special numbers between 1 and %d is %d\n", n, ans)
}

c完整代码如下:
#include <stdio.h>
int offset[] = {
	0,
	1,
	10,
	100,
	1000,
	10000,
	100000,
	1000000,
	10000000,
	100000000,
	1000000000
};
int len(int n) {
	int ans = 0;
	while (n != 0) {
		ans++;
		n /= 10;
	}
	return ans;
}
int all(int bits) {
	int ans = 9;
	int cur = 9;
	while (--bits != 0) {
		ans *= cur--;
	}
	return ans;
}
int small(int bits, int candidates) {
	int ans = 1;
	for (int i = 0; i < bits; i++, candidates--) {
		ans *= candidates;
	}
	return ans;
}
int process(int num, int len, int rest, int status) {
	if (rest == 0) {
		return 1;
	}
	int cur = (num / offset[rest]) % 10;
	int cnt = 0;
	for (int i = 0; i < cur; i++) {
		if ((status & (1 << i)) == 0) {
			cnt++;
		}
	}
	int ans = cnt * small(rest - 1, 9 - (len - rest));
	if ((status & (1 << cur)) == 0) {
		ans += process(num, len, rest - 1, status | (1 << cur));
	}
	return ans;
}
int countSpecialNumbers(int n) {
	int len0 = len(n);
	int ans = 0;
	for (int i = 1; i < len0; i++) {
		ans += all(i);
	}
	int firstNumber = n / offset[len0];
	ans += (firstNumber - 1) * small(len0 - 1, 9);
	ans += process(n, len0, len0 - 1, 1 << firstNumber);
	return ans;
}
int main() {
	int n = 135;
	int ans = countSpecialNumbers(n);
	printf("The number of special numbers between 1 and %d is %d\n", n, ans);
	return 0;
}

c++完整代码如下:
#include <iostream>
using namespace std;
int offset[11] = {
	0,
	1,
	10,
	100,
	1000,
	10000,
	100000,
	1000000,
	10000000,
	100000000,
	1000000000
};
int len(int n) {
	int ans = 0;
	while (n != 0) {
		ans++;
		n /= 10;
	}
	return ans;
}
int all(int bits) {
	int ans = 9;
	int cur = 9;
	while (--bits != 0) {
		ans *= cur--;
	}
	return ans;
}
int small(int bits, int candidates) {
	int ans = 1;
	for (int i = 0; i < bits; i++, candidates--) {
		ans *= candidates;
	}
	return ans;
}
int process(int num, int len, int rest, int status) {
	if (rest == 0) {
		return 1;
	}
	int cur = (num / offset[rest]) % 10;
	int cnt = 0;
	for (int i = 0; i < cur; i++) {
		if ((status & (1 << i)) == 0) {
			cnt++;
		}
	}
	int ans = cnt * small(rest - 1, 9 - (len - rest));
	if ((status & (1 << cur)) == 0) {
		ans += process(num, len, rest - 1, status | (1 << cur));
	}
	return ans;
}
int countSpecialNumbers(int n) {
	int len0 = len(n);
	int ans = 0;
	for (int i = 1; i < len0; i++) {
		ans += all(i);
	}
	int firstNumber = n / offset[len0];
	ans += (firstNumber - 1) * small(len0 - 1, 9);
	ans += process(n, len0, len0 - 1, 1 << firstNumber);
	return ans;
}
int main() {
	int n = 135;
	int ans = countSpecialNumbers(n);
	cout << "The number of special numbers between 1 and " << n << " is " << ans << endl;
	return 0;
}

2023-05-02:如果一个正整数每一个数位都是 互不相同 的,我们称它是 特殊整数 。 给你一个正整数 n ,请你返回区间 [1, n] 之间特殊整数的数目。 输入:n = 20。 输出:19。的更多相关文章
- C++ PTA 本题要求实现一个计算m和n之间所有整数的和
		6-2 2020mhb_函数_求和 (10分) 本题要求实现一个计算m和n之间所有整数的和(求和时需要将m和n也加入到和中)的函数.注意:如果m<=n则计算m到n的所有整数之和,如果m> ... 
- java标签(label)求16进制字符串的整数和 把一个整数转为4个16进制字符表示
		p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Menlo; color: #4f76cb } p.p2 { margin: 0.0px 0. ... 
- 梁勇 java教材 编程练习题 第二章 2.6 键盘 读取一个在0 到 9999 之间的整数,并将该整数的各位数字相加。
		import java.util.Scanner; /** * 需求:从键盘输入任意0~9999之间的整数,输出这个整数各位数字之和. * 思路:方法一,使用扫描器Scanner类,扫描控制台输入流 ... 
- js实现随机选取[10,100)中的10个整数,存入一个数组,并排序。    另考虑(10,100]和[10,100]两种情况。
		1.js实现随机选取[10,100)中的10个整数,存入一个数组,并排序. <!DOCTYPE html> <html lang="en"> <hea ... 
- JS事件 编程练习-自制计算器 使用JS完成一个简单的计算器功能。实现2个输入框中输入整数后,点击第三个输入框能给出2个整数的加减乘除。
		编程练习 使用JS完成一个简单的计算器功能.实现2个输入框中输入整数后,点击第三个输入框能给出2个整数的加减乘除. 提示:获取元素的值设置和获取方法为:例:赋值:document.getElement ... 
- [转]linux shell数据重定向(输入重定向与输出重定向)详细分析
		在了解重定向之前,我们先来看看linux 的文件描述符. linux文件描述符:可以理解为linux跟踪打开文件,而分配的一个数字,这个数字有点类似c语言操作文件时候的句柄,通过句柄就可以实现文件 ... 
- C++ 输入cin 和输出cout
		C++输入cout与输出cin 输入和输出并不是C++语言中的正式组成成分.C和C++本身都没有为输入和输出提供专门的语句结构.输入输出不是由C++本身定义的,而是在编译系统提供的I/O库中定义的. ... 
- CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
		CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. 主要方法 public CountDownLatch(int count); pu ... 
- 【mybatis深度历险系列】mybatis中的输入映射和输出映射
		在前面的博文中,小编介绍了mybatis的框架原理以及入门程序,还有mybatis中开发到的两种方法,原始开发dao的方法和mapper代理方法,今天博文,我们来继续学习mybatis中的相关知识,随 ... 
- Python基础之注释,算数运算符,变量,输入和格式化输出
		Python的注释 注释的作用:用自己熟悉的语言,对某些代码进行标注说明,增强程序的可读性: 在python解释器解释代码的过程中,凡是#右边的,解释器都直接跳过这一行: 注释的分类 单行注释 # 这 ... 
随机推荐
- ansible介绍与简单的使用
			在roles下建立site.yml文件#site.yml - hosts: webservers remote_user: root roles: - websrvs - dbsrvs#将文件拷贝到f ... 
- 2.3Dmax界面_视图调整
			一.试图模型显示效果的切换 '默认是真实显示效果' 线框模式 快捷键F3 ----> 真实显示效果和线框显示效果的切换(切换到线框显示效果再按F3就切换到了真实显示效果). 线面模式 快捷键F4 ... 
- Oracle查询优化经验
			1.ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾. (低效,执行时间156 ... 
- 随笔:for in 和 for of的区别
			百度前端面试题:for in 和 for of的区别详解以及为for in的输出顺序 - 知乎 以该页面为例,我稍微总结一点东西: 在这⾥我们把对象中的数字属性称为 「排序属性」,在V8中被称为 el ... 
- zabbix 告警说明及触发cpu告警
			1. https://www.cnblogs.com/caonw/p/12766454.html 1.内存检测:Template OS Linux:vm.memory.size[available]. ... 
- Java下变量大小写驼峰、大小写下划线、大小写连线转换
			<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artif ... 
- ubuntu14.04 cm12.0 genymotion
			前几天在ubuntu14.04编译过android5.0.1源码,但是呢?不知怎么运行不起来,后来又试了试把img文件在win平台运行虚拟机不知怎么还是不行,再后来想通过刷机运行学习framework ... 
- 基本的dns命令
			打开cmd的方式 win+r 键 输入cmd 管理员方式运行 打开桌面 命令提示符 盘符切换 直接输入要切换的盘 查看当前目录下所有文件 dir 切换目录 cd /d 跨盘 ... 
- https加固,https://ip暴露后端IP。
			增加server配置server { listen 443 default_server; server_name _ ; ssl on; ssl_certificate test.crt 随便设置一 ... 
- python内置函数open()
			open()函数 介绍 open()函数用于打开文件并创建文件对象. open()函数的语法格式: file = open(filename, mode='r', buffering=-1, enco ... 
