算法基础2

位运算/离散化/区间合并

位运算

image-20240331144424884

方法一:

思路:在二进制表示中,1 的最低位是 1,其余位都是 0。==当一个数 i1 进行“按位与”运算时,只有 i 的最低位是 1 时,结果才会是 1,否则结果是 0。==这是因为“按位与”运算的规则是,只有两个对应位都是 1 时,结果才是 1,否则结果是 0

# 这个方法会超时,但是我觉得时间复杂度没啥区别
n = int(input())
L = [int(x) for x in input().split()]

def lowbit(i):
    res = 0
    while n:
        if i & 1:  # 检查二进制表示的最低位是否为1
            res += 1
        i+=1
    return res
for i in L:
    print(lowbit(i),end=" ")

方法二:

思路:在二进制表示中,-nn 的二进制补码,即 n 的二进制表示的每一位取反后加 1。因此,n & -n 的结果就是 n 的二进制表示中最低位的 1。循环体中,首先计算 i 的二进制表示中最低位的 1,然后从 i 中减去这个值,然后将 res1。这样,每次循环都会消除 i 的二进制表示中的一个 1,直到 i 变为 0,此时 res 就是 i 的二进制表示中 1 的个数。

n = int(input())
L = [int(x) for x in input().split()]
res = 0
def lowbit(n):
    return n & -n # 保留最低位的1
for i in L:
    while i:
        i -= lowbit(i) # 每次减去最低位的1
        res += 1
    print(res,end=" ")
    res = 0 # 重置res

离散化

image-20240331153339356

这个题目为为什么要用离散化呢?

⚠️:因为存储的下标实在太大了,如果直接开这么大的数组,根本不现实,第二个原因,本文是数轴,要是采用下标的话,可能存在负值

开始我的写法:(不现实,且边界超出)

from sys import stdin
# 区间化
n, m = map(int, stdin.readline().split())
N = 2 * 10 ** 9 + 100
list_a = [0] * N


def interval_sum(n, m):
    for i in range(n):
        a, b = map(int, stdin.readline().split())
        list_a[a] += b
    for j in range(m):
        sum = [0] * N
        for i in range(1, N + 1):
            sum[i] = sum[i - 1] + list_a[i]
        l, r = map(int, stdin.readline().split())
        print(sum[r] - sum[l - 1])


if __name__ == '__main__':
    interval_sum(n, m)

**离散化的本质:**是映射,将间隔很大的点,映射到相邻的数组元素中。减少对空间的需求,也减少计算量

8021.png

模版:

#把原区间序号离散化 IndexLst[i]的值代表原区间的序号,i代表离散化后的序号
#1.把添加,查询操作使用的所有序号记录下来,排序去重得到一个离散化后的区间
#2.按照离散化后的序号,进行 添加,求区间和的操作
n,m = map(int,input().split())
addNum = []
query = []
IndexLst = []
for i in range(n):
    x,c = map(int,input().split())
    addNum.append([x,c])
    IndexLst.append(x)
for i in range(m):
    l,r = map(int,input().split())
    query.append([l,r])
    IndexLst.append(l)
    IndexLst.append(r)

#离散化操作
IndexLst.sort()
IndexLst = list(set(IndexLst)) 

def find(x):
    l = 0
    r = len(IndexLst)-1
    while l<r:
        mid = (l+r)>>1
        if x<=IndexLst[mid]:r=mid
        else:l=mid+1
    return r+1 #离散化后的序号为1 —— len(IndexLst)-1


#注意nums序号从1到len-1
#s[0]=0 s[1] = nums[1]
nums=[0]*(len(IndexLst)+5)
s =[0]*(len(IndexLst)+5)
for x,c in addNum:
    nums[find(x)]+=c
for i in range(1,len(IndexLst)+1):
    s[i]=s[i-1]+nums[i]
for i in query:
    l,r = find(i[0]),find(i[1])
    print(s[r]-s[l-1])

区间合并

image-20240331203905291

思路:
可以先按左端点排序,再维护一个区间,与后面一个个区间进行三种情况的比较,存储到数组里去

模版:

n = int(input())
arr = []
for i in range(n):
    l,r = map(int,input().split())
    arr.append((l,r)) # 用元组存储区间
arr.sort(key=lambda x:x[0]) # 按照区间的左端点排序
st = arr[0][0] # 区间的左端点
ed = arr[0][1] # 区间的右端点
num = 1
for i in range(1,n):
    if arr[i][1] <= ed: # 如果当前区间的右端点小于等于ed,说明当前区间被包含在前一个区间中,直接跳过
        continue
    if arr[i][0] <= ed and arr[i][1] > ed: # 如果当前区间的左端点小于等于ed,但是右端点大于ed,说明两个区间有交集,更新ed
        ed = arr[i][1]
    if arr[i][0] > ed: # 如果当前区间的左端点大于ed,说明两个区间没有交集,更新st和ed,num+1
        num += 1
        st = arr[i][0]
        ed = arr[i][1]
print(num)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值