题目描述
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
思路:
# -*- coding:utf-8 -*-
class Solution:
def GetUglyNumber_Solution(self, index):
# write code here
if index == 0:
return 0
# 1作为特殊数直接保存
baselist = [1]
min2 = min3 = min5 = 0
curnum = 1
while curnum < index:
minnum = min(baselist[min2] * 2, baselist[min3] * 3, baselist[min5] * 5)
baselist.append(minnum)
# 找到第一个乘以2的结果大于当前最大丑数M的数字,也就是T2
while baselist[min2] * 2 <= minnum:
min2 += 1
# 找到第一个乘以3的结果大于当前最大丑数M的数字,也就是T3
while baselist[min3] * 3 <= minnum:
min3 += 1
# 找到第一个乘以5的结果大于当前最大丑数M的数字,也就是T5
while baselist[min5] * 5 <= minnum:
min5 += 1
curnum += 1
return baselist[-1]
原文:https://blog.csdn.net/qq_20141867/article/details/81060581
数值的次方
题目描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
思路:
这道题看似简单,其实BUG重重。要注意的问题:
1 关于次幂的问题特殊的情况,比如次幂为负数,或者基数为0时等等复杂的情况
2. 机器中浮点数的比较是由误差的,因此double类型的比较,不能用简单的a==0来比较。一般的比较方式是,相减的差在一个很小的区间内,我们就认为是相等的。思路:首先考虑base在-0.00001到0.00001之间的数,其接近于0,所以其指数次输出为0,对于指数为0的任意非0数结果为1,对于指数幂为1的任意数结果为base本身,对于其他的base值,当指数为正数时,直接相乘即可,对于指数为负数时,先将其转换为正的指数,相乘的结果再取倒数即可。
即分情况讨论即可
# -*- coding:utf-8 -*-
class Solution:
def Power(self, base, exponent):
if base==0:
return 0
elif exponent==0:
return 1
elif exponent==1:
return base
else:
return pow(base,exponent)
题目描述
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
问题:1. 输入整数,可能是正,可能是负,或者是0
2.整数转变为二进制如何转变?如何计算1的个数
python中 可以使用bin(n).count(‘1’)这个做法,但是需要单独考虑因为n是负数时该式子不成立
3.补码是什么? 负数如何用补码
复习:
一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1
原码:
原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如8位二进制1,-1的原码如下
8----- [+1]原 = 00000001
[-1]原 = 1000 0001
第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是: [1111 1111, 0111 1111] 即 [-127 , 127]
反码:正数的反码是其本身,负数的反码是在其原码的基础上,符号位不变,其余各个位取反. [+1] = [00000001] 原 = [00000001]反
[-1] = [10000001]原 = [11111110]反
补码:正数的补码就是其本身,负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1.
(即在反码的基础上+1)
如何获得二进制数?
”方法1: 用2辗转相除直到结果为1,将余数和最后的1从下向上的组合,就是我们想要的结果
python中 可以使用bin(n).count(‘1’)这个做法,但是需要单独考虑因为n是负数时该式子不成立
# -*- coding:utf-8 -*-
class Solution:
def NumberOf1(self, n):
cnt = 0
if n < 0:
n = n & 0xffffffff
return bin(n).count('1')
带self 参数就需要建立class类
输入一个负整数看看,程序会陷入死循环,因为在其他语言中,负数在计算机中是用补码表示的,最高位是1,在右移的过程中,高位都是用1来填补的,所以while num这个条件一直为真;在python中,根据右移的定义就可以自行推断出来。既然现在右移num不行,那我们可以左移1,在32的整数中,最多左移32位,1就会变为零,所以这可以作为判断条件,在python中,我们一起可以左移下去(到虚拟内存大小的位数),
可以使用一个mask来表示正在看到的位数,循环32次,那么就得到了每一个位置上是1的个数
# -*- coding:utf-8 -*-
class Solution:
def NumberOf1(self, n):
mask = 1
cnt = 0
for i in range(32):
if n & mask:
cnt += 1
mask <<= 1
return cnt
https://www.jianshu.com/p/e29d64d8f1c3
`
https://www.jianshu.com/p/e29d64d8f1c3
方法2:是用位运算,将1每次左移,和数字进行&运算,如果成功,则返回1
技巧:python中的左移和右移与其他C/C++等的定义和结果都是不一样的,大家可以自行做实验,python中的定义:右移n位定义为除以pow(2,n),左移n位定义为乘以pow(2,n),而且没有溢出(移除的int会升级为long类型)
`n-1会让n最右边的1变为0,其左边所有的数字都不会改变,所以每 n = (n-1)&n一次,n就少一个1
class Solution:
def NumberOf1(self, n):
total =0
if n==0:
return 0
if n<0:
n=n & 0xffffffff # 这一步是关于负数运算的
while n:
n=n&(n-1) #按位与
total+=1
return total
class Solution:
def numberOf1(self, n):
total = 0
if n == 0:
return 0
if n < 0:
n = n & 0xffffffff
while n:
n = n & (n - 1)
total += 1
return total
if __name__ == '__main__':
demo=Solution()
print(demo.numberOf1(9))
为什么这个输出是none
拓展:
位运算n&(n-1)的使用
按位与的知识
n&(n-1)作用:将n的二进制表示中的最低位为1的改为0,先看一个简单的例子: n = 10100(二进制),则(n-1) = 10011
==》n&(n-1) = 10000 可以看到原本最低位为1的那位变为0。
1、 判断一个数是否是2的方幂
n > 0 && ((n & (n - 1)) == 0 )解释((n & (n-1)) == 0):
如果A&B==0,表示A与B的二进制形式没有在同一个位置都为1的时候。
那么本题到底啥意思??
不妨先看下n-1是什么意思。
令:n=1101011000(二进制,十进制也一样),则
n-1=1101010111。
n&(n-1)=1101010000
由此可以得出,n和n-1的低位不一样,直到有个转折点,就是借位的那个点,从这个点开始的高位,n和n-1都一样,如果高位一样这就造成一个问题,就是n和n-1在相同的位上可能会有同一个1,从而使((n
& (n-1)) != 0),如果想要((n & (n-1)) == 0),则高位必须全为0,这样就没有相同的1。
所以n是2的幂或0
求某一个数的二进制表示中1的个数 while (n >0 ) {
count ++;
n &= (n-1); }计算N!的质因数2的个数。 容易得出N!质因数2的个数 = [N / 2] + [N / 4] + [N / 8] + …. 下面通过一个简单的例子来推导一下过程:N = 10101(二进制表示) 现在我们跟踪最高位的1,不考虑其他位假定为0, 则在 [N / 2]
01000 [N / 4] 00100 [N / 8] 00010 [N / 8] 00001 则所有相加等于01111
= 10000 - 1 由此推及其他位可得:(10101)!的质因数2的个数为10000 - 1 + 00100 - 1 + 00001 - 1 = 10101 - 3(二进制表示中1的个数)推及一般N!的质因数2的个数为N-(N二进制表示中1的个数)
顺时针打印矩阵
题目描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
则依次打印出数字
1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
解析:由于题目是以从外圈到内圈的顺序依次打印,在矩阵中标注一圈作为分析的目标。设矩阵的宽度为cols,而其高度为rows。选取左上角坐标为(startX, startY),右下角坐标为(endX, endY)的一个圈来分析。
由于endX和endY可以根据startX、startY以及columns、rows来求得,因此此时我们只需要引入startX和startY两个变量。我们可以想象有一个循环,在每一次循环里我们从(startX, startY)出发按照顺时针打印数字。
接着分析这个循环结束的条件。对一个5×5的矩阵而言,最后一圈只有一个数字,对应的坐标为(2, 2)。我们发现5 > 2 * 2。对一个6×6的矩阵而言,最后一圈有四个数字,对应的坐标仍然为(2, 2)。我们发现6 > 2 * 2依然成立。于是我们可以得出,让循环继续的条件是“cols > startX * 2 && rows > startY * 2”。
接下来我们分析如何按照顺时针的顺序打印一圈的数字。我们可以分四步来打印:第一步是从左到右打印一行,第二步是从上到下打印一列,第三步从右到左打印一行,最后一步是从下到上打印一列。也就是我们把打印一圈数字这个问题,分解成四个子问题。
值得注意的是,最后一圈可能退化成只有一行、只有一列、甚至只有一个数字,因此打印这样的一圈就不需要四步了。
原文:https://blog.csdn.net/yanxiaolx/article/details/52254590
def printMatrix(self, matrix):
# write code here
if matrix==[[]]:
return
row=len(matrix)
column=len(matrix[0])
left=0
right=column-1
top=0
boom=row-1
res=[]
while right>left and top<boom:
#从左到右
for i in range(left,right+1):
res.append(matrix[top][i])
#从上到下
for i in range(top+1,boom+1):
res.append(matrix[i][right])
#从右到左
for i in range(right-1,left-1,-1):
res.append(matrix[boom][i])
#从下到上
for i in range(boom-1,top,-1):
res.append(matrix[i][left])
left+=1
right-=1
top+=1
boom-=1
#剩下一行
if boom==top and left<right:
for i in range(left,right+1):
res.append(matrix[boom][i])
#剩下一列
if left==right and boom>top:
for i in range(top,boom+1):
res.append(matrix[i][left])
#剩下一个
if boom==top and left==right:
res.append(matrix[left][top])
return res
原文:https://blog.csdn.net/yangnianjinxin/article/details/79243110
和为s的连续正数序列
题目描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
思路
# -*- coding:utf-8 -*-
class Solution:
def FindContinuousSequence(self, tsum):
res=[]
for i in range(1,tsum//2+1):
sumRes=i
for j in range(i+1,tsum//2+2):
sumRes+=j
if sumRes==tsum:
res.append(list(range(i,j+1)))
break
elif sumRes>tsum:
break
return res
-和为s的两个数字
题目描述
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
输出描述: 对应每个测试案例,输出两个数,小的先输出。
不需要判断最小的
# -*- coding:utf-8 -*-
class Solution:
def FindNumbersWithSum(self, array, tsum):
for i in array:
if tsum-i in array:
if tsum-i==i:
if array.count(i)>1:
return [i,i]
else:
return [i,tsum-i]
return []
下面这个是我自己写的,通过
# -*- coding:utf-8 -*-
class Solution:
def FindNumbersWithSum(self, array, tsum):
list=[]
n=len(array)
for i in range(0,n-1):
for j in range(i+1,n):
if array[i]+array[j]==tsum:
list.append([array[i],array[j]])
if list==[]:
return []
return min(list)
题目描述
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
思路:
1,使用空格或者特殊字符把字符串转换为多个单词字符串,然后存在列表里,
2,列表翻转,再进行连接
-- coding:utf-8 --
class Solution:
def ReverseSentence(self, s):
str1=s.split(’ ') #
lists=[]
for i in str1:
lists.append(i)
return ’ '.join(lists[::-1])
## 矩阵中的路径*** 机器人的运动范围
题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
思路:
回溯法,遍历矩阵中的每一个位置
-- coding:utf-8 --
class Solution:
def hasPath(self, matrix, rows, cols, path):
for i, s in enumerate(matrix):
if s==path[0] and self.visit([(i//cols, i%cols)], matrix, rows, cols, path):
return True
return False
def visit(self, ans, matrix, rows, cols, path):
if len(ans)==len(path):
return True
i,j = ans[-1]
nex = [(ii,jj) for ii,jj in [(i,j-1),(i,j+1),(i-1,j),(i+1,j)]
if 0<= ii <rows and 0<= jj <cols and
(ii,jj) not in ans and
matrix[ii*cols +jj]==path[len(ans)]]
return sum([self.visit(ans+[x], matrix, rows, cols, path) for x in nex])
题目描述
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
思路:将地图全部置1,遍历能够到达的点,将遍历的点置0并令计数+1.这个思路在找前后左右相连的点很有用,比如leetcode中的海岛个数问题/最大海岛问题都可以用这种方法来求解。
class Solution:
def init(self):
self.count = 0
def movingCount(self, threshold, rows, cols):
# write code here
arr = [[1 for i in range(cols)] for j in range(rows)]
self.findway(arr, 0, 0, threshold)
return self.count
def findway(self, arr, i, j, k):
if i < 0 or j < 0 or i >= len(arr) or j >= len(arr[0]):
return
tmpi = list(map(int, list(str(i))))
tmpj = list(map(int, list(str(j))))
if sum(tmpi) + sum(tmpj) > k or arr[i][j] != 1:
return
arr[i][j] = 0
self.count += 1
self.findway(arr, i + 1, j, k)
self.findway(arr, i - 1, j, k)
self.findway(arr, i, j + 1, k)
self.findway(arr, i, j - 1, k)
## 求1到N加法,做加法
题目描述
求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
思路:直接套公式
-- coding:utf-8 --
class Solution:
def Sum_Solution(self, n):
return n*(n+1)/2
# write code here
题目描述
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
思路:可以采用位操作来实现,利用异或运算来计算不带进位的加法结果,利用与运算计算进位的标志,然后将这两个结果进行不带进位相加,重复上述过程,直至进位标志位0
链接:https://www.nowcoder.com/questionTerminal/59ac416b4b944300b617d4f7f111b215
来源:牛客网
同样我们可以用三步走的方式计算二进制值相加: 5-101,7-111 第一步:相加各位的值,不算进位,得到010,二进制每位相加就相当于各位做异或操作,101^111。
第二步:计算进位值,得到1010,相当于各位做与操作得到101,再向左移一位得到1010,(101&111)<<1。
第三步重复上述两步, 各位相加 010^1010=1000,进位值为100=(010&1010)<<1。
继续重复上述两步:1000^100 = 1100,进位值为0,跳出循环,1100为最终结果。
计算两个数字的异或值,相当于只计算每一位的和,不计算进位,得出结果sum;
2.计算两个数字的与值,相当于求出两个数字的进位,然后左移一位,相当于进位,得出结果jw
-- coding:utf-8 --
class Solution:
def Add(self, num1, num2):
# write code here
while num2 != 0:
temp = num1 ^ num2
num2 = (num1 & num2) << 1
num1 = temp & 0xFFFFFFFF
return num1 if num1 >> 31 == 0 else num1 - 4294967296
## -翻转单词顺序列
题目描述
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
思路:
1,使用空格或者特殊字符把字符串转换为多个单词字符串,然后存在列表里,
2,列表翻转,再进行连接
-- coding:utf-8 --
class Solution:
def ReverseSentence(self, s):
str1=s.split(’ ') #
lists=[]
for i in str1:
lists.append(i)
return ’ '.join(lists[::-1])
## 扑克牌顺子****
题目描述
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。
思路:
> 链接:https://www.nowcoder.com/questionTerminal/762836f4d43d43ca9deb273b3de8e1f4
来源:牛客网
>
> 这道题很简单,注意两点
> 1、如果输入为空,返回false
> 2、除了王的任何某个特定数值的牌出现两张或者更多,那么一定凑不齐顺子。
> 思路,先统计王的数量,再把牌排序,如果后面一个数比前面一个数大于1以上,那么中间的差值就必须用王来补了。看王的数量够不够,如果够就返回true,否则返回false。
思路:
1)没有大小王的时候即判断数是否连续;
2)有大小王的时候,判断数的间隔是否小于王的数量。小于返回true,大于返回false;
3)有相等的牌则直接返回false。
链接:https://www.nowcoder.com/questionTerminal/762836f4d43d43ca9deb273b3de8e1f4
来源:牛客网
class Solution:
def IsContinuous(self, numbers):
# write code here
if len(numbers) < 5:
return False
#计算0的个数
nOfZero = numbers.count(0)
#排序
numbers.sort()
#序列中间隔的值初始化为0
sumOfGap=0
#遍历非0部分的递增序列
for i in range(nOfZero, len(numbers) - 1):
small = numbers[i]
big = numbers[i + 1]
#当前与下一个值的比较,若相等则说明存在对子
if small == big:
return False
else:
#若不同,则得到二者的差再减1,若为0则说明连续,否则二者之间存在空缺
sumOfGap+= (big-small - 1)
#判断0的个数及序列中非0部分间隔值,若0不小于间隔值,则说明满足连续条件
if nOfZero >= sumOfGap:
return True
else:
return False
## 孩子们的游戏
题目描述
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
思路:
约瑟夫问题
一个重要的公式
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190223193426255.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI0NDI5MzMz,size_16,color_FFFFFF,t_70)
链接:https://www.nowcoder.com/questionTerminal/f78a359491e64a50bce2d89cff857eb6
来源:牛客网
class Solution:
def LastRemaining_Solution(self, n, m):
if n < 1:
return -1
con = range(n)
final = -1
start = 0
while con:
k = (start + m - 1) % n
final = con.pop(k)
n -= 1
start = k
return final