时分秒重合问题

时分秒重合问题

今天晚上和同事吃饭时聊起了以前初中接触过的话题:24 小时内时针、分针和秒针重合几次。

吃完饭之后回来捋了下思路:

  • 假设时针的角速度为 ω(ω = 1 / 120 (度/秒)),那么分针的角速度就为 12ω,秒针的角速度为 720ω
  • 假设时针和分针在 t 秒后重合,那么分针在 t 时间内走过的角度减去时针在 t 时间内走过的角度,得到的结果肯定是 360 的整数倍
  • 根据上面的规则,可以算出时针和分针重合的时间 – 集合 A
  • 同理也能算出分针和秒针重合的时间 – 集合 B
  • 那么时针、分针及秒针三者重合的时间就是集合 A、B 的交集

具体实现代码如下:

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
/**
* 时间补 0
*
* @param time
*/
const padTime = (time: number) => {
return time < 10 ? `0${time}` : `${time}`;
};

/**
* 将秒转换为 HH:mm:ss 格式
*
* @param seconds
*/
const convert = (seconds: number) => {
const hour: number = Number.parseInt(`${seconds / (60 * 60)}`),
minute: number = Number.parseInt(`${(seconds - hour * 60 * 60 ) / 60}`),
second: number = Math.round(seconds - hour * 60 * 60 - minute * 60);

return `${padTime(hour)}:${padTime(minute)}:${padTime(second)}`;
}

/**
* 计算重叠时间
*
* @param speedA
* @param speedB
*/
const overlap = (speedA: number, speedB: number) => {
const seconds: number = 24 * 60 * 60,
speed1Circles: number = seconds * speedA / 360; // A 速度一天走的圈数

let times: string[] = [];

for (let i = 0; i < speed1Circles - 1; i++) {
/**
* speedA 在 t 时间内走过的角度 - speedB 在 t 时间内走过的角度 = 360 的整数倍
*
* speedA * t - speedB * t = k * 360
* t = (k * 360) / (speedA - speedB)
*
*/

const time = (i * 360) / Math.abs(speedA - speedB); // 重合的时间

if (time < (3600 * 24)) {
times.push(convert(time));
}
}

return times;
}
1
2
3
4
5
6
7
8
9
10
11
12
// 时分秒角速度(度/秒)
const hSpeed: number = 1 / 120,
mSpeed: number = 0.1,
sSpeed: number = 6;

const timesA: string[] = overlap(mSpeed, hSpeed), // 时针和分针重合时间
timesB: string[] = overlap(sSpeed, mSpeed), // 分针和秒针重合时间
result: string[] = timesA.filter(num => timesB.includes(num)); // 二者取交集

console.log(timesA.length); // 22
console.log(timesB.length); // 1416
console.log(result); // [ '00:00:00', '12:00:00' ]

根据运算结果可知,时针、分针、秒针三者在 24 小时内重合了 2 次,重合时间分别是在 0 点以及 12 点。