解密犯罪时间 - 华为OD统一考试(C卷)

OD统一考试(C卷)

分值: 100分

题解: Java / Python / C++

alt

题目描述

警察在侦破一个案件时,得到了线人给出的可能犯罪时间,形如 HH:MM 表示的时刻。

根据警察和线人的约定,为了隐蔽,该事件是修改过的,解密规则为:

利用当前出现过的数字,构造下一个距离当前事件最近的时刻,则该时间为可能的犯罪的时间。每个数字都可以被无限次使用。

输入描述

形如 HH:SS 字符串,表示原始输入。

输出描述

HH:SS 字符串,表示推理处理的犯罪时间。

备注:

  1. 可以保证现任给定的字符串一定是合法的,例如,"01:3501:35" 和 "11:0811:08" 是合法的,"1:351:35"和"11:811:8" 是不合法的。
  2. 最近的时刻可能在第二天。

示例1

输入:
20:12

输出:
20:20

示例2

输入:
23:59

输出:
22:22

题解

这个问题可以分为以下几个步骤来解决:

  1. 记录已经出现的数字: 遍历输入的时间字符串,记录出现过的数字。这里可以使用一个长度为10的布尔数组exists,用于标记数字0到9是否出现过。
  2. 计算原始时间: 将输入的时间字符串转换为分钟表示,方便后续的计算。
  3. 枚举所有时间: 使用两层循环枚举所有可能的小时和分钟,然后计算对应的分钟数,得到当前时间点。
  4. 判断当前时间点是否符合条件: 判断当前小时和分钟的每一位数字是否都在已经出现过的数字中。如果有任何一个数字未出现,说明这个时间点不符合条件,直接跳过。
  5. 计算时间间隔: 计算当前时间点与原始时间的时间间隔,考虑了第二天的情况。
  6. 找到最近的时刻: 通过比较时间间隔找到最近的时刻,更新最近时刻的小时、分钟和时间间隔。
  7. 格式化输出结果: 最终输出找到的最近时刻。

Java

import java.util.Scanner;
/**
 * @author code5bug
 */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String stime = scanner.next();
        int pos = stime.indexOf(":");

        // 记录已经出现的数字
        boolean[] exists = new boolean[10];
        for (char c : stime.toCharArray()) {
            if (Character.isDigit(c)) {
                exists[c - '0'] = true;
            }
        }

        // 小时,分钟,最近的时间间隔(分钟)
        int hour = 0, minute = 0, d = Integer.MAX_VALUE;

        // 原始时间
        int times = Integer.parseInt(stime.substring(0, pos)) * 60 + Integer.parseInt(stime.substring(pos + 1));

        // 枚举所有时间,找到下一个距离当前事件最近的时刻
        // - 如果时间点中有字符未出现,则不考虑该时间点,因为该时间点已经不可能是答案了
        // - 如果时间点中有字符出现:
        //          - 如果时间相同,则不考虑该时间点,因为该时间点已经不可能是答案了
        //          - 如果时间不同,则考虑该时间点,因为该时间点可能是答案了,但是要判断当天还是下一天
        for (int h = 0; h < 24; h++) {
            if (!exists[h % 10] || !exists[h / 10]) continue;

            for (int m = 0; m < 60; m++) {
                int curTimes = h * 60 + m;
                // 字符未出现或时间相同
                if (!exists[m % 10] || !exists[m / 10] || curTimes == times) continue;

                // 计算时间间隔
                int curD = (curTimes > times) ? curTimes - times : 24 * 60 - (times - curTimes);
                if (curD < d) {   // 找到更近的时刻
                    hour = h;
                    minute = m;
                    d = curD;
                }
            }
        }

        System.out.printf("%02d:%02d%n", hour, minute);
    }
}

Python

def find_nearest_time(stime):
    # 初始化存在性数组
    exists = [False] * 10

    # 找到时间中的冒号位置
    pos = stime.find(":")
    
    # 遍历时间字符串,标记存在的数字
    for c in stime:
        if c.isdigit():
            exists[int(c)] = True

    # 初始化小时、分钟和最小时间间隔
    hour, minute, d = 0, 0, float('inf')

    # 计算原始时间
    times = int(stime[:pos]) * 60 + int(stime[pos + 1:])

    # 枚举所有时间,找到下一个距离当前事件最近的时刻
    for h in range(24):
        if not exists[h % 10] or not exists[h // 10]:
            continue

        for m in range(60):
            cur_times = h * 60 + m

            # 如果分钟或小时的某一位不存在,或者时间相同,则跳过
            if not exists[m % 10] or not exists[m // 10] or cur_times == times:
                continue

            # 计算时间间隔
            cur_d = cur_times - times if cur_times > times else 24 * 60 - (times - cur_times)
            
            # 找到更近的时刻
            if cur_d < d:
                hour, minute, d = h, m, cur_d

    # 格式化输出结果
    result = "{:02d}:{:02d}".format(hour, minute)
    print(result)

# 从标准输入读取时间字符串
stime = input().strip()

# 调用函数找到最近的时间
find_nearest_time(stime)

C++

#include <bits/stdc++.h>

using namespace std;

int main() {
    string stime;
    cin >> stime;
    int pos = stime.find(":");

    bool exists[10];

    for (char c : stime) {
        if (isdigit(c)) exists[c - '0'] = true;
    }

    // 小时,分钟,最近的时间间隔(分钟)
    int hour = 0, minute = 0, d = INT_MAX;

    // 原始时间
    int times = stoi(stime.substr(0, pos)) * 60 + stoi(stime.substr(pos + 1));

    // 枚举所有时间,找到下一个距离当前事件最近的时刻
    // - 如果时间点中有字符未出现,则不考虑该时间点,因为该时间点已经不可能是答案了
    // - 如果时间点中有字符出现:
    //          - 如果时间相同,则不考虑该时间点,因为该时间点已经不可能是答案了
    //          - 如果时间不同,则考虑该时间点,因为该时间点可能是答案了,但是要判断当天还是下一天
    for (int h = 0; h < 24; h++) {
        if (!exists[h % 10] || !exists[h / 10]) continue;

        for (int m = 0; m < 60; m++) {
            int cur_times = h * 60 + m;
            // 字符未出现或时间相同
            if (!exists[m % 10] || !exists[m / 10] || cur_times == times) continue;

            // 计算时间间隔
            int cur_d = (cur_times > times) ? cur_times - times : 24 * 60 - (times + cur_times);
            if (cur_d < d) {   // 找到更近的时刻
                hour   = h;
                minute = m;
                d      = cur_d;
            }
        }
    }

    cout << (hour < 10 ? "0" : "") << hour << ":" << (minute < 10 ? "0" : "") << minute << endl;

    return 0;
}    

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

#面经##春招##秋招##校招##华为#
全部评论
回溯算法暴力枚举输入时间所有的组合并剔除非法时间,排序,组合中查找当前时间的下一个时间,如果当前时间是最后一位取第一位
1 回复 分享
发布于 2024-09-26 00:46 上海
直接贪心算法,从给出的时间最后一位开始,看已有数字中是否有比当前位数字大的且合法的,如果有,用比它大的最小数字替换,后面的位用最小的数字补齐,如果没有则看前一位,同样的替换逻辑
1 回复 分享
发布于 2024-04-26 10:33 浙江

相关推荐

大方的大熊猫准备进厂:1.教育背景:你希望从事什么专业的工作你的主修课就是什么;成绩优秀是你应该做的,没什么可描述的,成绩不优秀也许人家在大学忙着创业呢?(成绩优秀不一定是好事,只能说明多元化的大学你上成了高中,没有真正上明白大学,反而体现了你死板,不爱社交,没有别的突出能力) 2.实践经历:你想表达的意思没有说清楚。你是说你会个性化服务,还是你有实习经历。如果没有带来,经济收益,表彰,更好的发展前景,那你还不如说说提升了自己哪些技能。你说有人给你送锦旗我都能明白你优秀,但是你说你会xxxx,你说这话谁信,证据呢。 3.入伍经历:你描述的就是你的工作职责或者你应该做的,并没有体现出来你把这个事情做好了,而且入伍经历并不能证明你能干好你要应聘的工作,不如只写经历其余所有内容都不写。 4.荣誉技能:重点突出一下,但不要过多描述,这些荣誉的含金量懂得都懂。 重点:你要应聘什么工作(具体岗位,实习生不具体),你的期望薪资
点赞 评论 收藏
分享
05-19 19:57
蚌埠学院 Python
2237:Gpa70不算高,建议只写排名,个人技能不在多而在精,缩到8条以内。项目留一个含金量高的,减少间距弄到一页,硕士简历也就一页,本科不要写很多
点赞 评论 收藏
分享
评论
3
1
分享

创作者周榜

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