力扣第288场周赛(前三题)Python题解

目录

?按奇偶性交换后的最大数字?

1 题目

2 分析和讲解

 3 淬不及防的知识点

 ?向表达式添加括号后的最小结果?

1 题目

 2 分析和讲解

 3 淬不及防的知识点 

?K 次增加后的最大乘积?

1 题目

​2 分析和讲解 

3 淬不及防的知识点 

?按奇偶性交换后的最大数字?

1 题目

 

2 分析和讲解

 方法一:就是在原本的列表上进行操作,当然先要转化为列表,其中每个元素是int。使用双指针,i 前—>后,j 后—>前,找到奇偶性相同的且 前者小于后者的进行交换

class Solution:
    def largestInteger(self, num: int):
        alist=[int(i) for i in str(num)]
        for i in range(len(alist)-1):
            for j in range(len(alist)-1,i,-1):
                if not (alist[j]-alist[i])&1 and alist[i]<alist[j]:
                    alist[i],alist[j]=alist[j],alist[i]
        blist=[str(i) for i in alist]
        return(int(''.join(blist)))

双层遍历的第一层,每次选择一个位置 alist[i],使得内层遍历结束后该位置是与其奇偶性相同的所有数当中最大的(有点类似冒泡,不过冒泡是相邻两个数交换,而这个是:放置最大数的位置确定,只需要将该位置上的数与所有能与其竞争并且击败它的数交换,也就是奇偶性相同且比它大,当 j 遍历到 i 的后一个位置时结束,至此该位置被最终确定)

方法二:较为直观,既然只能对应交换奇偶性相同的数,就将奇数和偶数分开,排个序,遇到能放奇数的放最大的奇数,遇到能放偶数的同理

class Solution:
    def largestInteger(self, num: int):
        s=str(num)
        s1=[]
        s2=[]
        n=len(s)
        for i in s:
            if int(i)&1:
                s1.append(i)
            else:
                s2.append(i)
        s1.sort()
        s2.sort()
        s3=''
        for i in s:
            if int(i)&1:
                s3+=s1.pop()
            else:
                s3+=s2.pop()
        return(int(s3))

将奇数和偶数分开排序简单,关键是如何判断什么时候能放奇数或者偶数呢?很简单,再次判断原列表,若为奇数就放最大的奇数,并在下次放奇数时选择除了已放过奇数剩余的最大奇数,这里有两种方法,看知识点部分

 3 淬不及防的知识点

(1)貌似力扣在下面代码输入时会报错(在VScode中就不会),换个名字就好了

 (2)将列表排序,每次选择最大值,下次选择次大值,以此类推,两种方法

? s.sort()  s.pop() 默认去除最后一个元素的值并返回该值,恰巧最后一个值就是最大值

?s.sort(reverse=True)  设置一个指针i 初始i=0 每次取走s[i] 之后i+=1  

 ?向表达式添加括号后的最小结果?

1 题目

 

 

 2 分析和讲解

方法:大差不差就是两层遍历,左和右括号能插入的位置,计算此时的数值得到最小的输出,但是实现细节上我与大佬有那么一(亿)点差距:

(1)分割两加数:我先求出加号的下标,再求左和右加数的长度,然后再拼接起来,然而大佬一行搞定

a, b = expression.split('+')

(2)中间遍历:有四个数,大佬的分别是 time1,time2,v1,v2,我的是k1,k2,k3,k4,我由于最开始将两加数变成整数,就用

k1,k2=divmod(left_num,10**(left-i))

上行代码求了,由于第一个数和第四个数比较特殊,因为在分割时会出现空的情况,故我用下面代码判断

if i==0:
    k1=1
    k2=left_num
else:
    k1,k2=divmod(left_num,10**(left-i))

大佬用的是字符串拼接的方式,切片的方式有些巧妙,这点差别并没有什么,

time1 = 1 if i == 0 else int(a[:i])
time2 = 1 if j == 0 else int(b[-j:])

但是到最后输出时,由于比如当第一个数在分割时为空时会被赋值为1,在输出时不会显示的,于是我最开始就判断这个数是否为1,如果为1,就设置为空,但会出现实例二的情况

expression='12+34'
print('1(2+3)4')

求得的最小值中第一个数就是1,一番周折后设置不仅这个数为1,而且要有第二个数长度等于总长度(相当于左加数全部给了第二个数),才会被设置为空,如下

if j1==1 and len(str(j2))==left:
    j1=''

而大佬提前储存了这个特殊数的最后输出结果

time1 = 1 if i == 0 else int(a[:i])
s1 = str(time1) if not i == 0 else ''

这就是区别。

下面为大佬和菜鸡的代码

大佬的代码

class Solution:
    def minimizeResult(self, expression: str):
        a, b = expression.split('+')
        v = 1e99
        to_ret = None
        for i in range(len(a)) :
            time1 = 1 if i == 0 else int(a[:i])
            s1 = str(time1) if not i == 0 else ''
            v1 = int(a[i:])
            for j in range(len(b)) :
                time2 = 1 if j == 0 else int(b[-j:])
                s2 = str(time2) if not j == 0 else ''
                v2 = int(b[:-j]) if not j == 0 else int(b)
                vt = time1 * time2 * (v1+v2)
                # print(time1, v1, v2, time2)
                # print(vt)
                # print('%s(%d+%d)%s'%(s1, v1, v2, s2))
                if vt < v :
                    v = vt
                    to_ret = '%s(%d+%d)%s'%(s1, v1, v2, s2)
        return to_ret

我(菜鸡)的代码

class Solution:
    def minimizeResult(self, expression: str):
        x_index=expression.index('+')
        left,right=x_index,len(expression)-x_index-1
        left_num,right_num=int(''.join(expression[0:x_index])),int(''.join(expression[x_index+1:]))
        cnt=float('inf')
        for i in range(left):
            for j in range(right):
                if i==0:
                    k1=1
                    k2=left_num
                else:
                    k1,k2=divmod(left_num,10**(left-i))
                
                if j==0:
                    k4=1
                    k3=right_num
                else:
                    k3,k4=divmod(right_num,10**j)
                if k1*(k2+k3)*k4<cnt:
                    cnt=k1*(k2+k3)*k4
                    j1,j2,j3,j4=k1,k2,k3,k4
        if j1==1 and len(str(j2))==left:
            j1=''
        if j4==1 and len(str(j3))==right:
            j4=''
        return('{}({}+{}){}'.format(j1,j2,j3,j4))
                

 3 淬不及防的知识点 

(1)以某一字符或字符串分割字符串得到左右两部分

a, b = expression.split('+')

(2)字符拼接:根据遍历特点,巧妙拼接

for j in range(len(b)) :
    time2 = 1 if j == 0 else int(b[-j:])

j=1,拼接字符串 b 的 【-1:】,即最后一个

j=2,拼接字符串 b 的 【-2:】,即最后两个

?K 次增加后的最大乘积?

1 题目

2 分析和讲解 

分析:根据实例可知要每次加在最小的那个数上,才会使得最终乘积最大,但很显然求诸如此类每次找最小的数或最小的两个数等进行操作的有两种方法:二叉堆和优先队列,但从时间上可以看出,二叉堆更胜一筹,也就是大佬用的方法,将列表先排序再用二叉堆会好一点

大佬的代码

class Solution:
    def maximumProduct(self, nums: List[int], k: int):
        heapt = sorted(nums)
        for _ in range(k) :
            a = heapq.heappop(heapt)
            heapq.heappush(heapt, a+1)
        to_ret = 1
        ttt = 10**9+7
        for t in heapt :
            to_ret = (to_ret*t)%ttt
        return to_ret

 

我的代码

class Solution:
    def maximumProduct(self, nums: List[int], k: int):
        from queue import PriorityQueue
        q=PriorityQueue()
        for i in nums:
            q.put(i)
        while k!=0:
            tmp=q.get()
            q.put(tmp+1)
            k-=1
        cnt=1
        x=10**9+7
        for i in range(len(nums)):
            cnt=(cnt*q.get())%x
        return(cnt%x)

3 淬不及防的知识点 

(1)解题关键就是知道每次要加在最小的那个数上,一是解题有时要有猜测,根据实例合理分析判断,直接写看看测试对不对,二是周长相等的四边形面积最大的就是正方形,这里合理扩展到多维,就是使得列表中每个数尽可能的都相等

(2)1e9显示是个浮点数,得转化为int,而10**9为整型

(3)二分堆和优先队列的使用

 可参照其中哈夫曼树的模板,原理的上网查找即可Python真题练习5(哈夫曼树)_qq_51226280的博客-CSDN博客参考文章:【蓝桥python冲刺17天】——如何轻松拿捏必考数论题?(第三弹)、小蓝の蓝桥城之旅·第二章·「暴力枚举」、1.算式900from itertools import permutationsfor per in permutations('0123456789'): #全排列字符串,合在一起,切片和转化为int i=''.join(per) a,b,c=int(i[0:4]),int(i[4:8]),int(i[8:]) if (a-b)*c=.https://blog.csdn.net/qq_51226280/article/details/123849017?spm=1001.2014.3001.5502


版权声明:本文为qq_51226280原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。