华为机试 - 解密犯罪时间

目录

题目描述

输入描述

输出描述

用例

题目解析

算法源码


题目描述

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

根据警察和线人的约定,为了隐蔽,该时间是修改过的,

解密规则为:利用当前出现过的数字,构造下一个距离当前时间最近的时刻,则该时间为可能的犯罪时间。

每个出现数字都可以被无限次使用。

输入描述

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

输出描述

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

备注

1.可以保证现任给定的字符串一定是合法的。

例如,“01:35”和“11:08”是合法的,“1:35”和“11:8”是不合法的。

2.最近的时刻可能在第二天。

用例

输入 输出
20:12 20:20
23:59 22:22
12:58 15:11
18:52 18:55
23:52 23:53
09:17 09:19
07:08 08:00

题目解析

解密规则为:利用当前出现过的数字,构造下一个距离当前时间最近的时刻,则该时间为可能的犯罪时间。

本题重在理解“下一个”最近时间,这里是“下一个”,而不是“上一个”,因此要求的时间在当前时间之后。但是备注中又说:“最近的时刻可能在第二天。”

也就是说,要求的时间  并不是严格 比当前时间 小的。

这题其实用dfs求全排列的话,就很简单。

我们基于dfs求得输入“20:12”的全部排列,

即由0,1,2构成的四层排列,题目说“每个出现数字都可以被无限次使用”,因此每层多可以使用相同的数字。

当然,求得的全排列中必然含有不合法的时间,我们需要利用正则来过滤掉非法的时间,正则如下

const regExp = /(([01][0-9])|([2][0-3]))[0-5][0-9]/;

剩余的全排列如下

[
  '2222', '2220', '2221', '2202', '2200', '2201',
  '2212', '2210', '2211', '2022', '2020', '2021',
  '2002', '2000', '2001', '2012', '2010', '2011',
  '2122', '2120', '2121', '2102', '2100', '2101',
  '2112', '2110', '2111', '0222', '0220', '0221',
  '0202', '0200', '0201', '0212', '0210', '0211',
  '0022', '0020', '0021', '0002', '0000', '0001',
  '0012', '0010', '0011', '0122', '0120', '0121',
  '0102', '0100', '0101', '0112', '0110', '0111',
  '1222', '1220', '1221', '1202', '1200', '1201',
  '1212', '1210', '1211', '1022', '1020', '1021',
  '1002', '1000', '1001', '1012', '1010', '1011',
  '1122', '1120', '1121', '1102', '1100', '1101',
  '1112', '1110', '1111'
]

我们将其按字典序升序

[
  '0000', '0001', '0002', '0010', '0011', '0012',
  '0020', '0021', '0022', '0100', '0101', '0102',
  '0110', '0111', '0112', '0120', '0121', '0122',
  '0200', '0201', '0202', '0210', '0211', '0212',
  '0220', '0221', '0222', '1000', '1001', '1002',
  '1010', '1011', '1012', '1020', '1021', '1022',
  '1100', '1101', '1102', '1110', '1111', '1112',
  '1120', '1121', '1122', '1200', '1201', '1202',
  '1210', '1211', '1212', '1220', '1221', '1222',
  '2000', '2001', '2002', '2010', '2011', '2012',
  '2020', '2021', '2022', '2100', '2101', '2102',
  '2110', '2111', '2112', '2120', '2121', '2122',
  '2200', '2201', '2202', '2210', '2211', '2212',
  '2220', '2221', '2222'
]

找到输入的20:12对应2012之后的一个时间2020,就是所求的,我们只要给2020中间加一个":",就是题解。

另外如果输入的时间对应的时间字符串刚好是排序后全排列最后一个,则此时我们需要取第二天的第一个时间,即排序后全排列第一个。

算法源码

/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

rl.on("line", (line) => {
  const [hour, minute] = line.split(":");
  const arr = [...new Set([...hour, ...minute])];

  const res = [];
  dfs(arr, [], res);
  res.sort();

  let index = res.indexOf(`${hour}${minute}`);

  let recentTime;
  if (index === res.length - 1) {
    recentTime = [...res[0]];
  } else {
    recentTime = [...res[index + 1]];
  }

  recentTime.splice(2, 0, ":");
  console.log(recentTime.join(""));
});

function dfs(arr, path, res) {
  if (path.length === 4) {
    const timeStr = path.join("");
    const regExp = /(([01][0-9])|([2][0-3]))[0-5][0-9]/;
    if (regExp.test(timeStr)) res.push(timeStr);
    return;
  }

  for (let i = 0; i < arr.length; i++) {
    path.push(arr[i]);
    dfs(arr, path, res);
    path.pop();
  }
}

你可能感兴趣的:(华为机试,算法,JavaScript,华为机试)