python算法模板第一部分(3)(双指针、位运算、离散化、区间合并)

注:本文是在学习了acwing的算法基础课后撰写,主要用于记录python版本算法的模板。其中部分参考了acwing众多大佬的题解。

1.双指针

思想:
朴素的两重循环需要O( n 2 n^2 n2),可以利用某种性质(i和j之间的单调关系)将其变为O(n)。
可用于单序列和双序列。
单序列中可用于维护一段区间,双序列中用于维护某种次序,如有序序列的合并。

模板:

# 朴素做法(用于对比):
for i in range(n):
	for j in range(i):
		if check(j, i):
			res = max(res, j - i + 1)

# 双指针做法:
for j in range(n):
	while i <= j and check(i, j):		# check函数根据题意编写
		i += 1
	res = max(res, j - i + 1)

2.位运算

常见用法:
1.n的二进制第k位
num >> k & 1

2.返回x的最后一位1
x & (~x+1)
x = 10101000
~x = 01010111
~x+1 = 01011000
x&(~x+1) = 00001000

3.离散化

思想:
适用于数组下标范围大,但值域小的情况。由于数组下标范围太大,开同样大小的数组不现实。离散化可以减少对空间的需求,离散化的思想是将间隔很大的点映射到相邻的数组元素中,常见做法是将数值映射为下标
在这里插入图片描述
如上图,原本需要10001长度的数组,现在只需要4。

步骤:
1.将所有使用到的下标都加入数组adds中
2.对adds排序后去重
3.根据题目要求进行剩余操作

模板:

def find(x):
    # 二分寻找
    l = 0
    r = len(alls) - 1
    while l < r:
        mid = (l + r + 1) >> 1
        if alls[mid] <= x:
            l = mid
        else:
            r = mid - 1
    return l + 1


if __name__ == "__main__":    
    n, m = map(int, input().split())
    N = 300010
    a = [0] * N     # 存储离散化后的索引和对应值,其中索引对应离散化后的索引,值对应离散化前索引的取值
    s = [0] * N     # 存a数组的前缀和数组
    
    add = []        # 存储插入操作的二元组
    query = []      # 存储查询操作的二元组
    alls = []       # 存储离散化前输入的所有索引,共n+2m个
    
    # 1.将所有使用到的下标都加入数组adds中
    for i in range(n):
        x, c = map(int, input().split())
        add.append((x, c))
        alls.append(x)
    
    for j in range(m):
        l, r = map(int, input().split())
        query.append((l, r))
        alls.append(l)
        alls.append(r)
    
    # 2.alls排序并去重
    alls = list(set(sorted(alls)))
    
    # 3.根据题目要求进行剩余操作
    
    # 插入
    for x, c in add:
        x2 = find(x)
        a[x2] += c
    
    # 前缀和
    for i in range(1, len(alls) + 1):
        s[i] = s[i-1] + a[i]
        
    # 查询
    for l, r in query:
        l2 = find(l)
        r2 = find(r)
        res = s[r2] - s[l2-1]
        print(res)

4.区间合并

思想:
用于快速合并n个区间。先排序后遍历维护合并区间。

步骤:
1.以区间左端点为基准对区间排序。
2.按顺序遍历区间,维护区间[start,end],表示当前的合并区间。若遍历到的区间与当前合并区间有交集,就会将其合并,否则遍历到的区间成为新的合并区间。
在这里插入图片描述

模板:

"""
segs为区间数组如[(1,2), (1,4)]
res为合并后的区间数组如[(1,4)]
"""
def merge(segs):
    res = []
    segs.sort()
    start = float('-inf')
    end = float('-inf')
    for l, r in segs:
        if end < l:
            if start != float('-inf'):
                res.append((start, end))
            start = l
            end = r
        else:
            end = max(end, r)
    if start != float('-inf'):
        res.append((start, end))
    return res

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值