|
|
|
|
package class24;
|
|
|
|
|
|
|
|
|
|
// 里程表不能含有4,给定一个数num,返回他是里程表里的第几个
|
|
|
|
|
public class Code03_NotContains4 {
|
|
|
|
|
|
|
|
|
|
// num中一定没有4这个数字
|
|
|
|
|
public static long notContains4Nums1(long num) {
|
|
|
|
|
long count = 0;
|
|
|
|
|
for (long i = 1; i <= num; i++) {
|
|
|
|
|
if (isNot4(i)) {
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean isNot4(long num) {
|
|
|
|
|
while (num != 0) {
|
|
|
|
|
if (num % 10 == 4) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
num /= 10;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// arr[1] : 比1位数还少1位,有几个数(数字里可以包含0但是不可以包含4)?0个
|
|
|
|
|
// arr[2] : 比2位数还少1位,有几个数(数字里可以包含0但是不可以包含4)?9个
|
|
|
|
|
// 1 -> 0 1 2 3 - 5 6 7 8 9 = 9
|
|
|
|
|
// arr[3] :比3位数还少1位,有几个数(数字里可以包含0但是不可以包含4)?81个
|
|
|
|
|
// 1 : 0 (0 1 2 3 - 5 6 7 8 9) = 9
|
|
|
|
|
// 2 :
|
|
|
|
|
// 1 (0 1 2 3 - 5 6 7 8 9) = 9
|
|
|
|
|
// 2 (0 1 2 3 - 5 6 7 8 9) = 9
|
|
|
|
|
// 3 (0 1 2 3 - 5 6 7 8 9) = 9
|
|
|
|
|
// 5 (0 1 2 3 - 5 6 7 8 9) = 9
|
|
|
|
|
// ...
|
|
|
|
|
// 9 (0 1 2 3 - 5 6 7 8 9) = 9
|
|
|
|
|
public static long[] arr = { 0L, 1L, 9L, 81L, 729L, 6561L, 59049L, 531441L, 4782969L, 43046721L, 387420489L,
|
|
|
|
|
3486784401L, 31381059609L, 282429536481L, 2541865828329L, 22876792454961L, 205891132094649L,
|
|
|
|
|
1853020188851841L, 16677181699666569L, 150094635296999121L, 1350851717672992089L };
|
|
|
|
|
|
|
|
|
|
// num中一定没有4这个数字
|
|
|
|
|
public static long notContains4Nums2(long num) {
|
|
|
|
|
if (num <= 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
// num的十进制位数,len
|
|
|
|
|
int len = decimalLength(num);
|
|
|
|
|
// 35621
|
|
|
|
|
// 10000
|
|
|
|
|
long offset = offset(len);
|
|
|
|
|
|
|
|
|
|
// 第一位数字
|
|
|
|
|
long first = num / offset;
|
|
|
|
|
return arr[len] - 1 + (first - (first < 4 ? 1 : 2)) * arr[len] + process(num % offset, offset / 10, len - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// num之前,有开头!
|
|
|
|
|
// 在算0的情况下,num是第几个数字
|
|
|
|
|
// num 76217
|
|
|
|
|
// 10000
|
|
|
|
|
// 6217
|
|
|
|
|
// 1000
|
|
|
|
|
// len
|
|
|
|
|
public static long process(long num, long offset, int len) {
|
|
|
|
|
if (len == 0) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
long first = num / offset;
|
|
|
|
|
return (first < 4 ? first : (first - 1)) * arr[len] + process(num % offset, offset / 10, len - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// num的十进制位数
|
|
|
|
|
// num = 7653210
|
|
|
|
|
// 7
|
|
|
|
|
public static int decimalLength(long num) {
|
|
|
|
|
int len = 0;
|
|
|
|
|
while (num != 0) {
|
|
|
|
|
len++;
|
|
|
|
|
num /= 10;
|
|
|
|
|
}
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// len = 6
|
|
|
|
|
// 100000
|
|
|
|
|
// len = 4
|
|
|
|
|
// 1000
|
|
|
|
|
// 3452168
|
|
|
|
|
// 1000000
|
|
|
|
|
// 3
|
|
|
|
|
public static long offset(int len) {
|
|
|
|
|
long offset = 1;
|
|
|
|
|
for (int i = 1; i < len; i++) {
|
|
|
|
|
offset *= 10L;
|
|
|
|
|
}
|
|
|
|
|
return offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 讲完之后想到了课上同学的留言
|
|
|
|
|
// 突然意识到,这道题的本质是一个9进制的数转成10进制的数
|
|
|
|
|
// 不过好在课上的解法有实际意义,就是这种求解的方式,很多题目都这么弄
|
|
|
|
|
// 还有课上的时间复杂度和"9进制的数转成10进制的数"的做法,时间复杂度都是O(lg N)
|
|
|
|
|
// 不过"9进制的数转成10进制的数"毫无疑问是最优解
|
|
|
|
|
public static long notContains4Nums3(long num) {
|
|
|
|
|
if (num <= 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
long ans = 0;
|
|
|
|
|
for (long base = 1, cur = 0; num != 0; num /= 10, base *= 9) {
|
|
|
|
|
cur = num % 10;
|
|
|
|
|
ans += (cur < 4 ? cur : cur - 1) * base;
|
|
|
|
|
}
|
|
|
|
|
return ans;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
long max = 88888888L;
|
|
|
|
|
System.out.println("功能测试开始,验证 0 ~ " + max + " 以内所有的结果");
|
|
|
|
|
for (long i = 0; i <= max; i++) {
|
|
|
|
|
// 测试的时候,输入的数字i里不能含有4,这是题目的规定!
|
|
|
|
|
if (isNot4(i) && notContains4Nums2(i) != notContains4Nums3(i)) {
|
|
|
|
|
System.out.println("Oops!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
System.out.println("如果没有打印Oops说明验证通过");
|
|
|
|
|
|
|
|
|
|
long num = 8173528638135L;
|
|
|
|
|
long start;
|
|
|
|
|
long end;
|
|
|
|
|
System.out.println("性能测试开始,计算 num = " + num + " 的答案");
|
|
|
|
|
start = System.currentTimeMillis();
|
|
|
|
|
long ans2 = notContains4Nums2(num);
|
|
|
|
|
end = System.currentTimeMillis();
|
|
|
|
|
System.out.println("方法二答案 : " + ans2 + ", 运行时间 : " + (end - start) + " ms");
|
|
|
|
|
|
|
|
|
|
start = System.currentTimeMillis();
|
|
|
|
|
long ans3 = notContains4Nums3(num);
|
|
|
|
|
end = System.currentTimeMillis();
|
|
|
|
|
System.out.println("方法三答案 : " + ans3 + ", 运行时间 : " + (end - start) + " ms");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|