CSDN 周赛 50 期题目详解

本文介绍了CSDN的一场编程竞赛,涉及订班服问题、异或和计算、零钱兑换的动态规划解决以及寻找最长回文串的策略。作者分享了针对这些算法题目的解决方案,并反思了自己的参赛经验。
摘要由CSDN通过智能技术生成

写在前面

        我听说CSDN有比赛,我就来了,啪的一声很快啊,上来就是一个 50 期周赛。一个订班服,一个异或和,左一个零钱兑换,右一个小艺照镜子。啊,训练有素,看来是有备而来!一套闪电五连鞭,一下就写完了。100分,传统算法点到为止。

CSDN 编程竞赛五十期:比赛详情 (csdn.net)

 

1、题目名称:订班服

小A班级订班服了! 可是小A是个小糊涂鬼,整错了好多人的衣服的大小。 小A只能自己掏钱包来补钱了。 小A想知道自己至少需要买多少件衣服。

这题就是比对两个列表的差异性额外购买的衣服数量

如果该衣服大小没有被订购,需要补的衣服数量加1,如果该衣服大小已经被订购,那么从已经订购的衣服列表中删除该衣服大小

def solution(n, arr1, arr2):
    res = 0
    add = 0
    if n > len(arr2):
        add = n - len(arr2)
        for i in arr1:
            if i not in arr2:
                res += 1
            else:
                arr2.remove(i)
    return res + add

2、题目名称:异或和

小张找到了一个整数 N,他想问问你从 1 到 N 的所有不同整数的异或和是多少, 请你回答他的问题。

 这题没什么好说的,^ 是异或,直接1到n异或和到底就可以了

def solution(N):
    result = 0
    for i in range(1, N + 1):
        result ^= i
        return result

3、题目名称:零钱兑换

给定数组arr,arr中所有的值都为正整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给 定一个aim,代表要找的钱数,求组成aim的最少货币数。 如果无解,请返回-1. 数据范围:数组大小满足 0 <= n <=10000 , 数组中每个数字都满足 0 < val <=10000,0 <= aim <=100000 要求:时间复杂度 O(n×aim) ,空 间复杂度 O(aim)。

 这题是这里面最难的,我采用的是动态规划,想了好久。第一次参加CSDN的比赛,还在数据格式输入卡了一会。

    def solution(str1):
        arr, aim = eval(str1)
        if aim == 0:
            return 0
        dp = [-1] * (aim + 1)
        dp[0] = 0
        for i in range(1, aim + 1):
            for j in arr:
                if j <= i and dp[i - j] != -1:
                    if dp[i] == -1:
                        dp[i] = dp[i - j] + 1
                    else:
                        dp[i] = min(dp[i], dp[i - j] + 1)
        return dp[aim]

最少货币数问题有点类似爬楼梯的题目。具体来说,它通过构建一个长度为aim+1的dp数组,其中dp[i]表示组成金额i所需的最少货币数,然后通过遍历数组arr和dp数组来更新dp数组的值,最终返回dp[aim]即可。

4、题目名称:小艺照镜子

已知字符串str。 输出字符串str中最长回文串的长度。

 回文数写过很多次了,这次题我想了比较偏门的解法:对于一个回文串,它的中心可能是一个字符,也可能是两个相邻的字符的中间位置,因此我们可以枚举回文串的中心位置,然后向两边扩散,判断是否是回文串

初始化 p 数组,用于记录以每个字符为中心的最长回文半径

def solution(s):
    new_str = '#' + '#'.join(s) + '#'
    n = len(new_str)
    p = [0] * n
    id = mx = res_id = res_mx = 0
    for i in range(n):
        p[i] = min(p[2 * i - i], mx - i) if mx > i else 1
        while i - p[i] >= 0 and i + p[i] < n and new_str[i - p[i]] == new_str[i + p[i]]:
            p[i] += 1
        if mx < i + p[i]:
            mx, id = i + p[i], i
        if p[i] > res_mx:
            res_mx, res_id = p[i], i
    return res_mx - 1

为什么要把每个字符都用#给包围,这个当时的想法的话是把每个字符长度都限定在奇数,无论是奇数的长度的字符还是偶数的长度的字符,都统一转化为奇数长度,然后用p 数组,用于记录以每个字符为中心的最长回文半径

如果 i 在 mx 的左边,那么可以利用对称性,将 i 的回文半径初始化为 i 关于 id 的对称点 j 的回文半径,如果 i 在 mx 的右边,那么只能暴力匹配

这道题当时写魔怔了,思路差不多是这个意思,问了一下GPT,给了个更好的方式

 总结

第一次参加CSDN的比赛,还需要多磨炼磨炼

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值