题目:
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
这里需要弄清楚为什么python中负数需要和 0xFFFFFFFF 做与操作?
在计算机中,所有的数字都是使用补码存储起来的。由于Python没有位数这个概念,所以得到二进制表示需要多一点操作,即将位数限制在32位,通过和一个32位的全1数字按位与运算即可。对于正数来说,上面的按位与操作可以不做,因为正数的符号位为0,补码即原码,所以前面的数字全为0,按位与没有意义。但对于负数来说,直接bin(-1)是不能得到其补码的,而是得到了1的原码前面加上了负号,即-0b1。则通过和一个32位的全1数字按位与运算可得到其补码二进制表示对应的十进制数(按位与运算把符号位的1视为了数字)。
补码:正数不变,负数是它正数的反码+1
例如:-2:111…1101+1即111…110
在python中比较特殊,它储存二进制的-2是-ob10,所以 0xFFFFFFFF&n 直接得到负数的正数
#只取n的前32位,n&32个1(0xFFFFFFFF)
#一个F是四位在十六进制里面
#简易做法:
n = 0xFFFFFFFF&n
count = 0
for c in str(bin(n)):
if c == "1":
court +=
return coun t
#做法二:
#每一次进行n-1&n的操作时n中的一个1都会被干掉
#到最后就会变成0
def NumberOf1(self,n):
count = 0
while n:
n=n&0xFFFFFFFF
n=n&(n-1)
count += 1
return count
题目:
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
异或^:相等为0,不等为1
先把两个数变成二进制,然后让这两个数进行与运算,得到的结果左移一位(因为要进行进位操作),然后再将;两个数进行异或操作(此时的两个数相加则是结果),然后把新得到的两个数一直循环下去直至进行与操作得到的数为0,最后进行异或操作得到的那个数就是答案。
加法操作可以转化为二进制数中先进行与操作,再进行异或操作,因为与操作是相同为1,不同为0,这样可以找到二进制数中需要进位的数的位置,然后在进行左移一位因为需要进位,然后再将这两个数进行异或操作,得到需要相加数的位置,因为异或操作是相同为0,不同为1。最后将这两个位操作的到的结果相加则可。但是不能相加所以可以继续进行这个操作,直至与操作得到的结果为0为止。
def Add(self,num1,num2):
xorNum = num1 ^ num2
andNum = (num1 & num2) << 1
while andNum != 0:
tmp1 = xorNum ^ andNum
tmp2=(xorNum & andNum) << 1
#python中存储数字是无限位,在进行异或操作的时候会得到很多个1,所以要把它变为32位的,但是在与操作的时候不会有这种情况
tmp1 = tmp1 & 0xFFFFFFFF
xorNum = tmp1
andNum = tmp2
#F在二进制里面是1111,7在二进制里面是0111
#在这里要判断是否为负数的情况,ox7FFFFFFF是在32位中正数的最大值,
#~为按位取反的意思
return xorNum if xorNum <= 0x7FFFFFFF else ~(xorNum ^ 0xFFFFFFFF)
题目:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
遇到不相同的数字就相互抵消掉,最终剩下的数字就可能是大于一半的数字长度的数字
def MoreThanHalfNum_Solution(self,numbers):
last = 0
lastCount = 0
for num in numbers:
if lastCount == 0:
last = num
lastCount = 1
else:
if num == last:
lastCount +=1
else:
lastCount -= 1
if lastCount == 0:
return 0
else:
#这种情况就是last可能大于一半的数字
lastCount = 0
for num in numbers:
if num == last:
lastCount += 1
if lastCount > (len(numbers) >> 1):
return last
return 0
题目:
求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
题目:
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
方法一:(时间复杂度太高)
死循环找丑数,判断一个数是不是丑数先一直循环除以2,直到不能整除,然后是3,然后是5,直到最后除完得1。
count = 0
def isUglyNumber(num):
while num % 2 == 0:
num = num//2
while num % 3 ==0:
num = num//3
while num % 5 ==0:
num = num//5
if num == 1:
return True
else:
return False
num = 1
while True:
if isUglyNumber(num):
count += 1
if count == index:
return num
num += 1
方法二:
创建一个装丑数的列表,然后根据index找到丑数。
生成三个指针分别是乘以2,3,5,得出来的数比较大小,小的放下一个,然后乘完的指针向下移一位,一直循环下去。
def GetUglyNumber_solution(self,index):
if index < 1:
retuen 0
uglyList = [1]
twoPointer = 0
threePointer = 0
fivePointer = 0
count = 1
while count != index:
minValue = min(2*uglyList[twoPointer],3*uglyList[threePointer],5*uglyList[fivePointer])
uglyList.append(minValue)
count += 1
if minValue == 2*uglyList[twoPointer]:
twoPointer += 1
if minValue == 3*uglyList[threePointer]:
threePointer += 1
if minValue == 5*uglyList[fivePointer]:
fivePointer += 1
return uglyList[count-1]
题目:
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
两个相同的数字异或为0,并且a^b ^c=a ^c ^b。
1。>> 和 <<都是位运算,对二进制数进行移位操作。<< 是左移,末位补0,相当于原数x乘2。>>是右移,右移1位相当于除以2。
找到那两个数的异或和之后,找数字里面的1的位置(用除以2,有余数的那个就是1的位置或者向右移一位)。再用掩码生成一个数,把这个数与数组中所有的数进行与操作,会得到两种数,一种与操作完为0,另一个与操作完为1。
def findNumsAppearOnce(self,array):
if len(array) < 2:
return None
twoNumXor = None
for num in array:
if twoNumXor == None:
twoNumXor == num
else:
twoNumXor = twoNumXor ^ num
#得到的twoNumXor就是两个不同数的异或,
#此时去找这个二进制数最后位上是1就可以判断出它们这些位上是不同的
#除以2去掉一个0,一直到有余数就找到那个1,因为2在二进制中是10
count = 0
while twoNumXor %2 == 0 :
twoNumXor = twoNumXor >> 1
count += 1
#1向左移count位
mask = 1 << count
#此时拿mask与数组进行与操作(相当于掩码操作,只判断mask中1那位上的数是否为1),
#把数组分为两组,每一组上都有一个只出现一次的数和其他相同的数
firstNum = None
secondNum = None
for num in array:
if mask & num == 0:
if firstNum == None:
firstNum = num
else:
firstNum == firstNum ^ num
else:
if secondNum == None:
secondNum == num
else:
secondNum = secondNum ^ num
return firstNum,secondNum
扑克牌顺子
题目:LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张_)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。
算一下列表里面0的个数,然后按照大小进行排序,把0都去掉,算一下每个数之间的空隙,如果空隙大于0的个数则False,反之则True。
def IsContinuous(self, numbers):
# write code here
if numbers == []:
return False
zeroNum = numbers.count(0)
numbers.sort()
gap_number = 0
for i in range(zeroNum,len(numbers)-1):
if numbers[i] == numbers[i+1]:
return False
gap_number += (numbers[i+1] - numbers[i] -1)
if gap_number > zeroNum:
return False
else:
return True