【Leetcode】可以一行(One-Liner)Python代码解决的 Leetcode 问题 - 掌握 Python 高阶函数


能够一行 Python 代码解决的问题,基本上就是用到 python 的高阶函数。
所以了解和解决这些问题,就掌握了 Python 的高阶函数。


高阶函数

reduce

1281. Subtract the Product and Sum of Digits of an Integer

Solution:

class Solution:
    def subtractProductAndSum(self, n: int) -> int:
        from  operator import mul
        from functools import reduce

        src = [int(i) for i in str(n)]
        return reduce(mul, src) - sum(src)

这个写法虽然不是一行,但是如果硬要写成一行也是可以的(导入包不计的话)。
而这一题对于 reduce 的写法比较典型。

Submission:
image.png

leetcode 网友更快的解法:
@ejaytumacder

Python 3 Solution 20 ms, 13.7 MB faster than 98.88%

class Solution:
 def subtractProductAndSum(self, n: int) -> int:
     sigma = 0
     pi = 1
     while(n > 0):
         n, digit = divmod(n, 10)
         sigma += digit
         pi *= digit
     return pi - sigma

reduce 的典型用法

reduce 函数的整体思路如图 10-1 所示。

reduce 图10-1
我们已经知道 functools.reduce() 可以替换成 sum(), 下面说说它的原理。 它的关键思想是, 把一系列值归约成单个值。 reduce() 函数的第一个参数是接受两个参数的函数, 第二个参数是一个可迭代的对象。 假如有个接受两个参数的 fn 函数和一个 lst 列表。 调用 reduce(fn, lst) 时, fn 会应用到第一对元素上, 即fn(lst[0], lst[1]), 生成第一个结果 r1。 然后, fn 会应用到 r1 和下一个元素上, 即 fn(r1, lst[2]), 生成第二个结果 r2。 接着, 调用 fn(r2, lst[3]), 生成 r3…… 直到最后一个元素, 返回最后得到的结果 rN1

自己实现 sum 功能的函数

在 Python 2 中, reduce 是内置函数, 但是在 Python 3 中放到 functools 模块里了。 这个函数最常用于求和, 自 2003 年发布的 Python 2.3 开始, 最好使用内置的 sum 函数。 在可读性和性能方面, 这是一项重大改善(见示例 5-6)。2

示例 5-6

学习了使用 reduce 函数 + add (operator.add) 函数实现 sum 函数,那么上面 1281. Subtract the Product and Sum of Digits of an Integer 中的 reduce(mul, src) 也就可以想得到了。

如果不用 reduce 函数(高阶函数),那么普通的写法是这样的:

/* C language */
int multiplicative(const int * const arr, int length) {
    /* 注意 int 长度问题,这里不做判断 */
    int ans = 1;
    int i = 0;
    for (i=0; i < length; i++) {
        ans *= arr[i];
    }
    return ans;
}

显然要多敲了很多次键盘 🙄

使用匿名函数 lambda 实现阶乘 N ! N! N!

上一题中使用 operator.mul + functools.reduce 实现了“累乘”,阶乘其实就是“累乘”的特殊集合。
如果之前没有听说过 operator 包,就不能一行实现阶乘了吗?

实际上 operator 包中的算数运算函数的实现也是十分简洁的,operator 实际上只是帮忙节省了敲键盘的次数。这一点可以通过自行查看 operator.py 了解。

答案显然是否定的:

from functools import reduce

def factorial(n: int) -> int:
    return reduce(lambda x, y: x * y, range(1, n + 1))

除了 sum,factorial 之外,还可以一行实现 “聚合异或” 的需求。
聚合异或 在 Leetcode 中也有一题,见下文中实现。

1486. XOR Operation in an Array

Solution:

class Solution:
    def xorOperation(self, n: int, start: int) -> int:
        from functools import reduce
        from operator import xor

        return reduce(xor, [(start + 2 * i ) for i in range(n)])

Submission:

image.png

1470. Shuffle the Array

2020/07/24

Given the array nums consisting of 2n elements in the form [x1,x2,...,xn,y1,y2,...,yn].

Return the array in the form [x1,y1,x2,y2,...,xn,yn].

Example 1:

Input: nums = [2,5,1,3,4,7], n = 3
Output: [2,3,5,4,1,7] 
Explanation: Since x1=2, x2=5, x3=1, y1=3, y2=4, y3=7 then the answer is [2,3,5,4,1,7].

Example 2:

Input: nums = [1,2,3,4,4,3,2,1], n = 4
Output: [1,4,2,3,3,2,4,1]

Example 3:

Input: nums = [1,1,2,2], n = 2
Output: [1,2,1,2]

Constraints:

  • 1 <= n <= 500
  • nums.length == 2n
  • 1 <= nums[i] <= 10^3

Solution:

from functools import reduce
from operator import add

class Solution:
    def shuffle(self, nums: List[int], n: int) -> List[int]:
        return reduce(add, zip(nums[:n], nums[n:]))

Submission:
image.png

注:
reduce(add, zip(...)) 这个写法不要在生产环境使用,会有严重的性能问题

tuple + tuple => O ( t u p l e . _ _ a d d _ _ ) O(tuple.\_\_add\_\_) O(tuple.__add__) => O ( n ) O(n) O(n)
reduce(tuple + tuple) => n 2 × O ( n ) \frac{n}{2} \times O(n) 2n×O(n) => O ( n 2 ) O(n^2) O(n2)

仅供学习 Python 高阶函数(函数式)编程。

详细细节请通过《Python 算法教程》一书了解:

l = [1, 2, 3]
l.append(4)

l = [1, 2, 3]
l = l + [4]

两种写法的不同,对性能的影响。


附:
无性能忧虑的解法:

def solution(nums: list, n: int) -> list:
    return reduce(lambda l, t: (l.extend(t), l)[-1], zip(nums[:n], nums[n:]), [])

空间和时间复杂度皆最优的解法:

def solution(nums, n):
    ans = [0] * len(nums)
    for i in range(n):
        ans[2*i] = nums[i]
        ans[2*i+1] = nums[n+i]
    return ans

反转字符串

反转字符串专题参见 👉 【Python】反转字符串的很多很多种方法及部分解算法题应用

使用匿名函数和 reduce 反转字符串:

from functools import reduce
def reverse_str(s: str) -> str:
    return reduce(lambda x, y: y + x, s)

sorted

sorted 的用法也是值得掌握的。
不过这篇博客不赘述了,因为其它地方有解释地已经很好的了,
参见 👉 Python3 sorted() 函数

1356. Sort Integers by The Number of 1 Bits

Solution:

class Solution:
    def sortByBits(self, arr: List[int]) -> List[int]:
        return sorted(arr, key=lambda v: (sum([int(_) for _ in bin(v)[2:]]), v))

Submission:
时间和空间都在 30% 左右排名。

不用 bin(v)[2:] + sum(_) 的一行(使用 count)

class Solution:
 def sortByBits(self, arr: List[int]) -> List[int]:
     return sorted(arr, key = lambda x: (bin(x).count("1"), x))

这个写法的 submission 排名应该会靠前。


all

844. Backspace String Compare

Given two strings S and T, return if they are equal when both are typed into empty text editors. # means a backspace character.

Note that after backspacing an empty text, the text will continue empty.

class Solution(object):
    def backspaceCompare(self, S, T):
        def F(S):
            skip = 0
            for x in reversed(S):
                if x == '#':
                    skip += 1
                elif skip:
                    skip -= 1
                else:
                    yield x

        return all(x == y for x, y in itertools.izip_longest(F(S), F(T)))

Submission: N/A


any - N/A

N/A


filter - N/A

N/A



列表推导式

1295. Find Numbers with Even Number of Digits

Solution:

class Solution:
    def findNumbers(self, nums: List[int]) -> int:
        return len([i for i in nums if len(str(i)) % 2 == 0])

Submission:

img

反转字符串

反转字符串专题同上。

使用列表推导反转字符串:

def reverse_str(s: str) -> str:
    return "".join([s[-i] for i in range(1, len(s) + 1)])

557. Reverse Words in a String III

Given a string, you need to reverse the order of characters in each word within a sentence while still preserving whitespace and initial word order.

Example 1:

Input: "Let's take LeetCode contest"
Output: "s'teL ekat edoCteeL tsetnoc"

Note: In the string, each word is separated by single space and there will not be any extra space in the string.

Solution:

class Solution:
    def reverseWords(self, s: str) -> str:
        return " ".join([word[::-1] for word in s.split()])

Submission:

leetcode_submissions_557. Reverse Words in a String III.png


Reference


  1. 《流畅的 Python》 CH 10.6 - Vector类第4版: 散列和快速等值测试:Pn/a ↩︎

  2. 《流畅的 Python》 CH 5.2 - 高阶函数:map、 filter和reduce的现代替代品: Pn/a ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值