python技巧

1、求解列表最大值及其下标:

max(zip(nums, range(len(nums))))

2、反转列表:

reversed(range(n))

 下面的写法与上面的写法等价

range(n, -1, -1)

 下面的写法也能实现列表反转, 但是a[3:-1:-1]不能实现边截取边反转,只能通过list(reversed(a[0:4]))实现

a[::-1]

 3、二维列表的截取:

[[a[i][j] for j in range(n // 2)] for i in range(n //2)]

跟matlab不同的是,下面写法无法对列进行截取,因为a[:n // 2]本身是一个二维列表

a[:n//2][:n//2]

4、堆的使用,如果使用大顶堆,需要对数值取反:

import queue
q = queue.PriorityQueue()
q.put(num) #放置元素
q.qsize() #获取队列长度
q.get() #取出堆顶元素
q.queue[0] #获取堆顶元素

该模块(queue.PriorityQueue)是从下面的模块(heap)总封装成的,具有线程安全的特点 

import heapq
heapq.heapify(nums) #堆排序数组
heapq.heappush(heap, num) #放入元素
heapq.heappop(heap) #取出堆顶元素
nums[0] #获取堆顶元素

5、排序,自定义排序比较函数

from functools import cmp_to_key   
def compare(x, y): 
    return int(y+x) - int(x+y)
nums = sorted(map(str, nums), key=cmp_to_key(compare))

6、 if a: 既会判断 a 是否非None, 是否列表非空,是否字符串不为空串,是否不为0,相当于if bool(a): 

7、使用迭代器中序遍历二叉树:

def inOrder(p):
    if not p: return
    yield from inOrder(p.left)
    yield p.val
    yield from inOrder(p.right)
print(list(inOrder(root)))

但是效率不如直接添加到数组,见二叉搜索树最近节点查询 

8、二分查找

import bisect
bisect.bisect([2,3,5,6,7],5) #3
bisect.bisect_left([2,3,5,6,7], 5) #3
bisect.bisect_right([2,3,5,6,7], 5) #2

返回的插入点 i 可以将数组 a 分成两部分。左侧是 all(val < x for val in a[lo:i]) ,右侧是 all(val >= x for val in a[i:hi])

参考资料:8.6. bisect — 数组二分查找算法 — Python 3.6.15 文档

【Python】详解 bisect 模块_闻韶-CSDN博客_bisect.bisect_left

此外,该函数不仅可以对固定数组进行二分查找,还可以根据输入求出表达式的值,例如:有序数组中的缺失元素

class Solution:
    def missingElement(self, nums: List[int], k: int) -> int:
        self.__class__.__getitem__ = lambda self, mid: nums[mid] - (nums[0] + mid) >= k
        l = bisect.bisect_left(self, True, 0, len(nums))
        return nums[l - 1] + k - (nums[l - 1] - (nums[0] + (l - 1)))

Python 3.10 支持通过 key 自定义二分规则: 例如:最小化两个数组中的最大值

class Solution:
    def minimizeSet(self, d1: int, d2: int, uniqueCnt1: int, uniqueCnt2: int) -> int:
        lcm = math.lcm(d1, d2)
        def check(x: int) -> bool:
            left1 = max(uniqueCnt1 - x // d2 + x // lcm, 0)
            left2 = max(uniqueCnt2 - x // d1 + x // lcm, 0)
            common = x - x // d1 - x // d2 + x // lcm
            return common >= left1 + left2
        return bisect_left(range((uniqueCnt1 + uniqueCnt2) * 2 - 1), True, key=check)

9、有序字典

from sortedcontainers import SortedDict as SD
sd = SortedDict({1: 3, 3: 1, 2: 2}) #SortedDict({1: 3, 2: 2, 3: 1})
idx = sd.bisect_right(2) #2
idx = sd.bisect_left(2) #1
sd.values()[idx] #2

10、有序列表

from sortedcontainers import SortedList
s = SortedList([])
s.add(("ds", 2))
s.add(("ad", 3))
print(s) #SortedList([('ad', 3), ('ds', 2)])

11、默认词典:

from collections import defaultdict
m = defaultdict(int)
m[0] += 1 #defaultdict(<class 'int'>, {0: 1})

12、 计数:

import collections
a = [1,2,3,4,2,4,5,2,3]
m = collections.Counter(a) #Counter({2: 3, 3: 2, 4: 2, 1: 1, 5: 1})
m.count(4) #2

13、lru缓存

from functools import lru_cache

@lru_cache()
def f(n):
    if n <= 1: return n 
    return f(n - 1) + f(n - 2)

f(100) #354224848179261915075

14、按照频率将数组升序排序

sorted(nums, key = lru_cache(None)( lambda n: (nums.count(n), -n) ))
sum(iter(v for _,_,v in sorted((v,-k,[k]*v) for k,v in Counter(nums).items())),[])

15、求取前缀和

list(itertools.accumulate([1,2,3,4,5], initial=0)) #[0, 1, 3, 6, 10, 15]

16、找到二进制1的个数以及二进制的长度

print((n:=2).bit_count())
print((n:=2).bit_length())

17、求排列组合及数目

print(list(itertools.combinations([1,2,3,4], 2))) 
#[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
print(math.comb(4, 2)) # 6
print(list(itertools.permutations([1,2,3], 2))) 
#[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
print(math.perm(3, 2)) #6
print(math.factorial(6)) #720

18、求最大公约数和最小公倍数

math.gcd(4,6) #2
math.lcm(4, 6, 8) #24

 19、reduce函数

reduce(lambda x,y: x*y, [1,2,3,4]) #24

20、pairwise函数

pairwise([1,2,3,4]) #[(1,2),(2,3),(3,4)]

21、取余定律

  • 加法:(a+b)%N = (a%N + b%N) % N 
  • 减法:(a-b)%N = (a%N - b%N) % N
  • 乘法:(a*b)%N = (a%N * b%N) % N
  • 幂运算:(a^b)%N = ( (a%N) ^ b ) % N

除法取余涉及到逆元,可直接使用python自带的库

pow(a, -1, mod)

排列组合逆元:

class Permutation:
    """排列组合计算器"""

    def __init__(self, mod: int = 10 ** 9 + 7):
        self._mod = mod
        self._size = 0
        self._cache_factorial = [1]  # 缓存阶乘
        self._cache_factorial_inv = [1]  # 缓存阶乘的乘法逆元

    def factorial(self, n: int) -> int:
        """计算阶乘:n!"""
        while self._size <= n:
            self._size += 1
            self._cache_factorial.append((self._cache_factorial[-1] * self._size) % self._mod)
            self._cache_factorial_inv.append(pow(self._cache_factorial[-1], self._mod - 2, self._mod))
        return self._cache_factorial[n]

    def arrange(self, n: int, m: int) -> int:
        """计算排列数:A(n,m) (n>=m)"""
        return (self.factorial(n) * self._cache_factorial_inv[n - m]) % self._mod

    def comb(self, n: int, m: int) -> int:
        """计算组合数:C(n,m) (n>=m)"""
        return (self.arrange(n, m) * self._cache_factorial_inv[m]) % self._mod

  参考资料:

Python SortedContainers Module 对字典排序_阿茂丶-CSDN博客_sortedcontainers

python中的有序字典 - 天痕丶 - 博客园

Python| itertools之pairwise:获取连续的重叠对_lovetaozibaby的博客-CSDN博客_pairwise python排列组合计算器(包含乘法逆元)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值