You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

146 lines
3.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2023_03_2_week;
// 给定正整数 n
// 返回在 [1, n] 范围内具有 至少 1 位 重复数字的正整数的个数。
// 测试链接 : https://leetcode.cn/problems/numbers-with-repeated-digits/
public class Code04_NumbersWithRepeatedDigits {
public static int numDupDigitsAtMostN(int n) {
if (n <= 10) {
return 0;
}
// n = 23645
// len = 5长度
// n = 723645
// offset = 100000
int len = 1;
int offset = 1;
int tmp = n / 10;
while (tmp > 0) {
len++;
offset *= 10;
tmp /= 10;
}
// n = 23645 5长度
// 1长度的有几个、2长度的有几个、3长度的有几个、4长度的有几个
// 直接公式决定
int noRepeat = 0;
for (int i = 1; i < len; i++) {
noRepeat += numAllLength(i);
}
// num = 723645
// 单独求6长度的数字不重复的有几个
if (len <= 10) {
// int a = 0b 11
int status = 0b1111111111;
// n = 732645
// offset 100000
// n / offset = 7
// 1 2 3 ... 6 7-1
// ====
// n = 732645
// offset 100000
// 10000
noRepeat += ((n / offset) - 1) * numberRest(offset / 10, status ^ 1);
// n = 732645
// offset 100000
// 7.....
noRepeat += process(offset / 10, status ^ (1 << (n / offset)), n);
}
return n + 1 - noRepeat;
}
// 10进制长度必须为len的所有数中
// 每一位数字都不重复的数有多少
// 10
// 9 * 9
// 9 * 9 * 8
// 9 * 9 * 8 * 7
public static int numAllLength(int len) {
if (len > 10) {
return 0;
}
if (len == 1) {
return 10;
}
int ans = 9;
int cur = 9;
while (--len > 0) {
ans *= cur;
cur--;
}
return ans;
}
// n = 732645
// 10000
// status : 还剩哪些数字可以选
// 返回值 : 前面的数字都和n一样剩下的位里有多少数字剩下的数字都不同
public static int process(int offset, int status, int n) {
if (offset == 0) {
// n = 732645
// 0
return 1;
}
int ans = 0;
// n = 732645
// off 100
// 732....
// 7320...
// 7321...
// 7322... X
// 7323... X
// 7324...
// 7325...
//
// n = 732645
// off 100
// 6
// 7326 % 10 = 6
int first = (n / offset) % 10;
for (int cur = 0; cur < first; cur++) {
if ((status & (1 << cur)) != 0) {
ans += numberRest(offset / 10, status ^ (1 << cur));
}
}
// n = 732645
// off 10
// 7326 ..
if ((status & (1 << first)) != 0) {
ans += process(offset / 10, status ^ (1 << first), n);
}
return ans;
}
// offset : 1000, 还剩4长度
// offset : 100000, 还剩7长度
// status : 还有哪些数字可以选
// 状态!
// 9 8 7 6 5 4 3 2 1 0
// 0 1 1 1 0 0 0 1 1 1
public static int numberRest(int offset, int status) {
// c 还有几种数字可以选!
// offset = 1000; 100 10 1 0
// c = 7 6 5 4 3
// ans = 1 * 7 * 6 * 5 * 4
int c = hammingWeight(status);
int ans = 1;
while (offset > 0) {
ans *= c;
c--;
offset /= 10;
}
return ans;
}
public static int hammingWeight(int n) {
n = (n & 0x55555555) + ((n >>> 1) & 0x55555555);
n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);
n = (n & 0x00ff00ff) + ((n >>> 8) & 0x00ff00ff);
n = (n & 0x0000ffff) + ((n >>> 16) & 0x0000ffff);
return n;
}
}