目录
一、斐波那契数列
题干
斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0,F(1) = 1 F(n) = F(n - 1) + F(n - 2),其中 n > 1
给你 n ,请计算 F(n) 。
解答
#递归的思想
class Solution(object):
def fib(self, n):
if n<2:
return n
else:
return self.fib(n-1)+self.fib(n-2)
#累加的思想,很明显时间复杂度更低
class Solution:
def fib(self, n):
if n < 2:
return n
p, q, r = 0, 0, 1
for i in range(2, n + 1):
p, q = q, r
r = p + q
return r
二、第N个泰波那契数
题干
泰波那契序列 Tn 定义如下:
T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2
给你整数 n,请返回第 n 个泰波那契数 Tn 的值。
解答
class Solution(object):
def tribonacci(self, n):
num,a,b,c=0,0,1,1
if n==0:
return 0
elif n==1 or n==2:
return 1
elif n>=3:
for i in range(n-2):
num=a+b+c
a=b
b=c
c=num
return num
三、爬楼梯
题干
假设你正在爬楼梯。需要 n
阶你才能到达楼顶。
每次你可以爬 1
或 2
个台阶。你有多少种不同的方法可以爬到楼顶呢?
解答
#其实就是斐波那契
class Solution(object):
def climbStairs(self, n):
a = [i for i in range(46)]
if n<=2:
return n
else:
for i in range(3,n+1):
a[i]=a[i-1]+a[i-2]
return a[n]
四、最小花费爬楼梯
题干
给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。
你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。
请你计算并返回达到楼梯顶部的最低花费。
解答
class Solution(object):
def minCostClimbingStairs(self, cost):
#到达第n级台阶所需花费。由于只是到达,不收该台阶的过路费
money = [0 for i in range(len(cost)+1)]
for i in range(2,len(cost)+1):
money[i]=min(money[i-1]+cost[i-1],money[i-2]+cost[i-2])
return money[-1]
五、买股票的最佳时机
题干
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
解答
class Solution(object):
def maxProfit(self, prices):
Max=0
Min=prices[0]
for i in range(1,len(prices)): #假设今天卖出
Min=min(Min,prices[i]) #在今天之前,价格的最小值
Max=max(Max,prices[i]-Min)
return Max
六、最长公共子序列
题干
给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。如果不存在公共子序列 ,返回 0 。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
解答
class Solution:
def longestCommonSubsequence(self, text1, text2):
m, n = len(text1), len(text2)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if text1[i - 1] == text2[j - 1]:
#如果这个字符属于最长子序列
dp[i][j] = dp[i - 1][j - 1] + 1
else:
#在这个字符之前,有没有最长子序列?
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
return dp[m][n]
七、杨辉三角
题干
输入某个数N,输出其在杨辉三角中第一次出现时是第几个数。例如,输入N=6,输出13
解答
a = [1 for i in range(10000)] # 可以适当增加数组的长度
goal=int(input())
len=temp=3
flag=True
if goal==1:
print(1)
flag=False
elif goal==2:
print(5)
flag=False
while flag==True:
for i in range(len+1,len+temp-1):
a[i]=a[i-temp]+a[i-temp+1]
if a[i]==goal:
flag=False
print(i+1)
break
len=len+temp
temp=temp+1
八、节点选择
题干
有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?
输入格式
第一行包含一个整数 n 。
接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。
接下来一共 n-1 行,每行描述树上的一条边。
输出格式
输出一个整数,代表选出的点的权值和的最大值。
样例输入
5
1 2 3 4 5
1 2
1 3
2 4
2 5
样例输出
12
样例说明
选择3、4、5号点,权值和为 3+4+5 = 12 。
数据规模与约定
对于20%的数据, n <= 20。
对于50%的数据, n <= 1000。
对于100%的数据, n <= 100000。
权值均为不超过1000的正整数。
解答
写完后认真想了想,觉得果然是偏离dp解法了
n=int(input())
dp = [[0] * n for _ in range(n)] # 关系矩阵,有关为1,无关为0
cost=list(map(int,input().split(" ")))
Max=0
for i in range(n-1):
m, n = map(int, input().split())
dp[m-1][n-1]=dp[n-1][m-1]=1 # 只是觉得对称比较好看,其实并不需要
for i in range(n-1):
flag=True
path=cost[i]
temp=[i]
for j in range(i+1,n):
if dp[i][j] == 0 : # 如果选择当前点
path=path+cost[j]
i=j
temp.append(j)
for x in temp:
for y in temp:
if dp[x][y] == 1:
flag=False
break
if flag==False:
break
if flag==True:
Max=max(Max,path)
print(Max)
九、耐摔指数
题干
x 星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。
塔的各层高度都是一样的。他们的第 1 层不是地面,而是相当于我们的 2 楼。 他们的地面层为 0 层。如果手机从第 7 层扔下去没摔坏,但第 8 层摔坏了,则 手机耐摔指数 = 7。
特别地,如果手机从第 1 层扔下去就坏了,则耐摔指数 = 0。 如果到了塔的最高层第 n 层扔没摔坏,则耐摔指数 = n。 为了加快测试进度,从每个型号手机中,抽样 3 部参加测试。
问题来了:如果已知了测试塔的高度 n,并且采用最佳的策略,在最坏的运气下 需要测试多少次才能确定手机的耐摔指数呢?
解答
这边建议出题人好好回去学学语文
h=int(input())+1
dp = [[0] * 3 for _ in range(h)]
for i in range(1,h):
dp[i][0]=i
for i in range(1,h):
temp=100000
for j in range(1,i+1):
# 假设手机从第j层摔下,摔碎了,手机数-1,需要测试剩下的1~j-1层
# 没摔碎,手机数不变,要测试剩下的j+1~h层
temp=min(temp,max(dp[j-1][0]+1,dp[i-j][1]+1))
dp[i][1]=temp
for i in range(1,h):
temp=100000
for j in range(1,i+1):
temp=min(temp,max(dp[j-1][1]+1,dp[i-j][2]+1))
dp[i][2] = temp
print(dp[-1][-1])
十、k好数
题干
问题描述
如果一个自然数 N 的 K 进制表示中任意的相邻的两位都不是相邻的数字,那么 我们就说这个数是 K 好数。求 L 位 K 进制数中 K 好数的数目。例如 K = 4,L = 2 的时候,所有 K 好数为 11、13、20、22、30、31、33 共 7 个。由于这个数目很 大,请你输出它对 1000000007 取模后的值。 输入格式 输入包含两个正整数,K 和 L。
输出格式
输出一个整数,表示答案对 1000000007 取模后的值。
样例输入
4 2
样例输出
7
数据规模与约定
对于 30%的数据,KL <= 106;
对于 50%的数据,K <= 16, L <= 10;
对于 100%的数据,1 <= K,L <= 100
解答
我竟然完全没看出来这个可以用dp解,起手暴力循环...
ps:我觉得答案写的很好,所以它是我的了(doge)
K,L=list(map(int,input().split()))
# 横坐标表示位,纵坐标表示某一位的状态,值为某一位在某一状态时的可能性
num=[[0 for i in range(L)] for j in range(K)]
for i in range(K): # 如果是第一位,那每种状态都只有一种情况
num[i][0]=1
print(num)
for j in range(L-1): # 位数,从第二位开始填表
for i in range(K): # 某一位当前的状态
tmp=0
for k in range(K): # 某一位前一位的状态
if abs(k-i)!=1:
tmp+=num[k][j]
num[i][j+1]=tmp
ans=0
for i in range(1,K): # 排除首位是0的情况
ans+=num[i][L-1]
print(ans%1000000007)