O‘REILLY: Lightbulb End Watching —— 计算指定时间范围内多组时间差之和(秒数)

本文介绍了CheckIO上的一个编程挑战,涉及Python编程,要求计算在给定开始和结束时间范围内多组灯泡开关时间差之和。文中详细阐述了解题思路、代码实现,并分享了几种优秀解决方案。
摘要由CSDN通过智能技术生成

CheckIO是一个通过闯关游戏学习编程的网站(Python和JavaScript)。通过解题开发新“岛屿”,同时,通过做任务获得Quest Points解锁会员题目。
文章内容:题目、我自己的思路和代码以及优秀代码,如果想看大神解题可以直接跳到“优秀代码”部分。
本题链接:https://py.checkio.org/en/mission/lightbulb-end-watching/

背景

这部分是关于灯泡的一系列任务,有助于了解流程以及对流程效果的评估。 在现实生活中,除了灯泡,也需要计算其他设备的效果,或者上班的工人以及他们的工资。

题目

这一任务是这个系列里的第三个任务,想要强调灯泡亮灭过程和该过程的观察期。

在上一个任务中,引入了 开始计时时间 这一参数,在该任务中,引入 停止计算时间 参数,该参数指示何时需要结束观察。 如果时间没有超过 停止计算时间 参数,则任务将与以前的任务一样,没有观察时间的限制。

另一点不同的是元素(按钮单击)的数量可以是奇数个(以前有一个前提,即元素的数量始终是偶数)。
在这里插入图片描述
输入: 给定三个参数,第一个是必选参数,第二个和第三个是可选参数。第一个参数是时间格式组成的列表,第二个和第三个参数是时间。

输出: 秒数(整数)

举个栗子:

sum_light([
    datetime(2015, 1, 12, 10, 0, 0),
    datetime(2015, 1, 12, 10, 10, 10),
    datetime(2015, 1, 12, 11, 0, 0),
],
datetime(2015, 1, 12, 10, 10, 0),
datetime(2015, 1, 12, 11, 0, 10)) == 20

sum_light([
    datetime(2015, 1, 12, 10, 0, 0),
],
datetime(2015, 1, 12, 9, 9, 0),
datetime(2015, 1, 12, 10, 0, 0)) == 0

sum_light([
    datetime(2015, 1, 12, 10, 0, 0),
    datetime(2015, 1, 12, 10, 10, 10),
    datetime(2015, 1, 12, 11, 0, 0),
    datetime(2015, 1, 12, 11, 10, 10),
],
datetime(2015, 1, 12, 9, 0, 0),
datetime(2015, 1, 12, 10, 5, 0)) == 300

假设:

  • 列表中的时间已经按升序排序
  • 列表中元素唯一(结果应该大于0)
  • 列表中元素个数为偶数个(灯泡最后是关闭状态)
  • 最小日期为:1970-01-01;最大日期为:9999-12-31

题目框架

from datetime import datetime
from typing import List, Optional

def sum_light(els: List[datetime], start_watching: Optional[datetime] = None, end_watching: Optional[datetime] = None) -> int:
    """
        how long the light bulb has been turned on
    """
    return 0


if __name__ == '__main__':
    print("Example:")
    print(sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
        datetime(2015, 1, 12, 10, 0, 10),
    ],
    datetime(2015, 1, 12, 10, 0, 0),
    datetime(2015, 1, 12, 10, 0, 10)))
    
    assert sum_light(els=[
        datetime(2015, 1, 12, 10, 0, 0),
        datetime(2015, 1, 12, 10, 0, 10),
    ],
    start_watching=datetime(2015, 1, 12, 10, 0, 0),
    end_watching=datetime(2015, 1, 12, 10, 0, 10)) == 10
    
    assert sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
        datetime(2015, 1, 12, 10, 0, 10),
    ],
    datetime(2015, 1, 12, 10, 0, 0),
    datetime(2015, 1, 12, 10, 0, 7)) == 7
    
    assert sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
        datetime(2015, 1, 12, 10, 0, 10),
    ],
    datetime(2015, 1, 12, 10, 0, 3),
    datetime(2015, 1, 12, 10, 0, 10)) == 7
    
    assert sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
        datetime(2015, 1, 12, 10, 0, 10),
    ],
    datetime(2015, 1, 12, 10, 0, 10),
    datetime(2015, 1, 12, 10, 0, 20)) == 0
    
    assert sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
        datetime(2015, 1, 12, 10, 10, 10),
        datetime(2015, 1, 12, 11, 0, 0),
        datetime(2015, 1, 12, 11, 10, 10),
    ],
    datetime(2015, 1, 12, 10, 30, 0),
    datetime(2015, 1, 12, 11, 0, 0)) == 0
    
    assert sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
        datetime(2015, 1, 12, 10, 10, 10),
        datetime(2015, 1, 12, 11, 0, 0),
        datetime(2015, 1, 12, 11, 10, 10),
    ],
    datetime(2015, 1, 12, 10, 10, 0),
    datetime(2015, 1, 12, 11, 0, 0)) == 10
    
    assert sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
        datetime(2015, 1, 12, 10, 10, 10),
        datetime(2015, 1, 12, 11, 0, 0),
        datetime(2015, 1, 12, 11, 10, 10),
    ],
    datetime(2015, 1, 12, 10, 10, 0),
    datetime(2015, 1, 12, 11, 0, 10)) == 20
    
    assert sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
        datetime(2015, 1, 12, 10, 10, 10),
        datetime(2015, 1, 12, 11, 0, 0),
        datetime(2015, 1, 12, 11, 10, 10),
    ],
    datetime(2015, 1, 12, 9, 50, 0),
    datetime(2015, 1, 12, 10, 0, 10)) == 10
    
    assert sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
        datetime(2015, 1, 12, 10, 10, 10),
        datetime(2015, 1, 12, 11, 0, 0),
        datetime(2015, 1, 12, 11, 10, 10),
    ],
    datetime(2015, 1, 12, 9, 0, 0),
    datetime(2015, 1, 12, 10, 5, 0)) == 300
    
    assert sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
        datetime(2015, 1, 12, 10, 10, 10),
        datetime(2015, 1, 12, 11, 0, 0),
        datetime(2015, 1, 12, 11, 10, 10),
    ],
    datetime(2015, 1, 12, 11, 5, 0),
    datetime(2015, 1, 12, 12, 0, 0)) == 310
    
    assert sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
        datetime(2015, 1, 12, 10, 10, 10),
        datetime(2015, 1, 12, 11, 0, 0),
    ],
    datetime(2015, 1, 12, 11, 5, 0),
    datetime(2015, 1, 12, 11, 10, 0)) == 300
    
    assert sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
        datetime(2015, 1, 12, 10, 10, 10),
        datetime(2015, 1, 12, 11, 0, 0),
    ],
    datetime(2015, 1, 12, 10, 10, 0),
    datetime(2015, 1, 12, 11, 0, 10)) == 20
    
    assert sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
        datetime(2015, 1, 12, 10, 10, 10),
        datetime(2015, 1, 12, 11, 0, 0),
    ],
    datetime(2015, 1, 12, 9, 10, 0),
    datetime(2015, 1, 12, 10, 20, 20)) == 610
    
    assert sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
    ],
    datetime(2015, 1, 12, 9, 10, 0),
    datetime(2015, 1, 12, 10, 20, 20)) == 1220
    
    assert sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
    ],
    datetime(2015, 1, 12, 9, 9, 0),
    datetime(2015, 1, 12, 10, 0, 0)) == 0
    
    assert sum_light([
        datetime(2015, 1, 12, 10, 0, 0),
    ],
    datetime(2015, 1, 12, 9, 9, 0),
    datetime(2015, 1, 12, 10, 0, 10)) == 10
    
    print("The third mission in series is completed? Click 'Check' to earn cool rewards!")

难度: Simple

思路及代码

思路

  1. 定义存储时间差的变量 result
  2. 将假设最大时间添加到时间列表里,作为最后关闭灯泡的时间;
  3. zip 函数将相邻两个时间作为一组,分别是 startend
  4. for 循环,先计算实际计时开始时间和实际停止计时时间,再判断对于每一对 startend,实际计时时间是否在其范围内,并且要实际计时开始时间小于实际停止计时时间;
  5. 如果满足上述条件,就将时间差加到 result 里;
  6. 返回 result

代码

def sum_light(els: List[datetime], start_watching: Optional[datetime] = None, end_watching: Optional[datetime] = None) -> int:
    result = 0
    els += [datetime(9999, 12, 30, 23, 59, 59)]
    for start, end in zip(els[::2],els[1::2]):
        real_start = max(start, start_watching or start)
        real_end = min(end, end_watching or end)
        if real_start < real_end:
            result += (real_end - real_start).total_seconds()
    return result

datetime(9999, 12, 30, 23, 59, 59) 可以写成 datetime.datetime.max
datetime.datetime.min表示 datetime(0000, 01 01, 00, 00, 00)

优秀代码

No.1

import contextlib, statistics, itertools, datetime
def sum_light(els, start_watching=datetime.datetime.min,
                     end_watching=datetime.datetime.max):
    result, it = datetime.timedelta(), itertools.chain(els, [end_watching])
    with contextlib.suppress(StopIteration):
        while ...:
            start = statistics.median([start_watching, next(it), end_watching])
            end   = statistics.median([start_watching, next(it), end_watching])
            result += end - start
    return result.total_seconds()

这位大佬的答案总是很高深,还看不懂 😦

No.2

def sum_light(els: List[datetime], start_watching: Optional[datetime] = None, end_watching: Optional[datetime] = None) -> int:
    els.append(end_watching)
    return sum(
        (
            min(end_watching or end, max(start_watching or end, end))
            - min(end_watching or end, max(start_watching or start, start))
        ).total_seconds()
        for start, end in zip(els[::2], els[1::2])
    )

No.3

def sum_light(els: List[datetime], start_watching: Optional[datetime] = None, end_watching: Optional[datetime] = None) -> int:
    if len(els) % 2:
        els.append(datetime.max)
    sw = start_watching or els[0]
    ew = end_watching or datetime.max
    return int(sum((min(ew, els[i + 1]) - max(sw, els[i])).total_seconds()
               for i in range(0, len(els), 2) if sw <= els[i + 1] and ew >= els[i]))

No.4

def sum_light(els: List[datetime], start_watching: Optional[datetime] = None, end_watching: Optional[datetime] = None) -> int:
    if len(els) == 0:
        return 0
    if end_watching and end_watching <= els[0]:
        return 0
    if len(els) == 1:
        return int((end_watching - max(els[0], start_watching)).total_seconds())
    
    if start_watching and els[1] <= start_watching:
        return sum_light(els[2:], start_watching, end_watching)
    
    start_point = max(els[0], start_watching) if start_watching else els[0]
    end_point = min(els[1],end_watching) if end_watching else els[1]
    return int((end_point - start_point).total_seconds()) + sum_light(els[2:], start_watching, end_watching)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值