算法简单题刷题1 | 豆包MarsCode AI刷题

63 阅读6分钟

群兔繁殖之谜

问题描述

生物学家小 R 正在研究一种特殊的兔子品种的繁殖模式。这种兔子的繁殖遵循以下规律:

  1. 每对成年兔子每个月会生育一对新的小兔子(一雌一雄)。
  2. 新生的小兔子需要一个月成长,到第二个月才能开始繁殖。
  3. 兔子永远不会死亡。

小 R 从一对新生的小兔子开始观察。他想知道在第 A 个月末,总共会有多少对兔子。

请你帮助小 R 编写一个程序,计算在给定的月份 A 时,兔子群体的总对数。

注意:

  • 初始时有 1 对新生小兔子。
  • 第 1 个月末有 1 对兔子:原来那对变成了成年兔子,并开始繁殖。
  • 第 2 个月末有 2 对兔子:原来那 1 对成年兔子,繁殖了 1 对新生的小兔子。
  • 从第 3 个月开始,兔子群体会按照上述规律增长。

输入

一个整数 A(1 ≤ A ≤ 50),表示月份数。

返回

一个长整数,表示第 A 个月末兔子的总对数。

测试样例

样例1:

输入:A = 1 返回:1

样例2:

输入:A = 5 返回:8

样例3:

输入:A = 15 返回:987

题解

是一个简单的数学问题,可以分成两部分来看,一部分是新兔子迭代的情况,一部分是老兔子的迭代情况。新兔子是由老兔子产下,因此下个月的新兔子肯定就是本月老兔子的个数,老兔子是由新兔子经过一个月成长得到,由于兔子不会死,那么下个月老兔子的个数就变成了本月新兔子的个数加上原有的老兔子的个数。最后就可以得到下面的式子:

Nnewcurrent=NoldpreviousNoldcurrent=Noldprevious+NnewprevoiusN_{new\,current} = N_{old\,previous} \\ N_{old\,current} = N_{old\,previous} + N_{new\,prevoius}

循环迭代

def solution(A: int) -> int:
    # Edit your code here
    #数学题,计算方法为,新兔子是上一个月老兔子的对数,老兔子是上一个月老兔子+新兔子的个数,
    #斐波那契数列的变形
    new = 1
    old = [0,0] #[previous , current]
    while A > 0:
        old[1] = new + old[0]
        new = old[0]
        old[0] = old[1]
        A = A - 1
    return new + old[1]
​
​
if __name__ == "__main__":
    # Add your test cases here
    print(solution(1) == 1)
    print(solution(5) == 8)
    print(solution(15) == 987)

记忆化递归

由于直接递归会溢出,可以用记忆化递归。

def solution(A: int) -> int:
    # 使用字典来存储已经计算过的结果
    memo = {}
    
    # 递归函数,计算第 n 个月的兔子总对数
    def fib(n):
        # 如果已经计算过,直接返回结果
        if n in memo:
            return memo[n]
        
        # 递归基例
        if n == 1:
            result = 1
        elif n == 2:
            result = 2
        else:
            # 递归关系
            result = fib(n-1) + fib(n-2)
        
        # 将结果存储在字典中
        memo[n] = result
        return result
    
    # 调用递归函数计算第 A 个月的兔子总对数
    return fib(A)
​
if __name__ == "__main__":
    # Add your test cases here
    print(solution(1) == 1)
    print(solution(5) == 8)
    print(solution(15) == 987)

完美整数

问题描述

一个整数如果由相同的数字构成,则称为完美整数。例如:

  • 111333 是完美整数。
  • 1219101 是不完美整数。

现在,你需要计算给定区间 [x, y] 中有多少个整数是完美整数。


测试样例

样例1:

输入:x = 1 ,y = 10 输出:9

样例2:

输入:x = 2 ,y = 22 输出:10

题解

观察到完美整数是每位都相同的数,个位数一定是完美整数。那么就看可以考虑将数字转换为字符串,判断每位都是否一样即可。这种方法会花费O^2

可以观察到每个位数的数都对应着9个完美整数,比如:所有的个位数中一共有9个完美整数,所有的十位数中共有9个完美整数....

迭代

def solution(x, y):
    count = 0
    
    for num in range(x, y + 1):
        # 将整数转换为字符串
        num_str = str(num)
        
        # 检查字符串中的所有字符是否相同
        if all(char == num_str[0] for char in num_str):
            count += 1
    
    return count
​
if __name__ == "__main__":
    print(solution(1, 10) == 9)
    print(solution(2, 22) == 10)

利用规律,时间复杂度O(1)

def solution(x, y):
# 计算从[1,n]区间内的完美整数个数
    def count_perfect_integers(n):
        n_str = str(n)
        max_digits = len(n_str)
        perfect_num = 0
        for i in range(max_digits):
            perfect_num += 1 * (10 ** i)
        count = 9 * (max_digits - 1) + n//perfect_num
        return count
    if x == 1:
        return count_perfect_integers(y)
    else:
        return count_perfect_integers(y) - count_perfect_integers(x - 1)
​
​
if __name__ == "__main__":
    # Add your test cases here
​
    print(solution(1, 10) == 9)
    print(solution(2, 22) == 10)
​

多米诺骨牌均衡状态

问题描述

小S玩起了多米诺骨牌,他排列了一行骨牌,并可能将某些骨牌向左或向右推倒。随着骨牌连锁反应的进行,一些骨牌可能因为左右两侧受力平衡而保持竖立。现在小S想要知道在所有动作完成后,哪些骨牌保持竖立。

给定一个表示骨牌初始状态的字符串,其中:

  • "L" 表示该位置的骨牌将向左倒。
  • "R" 表示该位置的骨牌将向右倒。
  • "." 表示该位置的骨牌初始时保持竖立。

模拟整个骨牌倒下的过程,求出最终仍然保持竖立的骨牌的数目和位置。

测试样例

样例1:

输入:num = 14,data = ".L.R...LR..L.." 输出:'4:3,6,13,14'

样例2:

输入:num = 5,data = "R...." 输出:'0'

样例3:

输入:num = 1,data = "." 输出:'1:1'

题解

这道题目虽然是简单题,但是需要对数组进行模拟,最好的方式应该是将向左倒、向右倒、竖立看作-1、0、1,这样子利用数组模拟进行状态转移推演时,就可以很轻易的计算出竖立的状态。比如某个牌当前状态是+1,但是右侧是-1,那么可以利用-1+1=0得到状态会变为0(即竖立状态)。此外需要额外注意,各个状态转移的情况,保证没有缺失。

def solution(num, data):
    # 初始化 finalState 数组,0 表示竖立,-1 表示向左倒,+1 表示向右倒
    final_state = [0] * num
​
    # 初始化时间数组,用于记录向左倒和向右倒的受力时间
    time_r = [0] * num  # 向右倒的时间记录
    time_l = [0] * num  # 向左倒的时间记录
​
    # 处理右倒('R')的影响
    for i in range(num):
        if data[i] == 'R':
            final_state[i] = 2  # 表示该位置是初始向右倒的骨牌
            cnt = 1  # 初始化受力时间
            for j in range(i + 1, num):
                if data[j] == '.':
                    final_state[j] = 1  # 向右倒的影响
                    time_r[j] = cnt  # 记录向右倒的受力时间
                    cnt += 1
                else:
                    break  # 遇到其他骨牌终止影响
​
    # 处理左倒('L')的影响
    for i in range(num - 1, -1, -1):
        if data[i] == 'L':
            final_state[i] = 2  # 表示该位置是初始向左倒的骨牌
            cnt = 1  # 初始化受力时间
            for j in range(i - 1, -1, -1):
                if data[j] == '.':
                    final_state[j] -= 1  # 向左倒的影响
                    time_l[j] = cnt  # 记录向左倒的受力时间
                    cnt += 1
                else:
                    break  # 遇到其他骨牌终止影响
​
    # 找出保持竖立的骨牌
    result = []
    for i in range(num):
        if final_state[i] == 0 and time_l[i] == time_r[i]:  # 确保向左和向右的受力时间相等
            result.append(i + 1)  # 1-based index
​
    # 如果没有竖立的骨牌,返回 "0"
    if len(result) == 0:
        return "0"
​
    # 格式化输出
    result_str = f"{len(result)}:" + ",".join(map(str, result))
    return result_str
​
​
if __name__ == "__main__":
    # 测试用例
    print(solution(14, ".L.R...LR..L..")
​
 == "4:3,6,13,14")  # 应输出 True
    print(solution(5, "R....") == "0")  # 应输出 True
    print(solution(1, ".") == "1:1")  # 应输出 True