《算法很美》python实现 记录python算法学习
python入门,开始学习算法,通过写博客记录,总结,巩固学习成果。
代码通过python实现,学习参考资料为蓝桥学院《算法很美》
位运算
位运算符号:&(位与),|(位或),^(位异或)
&:对应数位都是1,该位运算结果才为1
|:对应数位只要有1个为1,该位运算结果就为1
^: 对应数位相同(同1 或 同0),该位运算结果为1
位运算基础运用:
① 判断奇偶数
原因:将待判断的数转换为二进制数,若为奇数,二进制最后一位为1,否则,二进制最后一位为0,因此,让待判断的数和1做位与运算,结果为1,则为奇数,反之,则为偶数。
n=int(input())
if n&1==1:
print(n,"为奇数")
else:
print(n,"为偶数")
② 获取二进制某位是0 还是1
方法:通过位移运算符,将查找某位移到最低位,和1做位与运算,结果为1,则该位为1,反之,则为0
a=13 # 1101
b=14 # 1110
#判断a ,b值对应的二进制的倒数第二位
result1=(a>>1)&1
result2=(b>>1)&1
print(result1,result2) #1 0
例题1 寻找数组中落单的数
一个数组除了某一个数字之外,其他的数字都出现了两次。请写一个程序找出这个只出现一次的数字
思路:运用异或运算
首先,明确异或运算的相关知识点
^:对应数位相同(同1 或 同0),该位运算结果为1
A^A=0
A^0=A
数组=[X1,X2,X3,X4……Xn]
因为A ^ A=0,那么对该数组所有元素求异或运算,即X1^ X2^ X3^ X4^ ……^ Xn,其中出现两次的数字Xi ^ Xj=0,最后X1^ X2^ X3^ X4^ ……^ Xn=X单^0=X单
代码如下:
numlist=[1,1,2,3,4,6,3,4,2,] #该数组落单的数字位6
res=0
for i in range(len(numlist)): #对数组所有元素进行^运算
res^=numlist[i]
print(res) #输出的是6
例题2 寻找数组中成对的数
1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素重复,其他的数字均只出现1次,每个数字只能访问一次,设计一个算法,将他找出来,不用辅助储存空间
思路:同上题,运用异或运算,稍微有点小变通
A^A=0
A^0=A
若像上题所有元素进行异或运算,那么相同的那两个数结果为0,被消去,不可行。
假设成对的数为k,那么对该数组所有元素进行异或运算(1^ 2 ^ 3 ^ 4 ^ ……^ k ^ k ^ … …^ 999^1000)[1001个数] ,在和( 1 ^ 2 ^ 3 ^ 4 ^ … … ^ 999 ^1000)[1000个数]进行异或运算,即( 1 ^ 2 ^ 3 ^ 4 ^ …… ^ k ^ k ^ …… ^ 999 ^ 1000) ^ ( 1 ^ 2 ^ 3 ^ 4 ^ … ^k … ^ 999 ^1000) ,那么之后成对的数多了1个,变为了3个,其位运算结果k ^ k ^ k=0 ^ k =k,其余出现一次的数成对,其位运算结果为0,就类似例题一的情况。
代码如下:
import random
numlist1=[i for i in range(1,1001)]
a=random.randrange(1,1001) #生成一个随机数
numlist1.append(a) #随机添加一个数,使得一个数成对,
res1=0
for i in range(len(numlist1)):
res1^=numlist1[i] #1^ 2 ^ 3 ^ 4 ^ ……^ k ^ k ^ … …^ 999^1000
numlist2=[j for j in range(1,1001)]
res2=0
for i in range(len(numlist2)):
res1^=numlist2[i] #1 ^ 2 ^ 3 ^ 4 ^ … ^k … ^ 999 ^1000
print(res1^res2)
print(a) #输出的res1^res2 , a 是相同的
例题3 二进制中1的个数
输入一个整数,输出该数二进制的1的个数
解法有很多种:
法一:设置一个count变量,将该数转变成一个二进制数字符串,碰到1,则count加1,遍历完,count为最终结果。
法二:利用位移运算符,同样设置一个count变量,不断向右移动1位,和1做位与运算,看最低位是否为1,统计到以count变量
法三:统计二进制1的个数,就看二进制数中的1被消除几次。
不断减1法
以11为例子,11的二进制为1011,11-1=10,二进制表示为(1011-0001=1010)10和11做位与运算,二进制:1011&1010=1010 ,可见11和(11-1)做与运算,把从右往左出现的第一个1消除了,接着10-1=9,二进制:1010-0001=1001
10和9做与运算,二进制:1010&1001=1000, 把从右往左出现的第二个1消除了,接着9-1=8,二进制:1001-0001=1000,9和8做与运算,二进制:1000&0111=0000,到这0000为终止条件,期间减去了3个1,每减去1个1,x&(x-1)使得二进制数x从右往左出现的第一个1消除了
代码如下:
count=0
n=int(input())
while n!=0: #n=0为终止条件
n=n&(n-1) #消去一个1,count就加1
count+=1
print(count)
例题4 判断一个数是否是2的n次方
观察是2的n次方的数的二进制表达,4:0100,8:0100,16:1000,其二进制表达式1的个数为1,其余全为0,联想上道题,判断二进制中1的个数,因此判断一个数是否是2的n次方,就是判断二进制中1的个数是否为1
代码如下
n=int(input())
print(n&(n-1)==0) #输出True 则是2的n次方
例题4 将二进制的奇偶位互换
思路:将奇数位和偶数位分开
二进制数位运算中,对应每位中,和0做与运算,被消去,变为0,和1做与运算,表示保留,0还是0,1还是1
以9为例子,其二进制为1001
分别和1010和0101做与运算
1001 & 0101 = 0001 得到了偶数位
1001 & 1010 = 1000 得到了奇数位
这样奇数位和偶数位便分开了
奇数位和偶数位互换,可通过位移运算符>>,<<
将奇数位>>1,偶数位<<1,二者进行异或运算便得到了结果
即(1000>>1)^(0001<<1)=0110
num=int(input())
binarynum=format(num,"b")
binarynum="{:0>8}".format(binarynum) #转为二进制数字符串
num01=int("01"*(len(binarynum)//2),2) #01为了获得其偶数位
num10=int("10"*(len(binarynum)//2),2) #10为了获得其奇数位
res=((num&num01)<<1)^((num&num10)>>1) #偶数位左移,奇数位右移,再做异或运算
print(res) #输出的是对应十进制
例题5 二进制表示浮点实数
给定以给0-1的实数,例如0.625,打印他的二进制位:0.101,因为小数点后面的二进制为:0.5,0.25,0.125…如果该数字不能用32位以内的二进制精确表示 ,则输出“Error”
代码如下:
n=eval(input())
resstr="0."
error=False
while n>0:
n=n*2 #乘2
if n>=1:
n-=1 #去整数
resstr+="1"
else:
resstr+="0"
if len(resstr)>34:
print("ERROR")
error=True
break
if not error:
print(resstr)
例题6
数组中某个数只出现了1次,其余数字出现了k次,请输出出现一次的这个数字(k>=2)
思路分析:
以k=3举例
三个三进制相加,做不进位加法!!!得到的是0
(不进位加法:当两数相加时,某一位的结果每大于等于该数对应的进制,不需要需要向上一位进1)
如3个7相加,7的三进制位21
21
21
21
——
00
同理两个二进制数相加,做不进位加法!!!得到的也是0
由此,我们可以知道
k个k进制数做不进位加法,结果为0
回到题目,将数组所有数字转为k进制,所有数字做不进位加法,那么出现k次的数字得到0,最后剩下出现1次的数字,再将该数字的k进制转为10进制
定义一个转换进制的函数
def tostr(num,base):
convertstring="0123456789ABCDEFG"
if num<base:
return convertstring[num]
else:
return tostr(num//base,base)+convertstring[num%base]
定义一个数组,以k=3为例
定义一个列表,用来储存转换为三进制的结果
还需要定义一个变量,来储存转为三进制字符串的最大长度。
numlist=[2,7,8,9,7,8,9,7,8,9]
k=3
Ternarynum=[] #三进制字符数组
maxlen=0
将数组中的数转换为三进制数,还需要倒置。
原因:保证后面做不进位加法,低位能够对齐
以12,7为例,转为三进制数110,11
倒置后:
011
11
各自的最低位对应着最低位
for num in numlist:
if len(tostr(num,k)[::-1])>maxlen:
maxlen=len(tostr(num,k)[::-1])
Ternarynum.append(list(tostr(num,k)[::-1]))
转换为三进制数后做不进位加法
result=[]
for i in range(maxlen):
thesum=0
for j in range(len(Ternarynum)):
if i>=len(Ternarynum[j]):
thesum+=0
else:
thesum+=eval(Ternarynum[j][i])
result.append(thesum%k)
最后得到的就是单独出现的数,因为之前倒置过,所以先倒置回来,然后转为10进制输出
resultnum=""
for i in result:
resultnum+=str(i)
resultnum=resultnum[::-1]
print(int(resultnum,k))
本文深入探讨了位运算的基础及应用,包括判断奇偶数、获取二进制位、寻找数组中落单或成对的数等算法问题,并提供了Python实现代码。同时,介绍了二进制中1的个数判断、判断2的n次方数、二进制奇偶位互换、浮点实数二进制表示等技巧。
1471

被折叠的 条评论
为什么被折叠?



