ccf历年第二题满分python代码及知识点总结(2013-2022)

201312-2ISBN号码

思路:

就是简单的字符串处理,没有什么好说的。

代码:

str_input = input()
s = str_input.replace("-", "")
sum_value = 0
start = 1
for i in range(len(s)-1):
    sum_value += int(s[i]) * start
    start += 1
last = sum_value % 11
if (last != 0 and s[-1] == str(last)) or (last == 10 and s[-1] == 'X'):
    print("Right")
else:
    print(str_input[:-1] + str(last) if last != 10 else str_input[:-1] + 'X')

知识点

就是字符串处理吧,一些替换啊,切片啊,拼接啊,很基础的知识点。

201403-2窗口*

思路

我这思路很清晰,完全没有问题啊,为啥时隔那么久再刷竟然是70分!

就是在每个窗口前面加上两个数,第一个数change_order表示这个窗口现在的顺序,第二个数order表示窗口本来的序号,整个过程不变。

在对每个点遍历的时候,先对窗口排序,逆序判断当前点在不在这个窗口,因为是逆序,所以在的话肯定是上面的窗口,跳出循环,把窗口的本来的序号order加到结果集中,并保存当前窗口first的change_order。如果点不在所有的窗口中,就把"IGNORED"加到结果集中。

遍历窗口,为了让点击所在窗口first为顶层窗口,其他窗口相对顺序不变,如果当前窗口的change_order大于本来first窗口的change_order,那么就-1,本来就比其小的不改变。最后把first窗口的change_order改为最大的值,即N,变成了顶层窗口。

再对下一个点进行循环判断。

这哪里有问题?测试几个样例完全没问题啊。

也许是时间复杂度的问题?因为这样的思路在外层for循环下每次都要排序,时间复杂度是O(n2logn)。

于是就改变一下思路,用一个字典,key是窗口坐标,value是序号。然后对每个点判断的时候,把遇到的窗口加到所有窗口后面,然后把这个窗口出现在第一个的给删掉。

代码:

N, M = map(int, input().split())
windows = []
windows_order = {
   }
points = []
for i in range(N):
    bounds = list(map(int, input().split()))
    windows.append(bounds)
    windows_order[tuple(bounds)] = i + 1
for j in range(M):
    points.append(list(map(int, input().split())))
# 对每次点击存放一次结果
for i in range(M):
    x, y = points[i][0], points[i][1]
    order = 0
    flag = 1
    for j in range(N-1, -1, -1):
        left_x, left_y = windows[j][0], windows[j][1]
        right_x, right_y = windows[j][2], windows[j][3]
        if left_x <= x <= right_x and left_y <= y <= right_y:
            print(windows_order[tuple(windows[j])])
            windows.append(windows[j])
            windows.remove(windows[j])
            flag = 0
            break
    if flag:
        print("IGNORED")

知识点

这题考察的就是逻辑思维和字典(学霸用的链表),其中列表是不可哈希对象,因为列表是可变的数据类型,所以在创建字典的时候key值用的是元组。怎么去模拟窗口的位置变换,就是把新的顶部窗口加到列表最后面,然后把之前的删除就行。

在和学霸讨论这题的时候,涉及到一些知识点,顺便巩固一下。查看对象的内存地址用id(),顺序列表中的存储空间是连续的。列表的每个元素都有自己的内存地址空间,但是这个列表的内存地址空间和列表第一个元素的地址空间是不一样的。

在这里插入图片描述

201409-2画图

思路1
因为1<=n<=100,0<=横坐标、纵坐标<=100。就先创建一个100*100的列表,然后遍历每个矩形坐标,遍历到的就把其赋值为1,最后判断列表中有多少个1即可。

代码1

n = int(input())
rec = []
for i in range(n):
    rec.append(list(map(int, input().split())))
paper = [[0] * 100 for _ in range(100)]
for i in range(n):
    leftx, lefty, rightx, righty = rec[i][0], rec[i][1], rec[i][2], rec[i][3]
    for x in range(leftx, rightx):
        for y in range(lefty, righty):
            paper[x][y] = 1
rec_cur = sum(paper, [])
print(rec_cur.count(1))

思路2
直接用集合,遍历矩阵,因为集合自动去重,所以最后返回集合的长度即可。

代码2

n = int(input())
rec = []
for i in range(n):
    rec.append(list(map(int, input().split())))
ans = set()
for i in range(n):
    leftx, lefty, rightx, righty = rec[i][0], rec[i][1], rec[i][2], rec[i][3]
    for x in range(leftx, rightx):
        for y in range(lefty, righty):
            ans.add((x, y))
print(len(ans))

知识点
纯逻辑吧,没什么知识点。第一个代码中用到sum(paper,[])是把二维列表转为一维列表,代码2中用到的是集合的自动去重。

201412-2 Z字形扫描

思路

这题也不涉及什么算法,就是找规律。也是想了一会调试了一会才通过的。

在上半个走位(包括对角线),添加的值的坐标有这样的规律:

如果坐标x、y之和为偶数,如2,就(2,0)(1,1)(0,2),x一直在减小,y一直在增大。如果是奇数,如3,就(0,3)(1,2)(2,1)(3,0),x一直在增大,y一直在减少。

在下半个走位,添加的值的坐标有这样的规律:

如果坐标x、y之和为偶数,如4,就(3,1)(2,2)(1,3),x一直在减小,y一直在增大。如果是奇数,如5,就(2,3)(3,2),x一直在增大,y一直在减少。注意一下x、y的边界。

代码:

n = int(input())
nums = []
for i in range(n):
    nums.append(list(map(int, input().split())))
res = []
for i in range(n):
    if i % 2:
        for j in range(i+1):
            res.append(nums[j][i-j])
    else:
        for j in range(i+1):
            res.append(nums[i-j][j])
for i in range(n, (n-1)*2+1):
    if i % 2:
        for j in range(i-n+1, n):
            res.append(nums[j][i-j])
    else:
        for j in range(i-n+1, n):
            res.append(nums[i-j][j])
for k in res:
    print(k, end=" ")

201503-2数字排序

思路
用字典得到每个数出现的次数,key是这个数,value是出现次数,然后排序。先value从大到小,然后key从小到大。

代码:

import collections
n = int(input())
nums = list(map(int, input().split()))
dic = collections.Counter(nums)
dic = sorted(dic.items(),  key=lambda x: (-x[1], x[0]))
for k in dic:
    print(k[0], k[1])

知识点:
字典。这里面用到了字典的排序,这个写法还是蛮有趣的。

201509-2日期计算

思路:
好像没什么好说的。上代码。

代码:

y = int(input())
d = int(input())
month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
if y % 400 == 0 or (y % 4 == 0 and y % 100 != 0):
    month[1] = 29
cur_day = 0
for i in range(12):
    cur_day += month[i]
    if cur_day >= d:
        print(i+1)
        print(d-(cur_day-month[i]))
        break

201512-2消除类游戏

思路:
先对每一行判断,把符合要求的坐标加到集合中;再对每一列判断,把符合要求的坐标加到集合中。然后把集合中所有的坐标上的元素赋值为0。

代码:

n, m = map(int, input().split())
games = []
for i in range(n):
    games.append(list(map(int, input().split())))
zeros = set()
# 判断每行
for i in range(n):
    for j in range(m-2):
        if games[i][j] == games[i][j+1] == games[i][j+2]:
            zeros.update([(i, j), (i, j + 1), (i, j + 2)])
# 判断每列
for j in range(m):
    for i in range(n-2):
        if games[i][j] == games[i+1][j] == games[i+2][j]:
            zeros.update([(i, j), (i + 1, j), (i + 2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值