401.二进制手表: 一道典型的回溯题,一般的思路是将num分解成h和m,分别表示hour中LED灯亮的数量和minute中LED灯亮的数量,同一个数量对应着不同的取值 i.e. h = 1 对应着 小时可以取到1, 2, 4, 8这四种取值,且都是合法的,而h=2对应着小时可以取到3, 5, 9,6,10,12 这6种取值,其中12超过了11是不合法的。
h的数量固定时,m= num - h 自然也就固定, 而我们要做的就是在固定h的数量时, 将所有合法的小时的对应取值H和分钟的对应取值MM组合起来成为 “H:MM”
沿着这个思路, 问题归结为两点:
- 其一, 给定h,如何算取[1, 2, 4, 8]的数量为h的合法组合(的和),自然也有m对应的
- 其二, 在第一点解决后,如何将给定h情况下,不同的小时对应的取值和分钟对应的取值组合起来
以上,难点在于 如何恰当地实现对组合数的求解
给定一个长度为n的列表,求长度为h的不同组合 (注意,需要的是具体的组合,不是组合数)
1 | def combinations(nums: list, h: int) -> list[list]: |
其实回顾一下我们小学是怎么求组合的,这个问题也就不攻自破了:
假定有一列数:a, b, c, d, e, …… 共n个
我们要求它的长度为k的组合,那么可以分两步:
- 选择第一个数,从剩下的n-1个数里选择k-1个
- 第一个数不选,从剩下的n-1个数里选择k个数
有没有受到一点启发?我们减小了问题的规模😯
再考虑一下边界情况,我们就可以轻松实现求解所有的长度为h的组合啦
- 如果h > n, 不满足组合的定义,用assert报错
- 如果列表的长度就是h,直接返回整个列表就好
- 如果h==0: 返回一个空列表
- 如果 h==1, 那直接枚举每一种可能
话不多说,上代码:
1 | def combinations(nums: list, h: int): |