靠谱的车- 华为OD统一考试(C卷)

OD统一考试(C卷)

分值: 100分

题解: Java / Python / C++

alt

题目描述

程序员小明打了一辆出租车去上班。出于职业敏感,他注意到这辆出租车的计费表有点问题,总是偏大。

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

比如:

  • 23再多一块钱就变为25;

  • 39再多一块钱变为50;

  • 399再多一块钱变为500;

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

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

输入描述

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

(1<=N<=888888888)。

输出描述

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

示例1

输入
5
输出
4
说明
5表示计费表的表面读数。
4表示实际产生的费用其实只有4块钱。

示例2

输入
17
输出
15
说明
17表示计费表的表面读数。
15表示实际产生的费用其实只有15块钱。

示例3

输入
100
输出
81
说明
100表示计费表的表面读数。
81表示实际产生的费用其实只有81块钱。

题解

此题采用记忆化搜索(实在不会可以暴力枚举所有的数字,然后去除掉数字中含有4的数字,即为答案,由于题目数据范围较大,暴力肯定会超时)。

代码大致描述:

  1. 通过递归函数 solve 处理计费表的每一位数字,考虑是否跳过数字4,是否有限制,是否是数字。
  2. 使用记忆化缓存 cache 避免重复计算,提高效率。
  3. 遍历计费表的每一位,根据不同情况调用递归函数。
  4. 返回计算结果。

Java

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String s = in.nextLine();
        Solution solution = new Solution();
        System.out.println(solution.solve(s.toCharArray(), 0, true, false));
    }
}


class Solution {
    int[] cache;

    public Solution() {
        this.cache = new int[15];
        Arrays.fill(this.cache, -1);
    }

    /**
     * 
     * @param w 原始字符数组
     * @param idx   构造索引位置
     * @param isLimit   构造时是否有限制
     * @param isNum 是否是数字
     * @return
     */
    public int solve(char[] w, int idx, boolean isLimit, boolean isNum) {
        if (idx == w.length) return isNum ? 1 : 0;

        // 返回记忆化缓存结果
        if (!isLimit && isNum && this.cache[idx] != -1) return this.cache[idx];

        int cnt = 0;
        // 高位不选择元素时,比如 1235(4位数) 只构造 3位的数字的结果数
        if (!isNum) cnt += solve(w, idx + 1, false, false);

        // w[idx] 的上限
        int up = isLimit ? (w[idx] - '0') : 9;
        // 当前 idx 位置枚举所有可能的值
        for (int d = isNum ? 0 : 1; d <= up; d++) {
            if (d != 4) cnt += solve(w, idx + 1, isLimit && d == up, true);
        }

        if (!isLimit && isNum) {
            this.cache[idx] = cnt;
        }

        return cnt;
    }
}

C++

#include <bits/stdc++.h>
using namespace std;

const int N=15;
int f[N],n;
string s;

int solve(int i,bool is_limit,bool is_num) {
    if(i==n)  return is_num;
    if (!is_limit && is_num && f[i] != -1)  return f[i];

    int res=0;
    if(!is_num) res=dp(i+1,false,false);
    
    int up=(is_limit)?s[i]-'0':9;
    for(int d=1-is_num; d<=up; d++) {
        if(4!=d) res+=dp(i+1,is_limit&&d==up,true);
    }
    if(!is_limit&&is_num) {
        f[i]=res;
    }
    return res;
}

int main() {
    cin>>s;
    n=s.size();
    memset(f,-1,sizeof(f));
    cout<<solve(0,true,false)<<endl;

    return 0;
}

Python

from functools import cache

@cache
def solve(i, is_limit, is_num):
    global s, n
    if i == n:
        return int(is_num)
    
    res = 0
    if not is_num:
        res = solve(i + 1, False, False)

    up = int(s[i]) if is_limit else 9
    for d in range(1 - int(is_num), up + 1):
        if d != 4:
            res += solve(i + 1, is_limit and d == up, True)

    return res


if __name__ == "__main__":
    s = input()
    n = len(s)
    print(solve(0, True, False))

(记忆化搜索)相关练习题

alt

🙏整理题解不易, 如果有帮助到您,请给点个赞 ‍❤️‍ 和收藏 ⭐,让更多的人看到。🙏🙏🙏

#校招##秋招##华为##面经##java#
全部评论
有这么个思路看上去似乎能用,各位看看有没有问题: 逢4在对应位多加1,只要发生进位,那么从进制来看是9进制,只不过遇到4提前加1然后超过9进位,而不是自然统计到9后进位,那么大体上是比较接近把9进制转成10进制的结果的,不过毕竟因为进制转换的方式和真正的9进制有点差异,把输入所有位都和4对比,大于4的都减一就得到了按照9进制处理的实际花费,再按照9进制转换下即可: s = input() # string output_string = '' for i in s: num = int(i) if num > 4: output_string += str(num - 1) else: output_string += str(num) print(int(output_string, 9))
2 回复 分享
发布于 2024-02-04 11:44 陕西
c语言 #include <stdio.h> #include <string.h> int main() { char buf[8]; int num = 0; scanf("%d", &num); int skip = 0; for (size_t i = 0; i < num; i++) { sprintf(buf, "%d", i); char* r = strchr(buf, '4'); if(NULL == r) continue; else skip++; } // printf("skip=%d\r\n", skip); printf("%d\r\n", num-skip); }</string.h></stdio.h>
点赞 回复 分享
发布于 2024-03-31 09:55 陕西
哥们 od c卷都是这个题目吗
点赞 回复 分享
发布于 2024-03-07 10:44 上海
点赞 回复 分享
发布于 2023-12-26 12:16 湖北
有更好的解法,欢迎评论区留下, 大家有笔试真题欢迎投稿,祝大家
点赞 回复 分享
发布于 2023-12-26 11:49 湖北

相关推荐

头像
01-22 10:36
已编辑
牛客运营
活动规则:你可以使用任何AI工具,生成牛客娘表情包,发送你的生成提示词+图片至本贴评论区,并将无水印原图发送至微信群。活动奖励:1、每张&nbsp;可爱的牛客娘表情包,可获得&nbsp;10牛币奖励(每人上限100张)&nbsp;~2、点赞量最高的前xx个评论,送牛客娘马克杯,(每25个评论,赠送一个马克杯,最多赠送20个)牛客娘表情包交流群:生成示例:&nbsp;这是牛客娘的形象,帮我用牛客娘的形象画一些ACM算法竞赛相关的表情包&nbsp;需要的表情包有:&nbsp;摸头&nbsp;(安慰)&nbsp;呵呵(冷笑的呵呵)&nbsp;牛魔&nbsp;牛啤(左手比大拇指,右手拿着啤酒)&nbsp;这次一定&nbsp;比心&nbsp;不许TD&nbsp;要给他迎头痛击&nbsp;设计要求:&nbsp;1.统一使用萌系风格。&nbsp;2.表情生动和肢体动作丰富、...
Xuan2333:没错没错就是我,牛客娘表情包的创作者,大家都可以自用哒awa (第5张“按住牛客娘开始思索”出自我的世界里的机械动力模组,我做这个表情包可是花了我1个多小时的时间啊qwq) 最后附上所有用过的素材图,希望大家喜欢awa wow 将图片中的人物改成两手托腮,只显示头部照片,眼睛为星星眼,表情开心,并在下方附上文字“wow” Ciallo 将第二张图的人物做出第一张图的姿势并且要在身体各处还有五官和动作完全一致,不要改背景,高分辨率,最佳质量,并在下方加上和图片相符的文字“Ciallo!” 说不出话 生成这个任务面无表情,一脸犹豫,嘴角下垂,双手交叉在胸前,在中间加上一个带有一条斜杠的麦克风的表示闭麦的符号,并且在下面配上文字“说不出话” 按住牛客娘开始思索 将第二张图的人物进行修改,要求是有一只手按在人物的头上,人物的眼神灵动,手略有着急的轻微摆起,头部微微抬起,并将第一张图放在第二张图的下方,高品质,把这张图的下方的黑色部分加上文字“按住牛客娘开始思索”,字体与图片里展示的“牛客娘”这三个字的字体相一致 我也要WA吗 将第一张图的人物的头发,脸部和衣服改成第二张图的人物的,眼睛保持不变,脸上的汗保持不变,头发的长度修改为和图片的一致,脸上不要有红晕,眼睛里不要有高光,眼睛里只要纯灰色查看图片
点赞 评论 收藏
分享
评论
7
10
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务