【蓝桥杯每日练习】:位运算

一、位运算符

符号描述作用
&与运算两个都为1,结果为1
|或运算只要有一个为1,结果为1
^异或同为0,异为1
~取反0变为1,1变为0
<<左移左移,末位补0
>>右移右移,高位补0

二、例题

1、二进制中1的个数

1.1 题目

请实现一个函数,输入一个整数n,输出该数二进制表示中1的个数。
例:9的二进制表示为1001,有2位是1

1.2 分析

只要将整数n与n-1进行与运算&,就可以删掉末位的1,例如:n=14,n的二进制为1110,n-1的二进制就是1101,进行与运算(都为1,结果为1),得到1100,此时末位的1被删掉。因此,我们只要不断的将n与n-1进行与运算并更新n,直到n=0时退出循环,此时循环的次数就是该数二进制表示中1的个数。

1.3 python代码

n = int(input())
res = 0
while n != 0:
    n = n & (n-1)
    res += 1    # 记录循环次数
print(res)

2、是不是2的整数次方

2.1 题目

用一条语句判断一个整数是不是2的整数次方。如果是就输出"yes",如果不是就输出"no"。
例:8是2的整数次方,输出"yes";9不是2的整数次方,输出"no"。

2.2 分析

这题比上一题更加简单,也是用与运算来解决。首先,我们来理解题目,如果一个数是2的整数次方(例:2^0 ,2的1次方,2的2次方等等),则说明二进制表达式中只有最高位为1,其他位都为0,因此只需要将n和n-1进行与运算,只要与运算结果为0,则说明除了最高位为1之外,其他位都是0,反之,则说明该数的二进制表达中不只一个1。

2.3 python代码

n=int(input())
if n & (n-1)==0:
    print("yes")
else:
    print("no")

3、小小蓝的异或消除

3.1 题目描述

小小蓝是一名天才程序员,他研究了一种特殊的数组操作,他称之为“异或消除”。
对一个整数数组arr执行一次“异或消除”操作,可以拆解成以下四个步骤:

  1. 找到数组中的最大值a和次大值b,若有多个相同的最大值或次大值,取最左边的那个。
  2. 将a和b两个元素同时从数组中移除。
  3. 计算a和b的异或值c = a ⊕ b。
  4. 将c放入数组的最左边。
    小小蓝想知道,对于给定的数组arr,经过不断的“异或消除”操作后,数组中最后留下的元素。他请你编写一个程序来帮助他解决这个问题。

输入格式

输入包含两行。
输入的第一行,包含一个整数n(1≤n≤10^5),表示数组arr的长度。
输入的第二行,包含n个整数,表示数组arr中的元素。

输出格式

输出仅一行,包含一个整数,表示数组中最后留下的元素。

样例输入

5
3 5 7 5 3

样例输出

7

说明

  1. 第一次异或消除操作,取出7和5,异或得2,数组变为[2,3,5,3]。
  2. 第二次异或消除操作,取出5和3,异或得6,数组变为[6,2,3]。
  3. 第三次异或消除操作,取出6和3,异或得5,数组变为[5,2]。
  4. 第四次异或消除操作,取出5和2,异或得7,数组变为[7]。

3.2 python代码

最开始的时候,我按照题意,直接写的代码,但是发现运行速度较慢,因此后面换了一个思路重新写了一个代码,运行速度大幅提升。
下面是最先写的代码:

# 原代码
import time
start = time.perf_counter()    # 存储初始时间
n=int(input())
arr=list(map(int,input().split()))
for i in range(n-1):
    m1=max(arr)
    arr.pop(arr.index(m1))
    m2=max(arr)
    arr.pop(arr.index(m2))
    c=m1 ^ m2
    arr.append(c)
print(arr[0])
end=time.perf_counter()   # 存储结束时间
print(str(end-start))     # 计算运行时间

输出结果:

12 
2 5 27 4 3 48 12 37 8 4 5 82
89
30.7753576

下面这个是后面改进后的代码:

import time
start = time.perf_counter()
n=int(input())
arr=list(map(int,input().split()))
res=0
for i in range(n):
    res^=max(arr)
    arr.pop(arr.index(max(arr)))
print(res)
end=time.perf_counter()
print(str(end-start))

输出结果:

12 
2 5 27 4 3 48 12 37 8 4 5 82
89
1.3495462999999999         # 可以看到对比上面,速度有明显的提升
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值