大厂算法:解密犯罪时间

155 阅读3分钟

一、题目

警察在侦破一个案件时,得到了线人给出的可能犯罪时间,形如 “HH:MM” 表示的时刻。根据警察和线人的约定,为了隐蔽,该时间是修改过的,解密规则为:利用当前出现过的数字,构造下一个距离当前时间最近的时刻,则该时间为可能的犯罪时间。每个出现数字都可以被无限次使用。

备注:

可以保证线人给定的字符串一定是合法的。 例如,“01:35” 和 “11:08” 是合法的,“1:35” 和 “11:8” 是不合法的。

最近的时刻有可能在第二天

二、输入

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

三、输出

形如HH:SS的字符串,表示推理出来的犯罪时间

四、示例

示例一

输入:
18:52

输出:
18:55

说明:利用数字1, 8, 5, 2构造出来的最近时刻是18:55,是3分钟之后。结果不是18:51因为这个时刻是18小时52分钟之后。

示例二

输入:
23:59

输出:
22:22

说明:利用数字2, 3, 5, 9构造出来的最近时刻是22:22。 答案一定是第二天的某一时刻,所以选择可构造的最小时刻为犯罪时间。

五、题解

  1. 本题考查的是工程实现能力,看似简单,没想清楚写出来可能就是一坨代码
  2. 本题实现使用了计算机思维的简单暴力算法,有一种暴力美感。时间复杂度就是 1440 次计算(一天的分钟数)

5.1 Java 实现

package org.stone.study.algo.ex202411;

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

/**
 * 大厂算法:解密犯罪时间
 * 下一个最近的时间
 **/
public class NextClosestTime {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String time = sc.nextLine();

        String ans = getNextClosestTime(time);
        System.out.println(ans);
    }

    public static String getNextClosestTime(String time) {
        // 提取时间中非:的字符,并将其转换为数字放到set 中
        Set<Integer> digits = new HashSet<>();
        for (int i = 0; i < time.length(); i++) {
            if (time.charAt(i)!= ':') {
                digits.add(time.charAt(i) - '0');
            }
        }
        String[] parts = time.split(":");
        int hours = Integer.parseInt(parts[0]);
        int minutes = Integer.parseInt(parts[1]);

        // 从当前时间开始,逐个尝试下一个时间是否有效。最多尝试1440次(24小时),即一天的时间。
        for (int delta = 1; delta <= 1440; delta++) {
            int nextTime = (hours * 60 + minutes + delta) % 1440;
            int newHours = nextTime / 60;
            int newMinutes = nextTime % 60;

            if(!validTime(newHours, newMinutes, digits)) {
                continue;
            }

            return String.format("%02d:%02d", newHours, newMinutes);
        }

        return "";
    }

    // 判断时间是否有效时间,数字是否在允许的数字集合中
    public static boolean validTime(int hours, int minutes, Set<Integer> digits) {
        if (hours > 23 || minutes > 59) {
            return false;
        }

        int[] time = {hours / 10, hours % 10, minutes / 10, minutes % 10};
        for (int digit : time) {
            if (!digits.contains(digit)) {
                return false;
            }
        }

        return true;
    }
}

5.2 Python实现

# 是否有效的小时和分钟
def is_valid(hour, minute):
    return 0 <= hour < 24 and 0 <= minute < 60

# 找到下一个最近的时间:数字可以重复使用,可以跨天
def next_closest_time(input_time):
    # 提取输入时间的各个数字
    digits = set(input_time.replace(':'''))
    digits = sorted(digits)

    hour, minute = map(int, input_time.split(':'))

    for delta in range(11440):
        # 计算下一个时间,最多尝试1440分钟(24小时)
        next_time = (hour * 60 + minute + delta) % (24 * 60)

        new_hour = next_time // 60
        new_minute = next_time % 60
        # 是否有效时间
        if not is_valid(new_hour, new_minute):
            continue

        new_time = f'{new_hour:02d}:{new_minute:02d}'
        # 检查新时间的每个数字是否在输入时间的数字集合中
        if all(digit in digits for digit in new_time.replace(':''')):
            return new_time
        
    return None

if __name__ == '__main__':
    input_time = input()
    print(next_closest_time(input_time))