【思特奇杯·云上蓝桥-算法集中营】第3周

目录

一、斐波那契数列

题干

解答

二、第N个泰波那契数

题干

解答

三、爬楼梯

题干

解答

四、最小花费爬楼梯

题干

解答

五、买股票的最佳时机

题干

解答

六、最长公共子序列

题干

解答

七、杨辉三角

题干

解答

八、节点选择

题干

解答

九、耐摔指数

题干

解答

十、k好数

题干

解答


一、斐波那契数列

题干

斐波那契数,通常用 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 阶你才能到达楼顶。

每次你可以爬 12 个台阶。你有多少种不同的方法可以爬到楼顶呢?

解答

#其实就是斐波那契
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)

猜你喜欢

转载自blog.csdn.net/shuhuigao/article/details/122644261