leetcode302场周赛复盘

第一次做竞赛的题,只做了两道半,下面整理下思路
2341. 数组能形成多少数对
在这里插入图片描述
在这里插入图片描述

主要思路:
第一步:看约束条件

  1. 题目中给出整个数组的大小为100,其中数字的范围也是[1,100],这表明可以穷举出现的数字。

第二步:看题目内容

  1. 题目要求按对消除相同元素,我首先想到的是去除重复元素就行。但是如果重复元素的个数是奇数,那么还需要保留一个。因此思路就过渡到统计各个数字出现的次数上了。统计结束后,如果数字出现次数除2为零,需要移去个数加上这个次数;如果不为零,剩下元素的个数加一。

第三步:写代码

class Solution:
    def numberOfPairs(self, nums: List[int]) -> List[int]:
        res1,res2=0,0
        ls=[0]*101
        for i in nums:
                ls[i]+=1
        for i in ls:
            res1=res1+(i//2)
            res2=res2+(i%2)
        return [res1,res2]        

2342. 数位和相等数对的最大和
在这里插入图片描述
在这里插入图片描述主要思路:
第一步:看约束条件
范围很大要考虑溢出问题。int最大2147483647 大概 2 ∗ 1 0 9 2*10^9 2109
第二步:看题目内容

  1. 题目要求统计数字各位和相同的数字的最大和。首先就要求出各个数字的位数和是多少,然后判断有没有相同的位数和,如果有就加起来和最大的比较。最后返回最大和。
  2. 统计相同元素,最好的办法应该用桶排序的思想(像第一题),但是由于数字太大,而且稀疏,因此使用字典的方法会更好。
  3. 首先,定义一个字典,键为数字位数和的字符格式,值为真实值。然后遍历nums,如果数字的位数和不在字典中,就加入字典。如果存在就拿真实值和字典中的值相加,判断是否是最大和(此处需要定一个当前最大和用于比较),同时在字典中保留两个相同值中最大的一个,以保证后续还有相同值出现时,加和是最大的。

第三步:写代码

class Solution:
    def maximumSum(self, nums: List[int]) -> int:
        dic={}
        res=-1
        for i in nums:
            tmp=sum([int(k) for k in list(str(i))])
            if str(tmp) in dic:
                res=max(res,dic[str(tmp)]+i)
                dic[str(tmp)]=max(dic[str(tmp)],i)  
            else:
                dic[str(tmp)]=i
        return res
        

2343. 裁剪数字后查询第 K 小的数字
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述主要思路:
第一步:看约束条件
列表中字符串的最大长度是100,超过了整型的记录范围
裁截的位置 t r i m i trim_i trimi 在字符的长度内
位置的选取 k i k_i ki在列表的长素内
有了这些条件就知道问题的边界在哪里了
第二步:看题目内容

  1. 题目要求出裁剪后第k小的数字的原始位置。这个就设计到一个原始位置的问题。
  2. 注意分析题目的特殊情况,如果出现重复的数字,默认原始位置索引小的,值更小。如下表所示,此处1号位置上的2小于4号位置上的2。排序之后顺序变为【1,2,2,3,4】如果返回第3小的数的原始位置,应该返回的是4。所以单使用list.index()是没办法找到重复元素的真实位置的。因此不能使用排序函数直接对数组进行排序,应该记录位置,只对位置进行排序。
索引01234
12342
  1. 了解完前提条件之后,这个题目类似于基数排序。裁剪的位数就是基数排序迭代的次数。
    因此定义一个桶大小为 [ 0 − 9 ] [0-9] [09]。另外因此定一个数组loc记录每次排序的位置, l o c [ i ] [ j ] loc[i][j] loc[i][j] ,表示裁切长度为i时,第j小的数字的原始位置

  2. 首先初始化位置,将当前位置写入 l o c [ 0 ] [ : ] loc[0][:] loc[0][:]

  3. 然后取所有元素的最后一位放入对应的桶中,然后按0-9的顺序重新排列数组,这里只记录排序后的数序写入 l o c [ 1 ] [ : ] loc[1][:] loc[1][:]。以上表为例,那么loc的构成为

loc[0]01234
原始值12342
loc[1]01423
排序后值12234

如果裁切为[1,1] 那么就是取 l o c [ 1 ] [ 1 − 1 ] loc[1][1-1] loc[1][11] 也就是0

第三步:写代码

class Solution:
    def smallestTrimmedNumbers(self, nums: List[str], queries: List[List[int]]) -> List[int]:
        n = len(nums)
        m = len(nums[0])
        # vecs[i][j] 表示基数排序第 i 轮中第 j 小的数对应的下标
        vecs=[[i for i in range(0,n)]]

        for  i in range(1,m+1):
            B={}
            for ele in range(10):
                B[str(ele)]=[]

             # 把第 i - 1 轮的结果,根据 nums 中右数第 i 位数,依次放入桶中
            for x in  vecs[i - 1]:
                B[nums[x][m - i]].append(x);
             # 把每个桶的结果连接起来,成为第 i 轮的结果
            tmp=[]
            for j in range(10):
                for  x in  B[str(j)]:
                    tmp.append(x)
            vecs.append(tmp)


        ans=[]
        for q in  queries:
            ans.append(vecs[q[1]][q[0] - 1])
        return ans

在这里插入图片描述
2344. 使数组可以被整除的最少删除次数
在这里插入图片描述
在这里插入图片描述
主要思路:
第一步:看约束条件

  1. 题目中的约束条件,除数和被除数都很大,可能会超时

第二步:看题目内容

  1. 题目要求返回可以被numsDivide数组整除的nums中最小元素,最直接的思路就是选择nums中最小的元素,如果可以被整除,那么就返回该值。如果不能被整除,那么就删除该元素,继续重复上述步骤,代码如下
class Solution:
    def minOperations(self, nums: List[int], numsDivide: List[int]) -> int:
        count=0
        while len(nums)>0:
            su=0
            k=min(nums)
            for i in numsDivide:
                su+=(i%k)
            if su==0:
                return count
            nums.remove(k)
            count+=1
        return -1     

但是如果数据量非常大时,就会超时。
2. 换个思路,如果某个数字可以被numsDivide整除,那么也可以被他们的最大公约数整除。因此,先求numsDivide的最大公约数,将遍历numsDivide数组转化为仅除最大公约数。
3. 然后遍历一遍数组,找到所有可以被最大公约数整除的数,求他们的最小值记为mn。如果mn为0,那么就返回-1。否则统计nums中小于mn的数量,即需要删除的元素数量。

第三步:写代码

class Solution:
    def minOperations(self, nums: List[int], numsDivide: List[int]) -> int:
        g=gcd(*numsDivide)
        mn=min([x for x in nums if g%x==0 ], default=0)
        if mn==0:
 			return -1
        return sum([ x< mn for x in nums]) 

补充下python中" * "的用法(参考原文
1.单星号 * 用于取出列表list或元组tuple中的元素。
单星号 * 只能读取到字典中的键(key)。

a = [1,2]
print(*a)
# 输出 1 2

2.用于收集列表中多余的值,收集的是列表。

a,b,*l=[2,3,4,5]
print(a) # 2
print(b) # 3
print(l) # l是列表 [4,5] 

3.在函数中,*代表收集参数,将收集的参数放在一个元组tuple里面。

def printFunc(x,*para):
    print(x)
    print(para)
printFunc(1,2,3)
# 输出
# 1
# (2, 3)
printFunc(x = 1,2,3,4) #报错
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值