一、题目

程序员小明打了一辆出租车去上班。

出于职业敏感,他注意到这辆出租车的计费表有点问题,总是偏大。

出租车司机解释说他不喜欢数字4,所以改装了计费表,任何数字位置遇到数字4就直接跳过,其余功能都正常。

比如:
23再多一块钱就变为25;

39再多一块钱变为50;

399再多一块钱变为500;

小明识破了司机的伎俩,准备利用自己的学识打败司机的阴谋。

给出计费表的表面读数,返回实际产生的费用。

二、输入

1
2
3
只有一行,数字N,表示里程表的读数。

(1<=N<=888888888)。

三、输出

1
一个数字,表示实际产生的费用。以回车结束。

四、示例

1
2
3
4
5
输入:
5

输出:
4

五、题解

  1. 理解题意。不是仅针对输入的数字,而是从 1 跳到输入数字整个过程中 4 的变化
  2. 暴力算比较好理解,从 1 跳到目标数过程中,数字中包括 4 就计数一次,表示跳过
  3. 10 进制转 9 进制的思想不太好理解,进制转换不难

5.1 Java 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package org.stone.study.algo.ex202411;

import java.util.Scanner;

/**
* 程序员小明打了一辆出租车去上班。
* 出于职业敏感,他注意到这辆出租车的计费表有点问题,总是偏大。
* 出租车司机解释说他不喜欢数字4,所以改装了计费表,任何数字位置遇到数字4就直接跳过,其余功能都正常。
* 比如:
* 23再多一块钱就变为25;
* 39再多一块钱变为50;
* 399再多一块钱变为500;
* 小明识破了司机的伎俩,准备利用自己的学识打败司机的阴谋。
* 给出计费表的表面读数,返回实际产生的费用。
*
* 示例输入/输出:
* 5
* 4
*
* 17
* 15
*
* 100
* 81
*/
public class TaxiFee {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = getActualFee2(n);
System.out.println(m);
}

/**
* 计算实际产生的费用
* @param n 计费表的表面读数
* @return 实际产生的费用
*/
private static int getActualFee1(int n) {
int cnt = 0;
for(int i = 1; i <= n; i++) {
if(String.valueOf(i).contains("4")) {
cnt++;
}
}

return n - cnt;
}

/**
* 利用进制转换的思想,不是很好理解。10进制跳过数字 4 相当于 9 进制
* @param n 计费表的表面读数
* @return 实际产生的费用
*/
private static int getActualFee2(int n) {
int ans = 0;

int multiplier = 1;
while(n > 0) {
int m = n % 10;
n /= 10;

if (m > 4) {
m -= 1;
}
ans += m * multiplier;
multiplier *= 9;
}

return ans;
}
}

5.2 Python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 跳过数字 4 后的数字为 n,返回原始数字
# 10进制转9 进制
def getActualFee(n):
res = 0
multiplier = 1
while n > 0:
digit = n % 10
n //= 10

if digit > 4:
digit -= 1

res += digit * multiplier
multiplier *= 9

return res


if __name__ == '__main__':
n = int(input())

m = getActualFee(n)
print(m)