【问题】
Self Dividing Numbers(自除数)是指该数能够被自己包含的每个数字整除。
例如,128%1 ==0,128%2 ==0,128%8 ==0,所以128是一个自除数。
注意,自除数是不能包含数字0。(0不能当除数)
所以,本题的要求是,给定一个上下边界,以列表的形式输出该区间包含所有自除数(包含边界)。
【例子】
Input: left = 1, right = 22
Output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22]
【思路】
暴力破解:通过循环,对区间内的每个数字按照定义进行判断。
例如,对于128,我们要测试d!= 0 && 128%d == 0(对于d = 1、2、8)。为此,我们需要遍历数字的每个数字。
如何遍历数字的每个数字:
1、将数字转换为字符串,取出数字后转换为整数后,进行n%d == 0检验
2、将数字连续除以10,取最后一位,进行n%d == 0检验
【解法】
1、又长又啰嗦的本人的解法
class Solution: def selfDividingNumbers(self, left: int, right: int) -> List[int]: output = [] for i in range(left,right+1): if "0" in str(i): continue c = 0 for n in range(0,len(str(i))): if i%int(str(i)[n]) == 0: c += 1 if c == len(str(i)): output.append(i) return output
2、官方解法
class Solution(object): def selfDividingNumbers(self, left, right): def self_dividing(n): for d in str(n): if d == '0' or n % int(d) > 0: return False return True """ Alternate implementation of self_dividing: def self_dividing(n): x = n while x > 0: x, d = divmod(x, 10) if d == 0 or n % d > 0: return False return True """ ans = [] for n in range(left, right + 1): if self_dividing(n): ans.append(n) return ans #Equals filter(self_dividing, range(left, right+1))
学习1:编写方程def self_dividing(n)
学习2:用False和True进行判定,我是用if c == len(str(i))进行判定,不如此法优雅,但解决思路是一样的
3、极简解法
基础版本
return [x for x in range(left, right+1) if all([int(i) != 0 and x % int(i)==0 for i in str(x)])]
优化版本
return [x for x in range(left, right+1) if all((i and (x % i==0) for i in map(int, str(x))))]
step by step
[ x for x in range(left, right+1) # iterate all numbers 遍历 if all( # whether all conditions in the list are true 条件判断 [int(i) != 0 and x % int(i)==0 # translate each digit into int and check whether dividable 自除数判断 for i in str(x)] # translate int to an iterable string 遍历 ) ]
学习1:用int(i)代替int(i) == 0(因为在if 0: 判断为False,所以可以简写
学习2:all()函数
当判断condition1 and condition2 and condition3时,大部分compiler/intepreter是从左到右依次判断,如果condition1==False,就会直接返回False(这也被称作short-circuit evaluation.)。
在本题中,每个数只要有一个数字不满足就可以离开判断。下列代码是对每个数是否是自除数进行判读,
if all( [... for i in str(x)] )
会遍历每个数字,并将判断结果输出,例如x=128,输出[True, True, True],x=23,输出[False, False]
但如果第一个数字的结果是False就可以直接返回False,计算第二个数字就是浪费。所以可以将代码改为
if all( (... for i in str(x)) )
all() 函数用于判断给定的可迭代参数 iterable 中的所有元素是否都为 TRUE,如果是返回 True,否则返回 False。
元素除了是 0、空、None、False 外都算 True。
函数等价于:
def all(iterable): for element in iterable: if not element: return False return True
Python 2.5 以上版本可用。
语法:all(iterable) iterable -- 元组或列表。
返回值:如果iterable的所有元素不为0、''、False或者iterable为空,all(iterable)返回True,否则返回False;
注意:空元组、空列表返回值为True,这里要特别注意。
实例
>>> all(['a', 'b', 'c', 'd']) # 列表list,元素都不为空或0 True >>> all(['a', 'b', '', 'd']) # 列表list,存在一个为空的元素 False >>> all([0, 1,2, 3]) # 列表list,存在一个为0的元素 False >>> all(('a', 'b', 'c', 'd')) # 元组tuple,元素都不为空或0 True >>> all(('a', 'b', '', 'd')) # 元组tuple,存在一个为空的元素 False >>> all((0, 1, 2, 3)) # 元组tuple,存在一个为0的元素 False >>> all([]) # 空列表 True >>> all(()) # 空元组 True
学习3:map()函数
因为把字符串转换为整数int会花费一些时间,因此我们可以先将字符串转换为int,而不是两次转换。
map(lambda x: int(x), str_to_convert)
map() 会根据提供的函数对指定序列做映射。
第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。
语法:map(function, iterable, ...)
- function -- 函数
- iterable -- 一个或多个序列
返回值:
Python 2.x 返回列表。
Python 3.x 返回迭代器。
实例
>>>def square(x) : # 计算平方数 ... return x ** 2 ... >>> map(square, [1,2,3,4,5]) # 计算列表各个元素的平方 [1, 4, 9, 16, 25] >>> map(lambda x: x ** 2, [1, 2, 3, 4, 5]) # 使用 lambda 匿名函数 [1, 4, 9, 16, 25] # 提供了两个列表,对相同位置的列表数据进行相加 >>> map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10]) [3, 7, 11, 15, 19]
参考:
https://www.runoob.com/python/python-func-map.html
https://www.runoob.com/python/python-func-all.html
https://leetcode.com/problems/self-dividing-numbers/discuss/162578/One-line-Python-(Learn-some-Python-tricks-that-you-might-not-know)