这篇博客是收集整理了一些以前平时的练手题目以及比较有意思的题目,锻炼思维逻辑和编程的能力的题,并附上个人的思路代码,多种解法。若大家有不同的见解,可以留言一起交流,后续也会继续发布新的内容。
例1、小明爬楼梯
小明要爬上一个有39阶的楼梯,每次最多可以跨两步,问小明一共有多少种方法?
递归的解法:
def count(n):
if n==1:
return 1
if n==2:
return 2
if n>2:
return count(n-1)+count(n-2)
x=int(input("请输入楼梯阶数;"))
print(count(x))
拓展:
拓展1、兔子生崽
一对兔子出生后第三月开始产崽,每月产一对崽,小兔子出生以后的第三个月开始产崽,每月一对,问第十个月共有有多少对兔子?
拓展2、小明又爬楼梯
小明又要爬上一个有15阶的楼梯,每次最多可以跨三步,问小明一共有多少种方法?
例2、生日蜡烛
某人从某年开始每年都举办一次生日,并且每次都要吹灭与自己年龄相同根数的蜡烛。现在算起来,他一共吹熄了 236 根蜡烛。请问,他从多少岁开始过生日的。
题解:
方法一
穷举法,这个是最简单,基本的方法,从一个年龄开始,计算多少个连续数字,当累计和大于236但不等于236时,跳出循环继续下一次。看看从第几个年龄开始的一段连续数字之和能恰好等于236:
for i in range(1,50):
sum=0 #年龄和
for j in range(i,50):
sum+=j
if sum==236:
print(sum,"起始年龄为:",i)
if sum>236:
continue #不符合条件,跳出此次循环
方法二
236根蜡烛一定是一段连续的数字之和(未知个数,含有起始数a和尾数b),那么我们将236作为一个界限,当连续数字之和小于236我们就继续加b+1,当大于236时,我们从头开始挨个进行减a,重复操作直到,达到和为236。
sum=0 #连续年龄和
a=1 #起始年龄
b=1 #末尾年龄
while sum != 236:
if sum < 236:
sum += #b年龄之和小于236但不等于236,增加下一年的年龄
b += 1 #最后一年龄的变化
if sum > 236: #年龄大于236但不等于236,减去起始计算第一年的年龄
sum -= a
a += 1
print(sum,"起始年龄为:",a)
例3、求素数
求2~100的素数有哪些?
题解:
方法一
最基本的方法就是判断从2到n范围内有没有n的因子
import math
a=[2]
for i in range(2,101):
for j in range(2,i): #判断2~n里面是否有n的因子
if i%j==0:
break
else:
pass
if j>math.sqrt(i): #当超过n的平方根还没有找到n的因子时,则n为素数
a.append(i)
break
print(a)
方法二
素数也最基本的因子,任意非素数都一定含有素数因子,那我们可以在方法一的基础上减少一些计算量,只判断n以前的素数里面是否有n的因子,若没有,则n也为素数。
import math
a=[2] #初始列表,含有第一个素数
for i in range(2,101):
for j in a: #判断素数是否能做因子
print(j)
if i%j==0: #如果素数可以做因子就排除
break
else:
pass #保证跳到下一个素数
if j>math.sqrt(i): #当除数大于被除数的平方跟的时候,代表没有找到除1和本身的因子
a.append(i) #这个数为素数添加进列表中
break
print(a)
方法三
我们通过剔除倍数的方法,减少计算量,从2开始剔除,直到n/2结束。这个也是最简便的方法。
import numpy as np
a = np.full(100,True) #用一个字符列表来代替数字
for i in range(2,50):
j=i+i #将i的倍数位置上的字符进行变换
while j<100: #实用的防止越界办法
a[j]=False #改变字符
j+=i
for i in range(2,len(a)): #用筛子进行筛选,素数是从2开始,我们就从2开始
if a[i]==True:
print(i,end=' ') #打印出来
例4、黑与白逻辑推理
有 A、B、C、D、E 这 5 个人,每个人额头上都贴了一张黑或白的纸。5 人对坐,每个人都可以看到其他人额头上纸的颜色。5 人相互观察后,
A 说:“我看见有 3 人额头上贴的是白纸,1 人额头上贴的是黑纸。”
B 说:“我看见其他 4 人额头上贴的都是黑纸”
C 说:“我看见 1 人额头上贴的是白纸,其他 3 人额头上贴的是黑纸”
D 说:“我看见 4 人额头上贴的都是白纸”
E 什么也没说。
现在已知额头上贴黑纸的人说的都是谎话,额头贴白纸的人说的都是实话。问这 5 人谁的额头上贴的是白纸,谁的额头上贴的是黑纸?
题解:
从题目中我们得知贴黑纸的人说的是谎话,贴白纸的人说的是实话,那我们可以定义贴白纸的人说实话数字为1,贴黑纸的人说谎话数字为0。那么由此每个人可以用数字来进行区分,并且说的话可以产生两种数字。
for a in range(0,2): #每个人有两种情况,实话或谎话
for b in range(0,2):
for c in range(0,2):
for d in range(0,2):
for e in range(0,2): #实话、白纸为1,谎话、黑纸为0
if ((b+c+d+e==3 and a==1) or (b+c+d+e!=3 and a==0)) and\
((a+c+d+e==0 and b==1) or (a+c+d+e!=0 and b==0)) and\
((a+b+d+e==1 and c==1) or (a+b+d+e!=1 and c==0))and\
((a+b+c+e==4 and d==1) or a+b+c+e!=4 and d==0):
print(a, b, c, d, e)
例5、分糖果
10 个小孩围成一圈分糖果,老师分给第 1 个小孩 10 块,第 2 个小孩 2 块,第 3 个小孩 8 块,第 4 个小孩 22 块,第 5 个小孩 16 块,第 6 个小孩 4 块,第 7 个小孩 10 块,第 8 个小孩 6 块,第 9 个小孩 14 块,第 10 个小孩 20 块。然后所有的小孩同时将手中的糖果分一半给右边的小孩:糖块数为奇数的人可以向老师要一块。问经过这样几次后大家手中的糖块数一样多吗?每人各有多少块糖?
题解:
这个难点不大,就是处理循环过程中的第一个给糖的人收到糖的问题,必须保证给糖的时候首尾相连不出问题。每给一次糖果要循环判断给奇数糖果的同学发一块糖。
方法一
第一次处理的时候,只用了一个列表,同时处理给糖和少糖操作。当处理最后一位同学和第一位同学的时候,我选择利用了一个中间数字进行处理。
##方法一
a=[10,2,8,22,16,4,10,6,14,20]
c=0
while len(set(a))>1: #判断小朋友的糖是否相等,不行等则继续分
c+=1
b=a[9]/2 #保留第十位同学一半的糖,最后给第一位同学
a[9]=a[9]/2
for i in range(9,0,-1): #前九位同学把自己的糖分一半给右边的同学
a[i]+=a[i-1]/2
a[i-1]=a[i-1]/2
a[0] += b #把保留第十位同学的一半的糖给第一位同学
for i in range(0,10): #判断手中持有奇数个糖的小朋友,并添加一颗糖
if a[i]%2!=0:
a[i]+=1
print("一共进行了%d次"%c)
print("当每位小朋友拥有的糖果相等时,他们都有%d个糖果"%a[0])
方法二
这个是后来做出的一个简便的做法,使用两个列表处理,简化计算,并且调整两个列表对应小朋友的位置,方便进行加减操做。
import numpy as np
a=[10,2,8,22,16,4,10,6,14,20]
c=0
while len(set(a))!=1: #判断小朋友的糖是否相等,不行等则继续分
c+=1
b=[]
for i in range(0,10):
b.append(a[i - 1] / 2) #前九位同学把自己的糖分一半给右边的同学,暂时存放
#第一位同学接受的是最后一位同学的糖果,通过i-1,i=0,-1的索引实现糖果的分配
a[i - 1] = a[i - 1] / 2 #前九位同学把自己的糖分一半给右边的同学各自的糖减少一半
a=np.array(a)+np.array(b) #获取前一位同学的糖
for i in range(0,10): #判断手中持有奇数个糖的小朋友,并添加一颗糖
if a[i]%2!=0:
a[i]+=1
print("一共进行了%d次"%c)
print("当每位小朋友拥有的糖果相等时,他们都有%d个糖果"%a[0])
两种方法相似,只是做了简化处理。