python刷题记录-不定时更新

本文精选了多项Python算法挑战,涵盖奖牌榜排序、容器操作、数字处理、比赛晋级规则、连续数字求和等典型问题,提供了清晰的思路解析与高效代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

   0. 前言
   1. Olympic Game
   2. Push Pop
   3. 相反数
   4. Advance Next Round
   5. Consecutive number
   6. 被选召的孩子
   7. 单词的压缩编码
   8. 爱吃香蕉的珂珂
   9. 和为k的最长子数组的长度
   10. N进制小数

0. 前言

回到顶部👆

   python刷题记录-训练思维
注:题目来源多为leetcode


1. Olympic Game

回到顶部👆

题目描述:
2012伦敦奥运会即将到来,大家都非常关注奖牌榜的情况,现在我们假设奖牌榜的排名规则如下:
1、首先gold medal数量多的排在前面;
2、其次silver medal数量多的排在前面;
3、然后bronze medal数量多的排在前面;
4、若以上三个条件仍无法区分名次,则以国家名称的字典序排定。
我们假设国家名称不超过20个字符、各种奖牌数不超过100,且大于等于0。

解答要求:
   时间限制:1000ms, 内存限制:64MB

输入:
   第一行输入一个整数N(0<N<21),代表国家数量;
   然后接下来的N行,每行包含一个字符串Namei表示每个国家的名称,和三个整数Gi、Si、Bi表示每个获得的gold medal、silver medal、bronze medal的数量,以空格隔开,如(China 51 20 21),具体见样例输入。

输出:
   输出奖牌榜的依次顺序,只输出国家名称,各占一行,具体见样例输出。

样例:
输入:

5
China 32 28 34
England 12 34 22
France 23 33 2
Japan 12 34 22
Russia 23 43 0

输出:

China
Russia
France
England
Japan

思路:
   首先我们要注意题目中对奖牌数的排序和对国家名称的排序是不一样的,对奖牌数是从大到小,对国家名称是按照字典序排列的(可以理解为从小到大),为了便于进行排序,我们可以将奖牌数前面增加一个负号,这样使两个排序的元素都从小到大,具体Python代码如下:

# 使用sorted
para = {}
# 国家数
n = int(input().strip())
for line in range(n):
    # 每一行数据
    data = input().split(' ')
    # 组装数据结构para={'China': [], 'Russia': []}
    para[data[0]] = [int('-' + i) for i in data[1:]]
# 开始排序(x[1]代表奖牌数目, x[0]代表国家)
new_para = sorted(para.items(), key=lambda x: (x[1], x[0]))
for i in new_para:
    print(i[0])

   看到另一种解法如下:

# 国家数
n = int(input())
# 组装数据结构info=[[], [], [], [], []]
info = []
for i in range(n):
    str = input()
    info.append(str.split())
# 按国家首字母排序
info.sort(key=lambda x: x[0])
# 按铜牌数量排序
info.sort(key=lambda x: int(x[3]), reverse=True)
# 按银牌数量排序
info.sort(key=lambda x: int(x[2]), reverse=True)
# 按金牌数量排序
info.sort(key=lambda x: int(x[1]), reverse=True)

for i in info:
    print(info[i][0])

2. Push Pop

回到顶部👆

题目描述:
   设计一个容器,对容器可以有两种操作,push(放入),pop(取出)。
   push M: 将整数M放入容器.
   pop M: 在容器中找到不超过M的最大正整数,将其pop(取出),如果不存在这样的数则不操作.

输入:
   第一行是一个数字N(1 <= N <= 100000),接下来N行,每行包含一个单词push或pop,以及一个数字M;push表示push操作,pop表示pop操作,输入文件中所有数字均在32位范围内并且是正整数。

输出:
   对于pop操作,输出一个整数,表示满足条件的数字,如果不存在这样的数字能够被取出,也输出"No Element!"

样例:
输入:

9
push 10
push 20
pop 2
pop 10
push 5
push 2
pop 10
pop 11
pop 19

输出:

No Element!
10
5
2
No Element!

思路:

   使用python内置的bisect操作(前提列表有序)
1.将所有的push操作全部插入列表
2.碰到是pop操作,如果列表为空或者第一个元素大于要操作的数字,那么肯定是没有的删除的;否则就去找到改数字在列表中的位置,然后删除这个位置的前一个位置的数字即可。

注解:

   bisect.insort: 插入数字到相应位置,会按大小插入;
   bisect.bisect: 并不真正插入原始列表,而是返回将要插入的列表下标;

解答:

import bisect

def func():
    l = []
    n = int(input())
    for i in range(n):
        line = input()
        num = int(line.strip().split()[1])
        if line.startswith('push'):
            bisect.insort(l, num)
        else:
            if not l or l[0] > num:
                print('No Element')
                continue
            index = bisect.bisect(l, num)
            print(l[index])
            l.pop(index)

3. 相反数

回到顶部👆

题目描述:
   有 N 个非零且各不相同的整数。请你编一个程序求出它们中有多少对相反数(a 和 -a 为一对相反数)。
输入格式:
  第一行包含一个正整数 N。(1 ≤ N ≤ 500)。
  第二行为 N 个用单个空格隔开的非零整数,每个数的绝对值不超过1000,保证这些整数各不相同。
输出格式:
  只输出一个整数,即这 N 个数中包含多少对相反数。
  
样例输入:
5
1 2 3 -1 -2
样例输出:
2

思路:
   将数据全部转化为正整数,放入集合,然后用原数据个数-集合元素个数即可

解答:

num = int(input())
set_len = len(set(map(lambda x: abs(x), map(int, input().strip().split()))))
print(num - set_len)

4. Advance Next Round

回到顶部👆

题目描述:
   有一个比赛,晋级下一轮的规则是:“参赛者如果得分大于0且不小于排名第K的参赛者的得分,将晋级下一轮!”
   现在已知有n名参赛者(n≥k),以及他们各自的得分,现在你需要计算将有多少人晋级下一轮。

输入:
输入的第一行包含两个整数n和k(1≤k≤n≤50),一空格分开。
第二行包含n个用空格分开的整数Ai(0≤Ai≤100),表示排名第i的参赛者的得分。其中对任意的i满足Ai≥Ai+1。

输出:
输出将有多少人晋级下一轮。

样例:
输入样例

8 5
10 9 8 7 7 7 5 5

输出样例 1

6

解答:

n, k = map(int, input().strip().split())
score = list(map(int, input().strip().split()))
# 第k名得分
k_score = score[k-1] if score[k-1] != 0 else 1
print(len([i for i in score if i >= k_score]))

5. Consecutive number

回到顶部👆

题目描述:
  一个正整数有可能可以被表示为 n(n>=2) 个连续正整数之和,如:

15=1+2+3+4+5
15=4+5+6
15=7+8

请编写程序,根据输入的任何一个正整数,找出符合这种要求的所有连续正整数序列。

输入数据:
  一个正整数,以命令行参数的形式提供给程序。

输出数据:
  在标准输出上打出执行结果[能分解成连续数目相加则输出YES,否则NO]。

样例:
输入样例

15

输出样例

YES

思路:

1.奇数: 任意一个奇数(n>1) n = (n-1)/2 + (n+1)/2,所以奇数必然可以写成连续数
2.偶数: 可以看成是奇数n的倍数,M=n2^k(n为奇数且n>1),M序列为在n序列两端不停的+1-1,消去对应的正负项即可。
例:
7 = 7 * 2^0: 3 4
14 = 7 * 2
1 2 3 4 5
28 = 7 * 2^2 0 1 2 3 4 5 6 7
56 = 7 * 2^4 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 消除完变成 5 6 7 8 9 10 11

综合得出: 目标数字能够除以2,最终是奇数(除了1)都可以拆分
所以,判断输入是否为2的n次方就可以了

解答:

def func():
    n = int(input().strip())
    while n >= 2:
        if n % 2 != 0:
            print('YES')
            break
        n /= 2
    if n == 1:
        print('NO')
        
if __name__ == '__main__':
    func()

6. 被选召的孩子

回到顶部👆

题目描述:
  小华和他的小伙伴们想参加一个游戏,但是参加的人很多,主办方需要筛选,规则如下:
  n个孩子从左到右站成一排,每个孩子都有一个分数(分数为正整数),要求所选出的孩子们必须是连续的一段,而且所选出的孩子的分数的平均值必须大于等于预先给定的一个常数b,但是这样选择的方法可能并不唯一,请问有多少种选法?

输入:
第一行:输入候选孩子的个数n(1<=n<=20000)和给定的常数b(1<=b<=500)
第二行:输入n个孩子的分数Xi(i=1,2,…)且1<=Xi<=500,用空格隔开

输出:
输出选择的种数

样例:
输入

5 9
32 4 9 21 10

输出

13

思路:

由于被选中的孩子必须是连续的一段,所以相当于列表子集求和大于平均分数b的个数,类似下面这样(样例):
选1个孩子:[32] [4] [9] [21] [10]
选2个孩子:[32, 4] [4, 9] [9, 21] [21, 10]
选3个孩子:[32, 4, 9] [4, 9, 21] [9, 21, 10]
选4个孩子:[32, 4, 9, 21] [4, 9, 21, 10]
选5个孩子:[32, 4, 9, 21, 10]
在这些选法中选择和大于平均分9的有13种

解答:

def func():
    c = 0
    n, avg_score = map(int, input().strip().split())
    score_list = []
    for i in range(n):
        score_list.append(int(input().strip()))
    for i in range(1, n+1):
        for j in range(n-i+1):
            if sum(score_list[j:i+j]) / i >= avg_score:
                c += 1
    print(c)

if __name__ == '__main__':
    func()

7. 单词的压缩编码

回到顶部👆

题目描述:
  给定一个单词列表,我们将这个列表编码成一个索引字符串 S 与一个索引列表 A。例如,如果这个列表是 [“time”, “me”, “bell”],我们就可以将其表示为 S = “time#bell#” 和 indexes = [0, 2, 5]。
  对于每一个索引,我们可以通过从字符串 S 中索引的位置开始读取字符串,直到 “#” 结束,来恢复我们之前的单词列表。那么成功对给定单词列表进行编码的最小字符串长度是多少呢?
条件:

1 <= words.length <= 2000
1 <= words[i].length <= 7
每个单词都是小写字母

样例:
输入:

words = [“time”, “me”, “bell”]

输出:

10
说明: S = “time#bell#” , indexes = [0, 2, 5]

思路:

  由题所知,短的字符串被包裹在长字符串内,所以可以先将列表字符串排序(由短到长),定义空字符串s,然后倒序遍历字符串列表,通过str的find方法在s中查找每个字符串,如果不存在,则追加到s,如果存在,则判断返回下标到第一个#号之间的字符串是否等于遍历出的即可。(str的find:找到返回下标,未找到则返回-1)

解答:

class Solution:
    def minimumLengthEncoding(self, words: List[str]) -> int:
    	# 列表中字符串排序(短->长)
        words.sort(key=lambda x: len(x))
        # 最终输出字符串
        s = ""
        for i in range(len(words) - 1, -1, -1):
        	# 在s中查找i
            fs = s.find(words[i])
            if fs == -1:
            	# 不存在则添加到s
                s += words[i] + "#"
            else:
            	# 存在则获得第一个#号的下标
                x = s[fs:].index("#")
                if s[fs: fs + x] != words[i]:
                    s += words[i] + "#"
        return len(s)

8. 爱吃香蕉的珂珂

回到顶部👆

题目描述:
  珂珂喜欢吃香蕉。这里有 N 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 H 小时后回来。
  珂珂可以决定她吃香蕉的速度 K (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 K 根。如果这堆香蕉少于 K 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。
  珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。返回她可以在 H 小时内吃掉所有香蕉的最小速度 K(K 为整数)。

样例1:

输入: piles = [3,6,7,11], H = 8
输出: 4

样例2:

输入: piles = [30,11,23,4,20], H = 5
输出: 30

样例3:

输入: piles = [30,11,23,4,20], H = 6
输出: 23

思路:
  1、根据题意可以推断出珂珂吃香蕉的数据k的范围为[sum(piles) / H, max(piles) + 1];
  2、遍历上述范围的k,利用math函数的ceil统计出吃每一堆香蕉花的时间,并累计(math.ceil(5/2) = 3);
  3、将花费时间和与H对比,一旦小于H则停止遍历并输出k;
解答:

import math

class Solution:
    def minEatingSpeed(self, piles: List[int], H: int) -> int:
    	# 吃所有香蕉平均速度
        i = math.ceil(sum(piles) / H)
        for k in range(i, max(piles) + 1):
        	# 总花费时间求和后与H比较
            if sum(math.ceil(pile / k) for pile in piles) <= H:
                return k

9. 和为k的最长子数组的长度

回到顶部👆

题目描述:
  给定一个数组 nums 和一个目标值 k,找到和等于 k 的最长子数组长度。如果不存在任意一个符合要求的子数组,则返回 0。

注意:
nums 数组的总和是一定在 32 位有符号整数范围之内的

示例 1:

输入: nums = [1, -1, 5, -2, 3], k = 3
输出: 4
解释: 子数组 [1, -1, 5, -2] 和等于 3,且长度最长

示例 2:

输入: nums = [-2, -1, 2, 1], k = 1
输出: 2
解释: 子数组 [-1, 2] 和等于 1,且长度最长

思路:
解答:


10. N进制小数

回到顶部👆

题目描述:
   将任意十进制正小数分别转换成2,3,4,5,6,7,8,9进制正小数,小数点后保留10位,并输出。

输入:
   输入包含两个数m, n,用空格隔开。并且当m, n均为0时输入结束。

limits:
0.0000009 < m < 1
1 < n < 10

输出:
   输出10进制正小数m的n进制小数,结果保留10位小数。

样例:

若十进制小数为0.795,则输出:
十进制正小数 0.795000 转换成 2 进制数为: 0.11001011
十进制正小数 0.795000 转换成 3 进制数为: 0.21011011
十进制正小数 0.795000 转换成 4 进制数为: 0.30232011
十进制正小数 0.795000 转换成 5 进制数为: 0.34414141
十进制正小数 0.795000 转换成 6 进制数为: 0.44341530
十进制正小数 0.795000 转换成 7 进制数为: 0.53645364
十进制正小数 0.795000 转换成 8 进制数为: 0.62702436
十进制正小数 0.795000 转换成 9 进制数为: 0.71348853

思路:

1.先定义一个字符串s=‘0.’;
2.然后用给定数m*n,将结果的整数部分追加到s;小数部分继续上述操作;
3.10次后输出s即为结果;

解答:

def func():
    while True:
        m, n = input().strip().split()
        m = float(m)
        n = int(n)
        s = '0.'
        if m == n == 0:
            break
        for i in range(10):
            s += str(int(m * n))
            m = m * n - int(m * n)
        print(s)

if __name__ == '__main__':
    func()

进制操作参考: python进制相互转换-整数与小数


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值