【每日力扣】最大交换(两种解法/自定义后序index函数)

本文介绍了如何解决最大交换问题,通过暴力解法和贪心策略,重点讲解了使用sort()和sorted()函数的差异以及如何处理相同数字的干扰,提供了解决算法和代码实现的修正过程。
摘要由CSDN通过智能技术生成

题目

最大交换

给定一个非负整数,你至多可以交换一次数字中的任意两位。返回你能得到的最大值。

示例 1 :

输入: 2736
输出: 7236
解释: 交换数字2和数字7。

示例 2 :

输入: 9973
输出: 9973
解释: 不需要交换。

思路&code

解法一:暴力解法

思路

        首先,最暴力的一种解法把每种一次交换之后的结果都写出来,最后在里面找到最大的那个结果。没什么好说的,直接上代码。

正确代码
class Solution:
    def maximumSwap(self, num: int) -> int:
        n = list(str(num))
        ma = num
        for i in range(len(n)):
            for j in range(i):
                n[i],n[j] = n[j],n[i]
                ma = max(ma,int(''.join(n)))
                n[i],n[j] = n[j],n[i]
        return ma

解法二:贪心

思路

        最大交换,明显是可以使用贪心的思想。我们可以思考得出,数位的高位上的数字越大,数字值越大,也就是说其实找最大变换就是想办法进行一次变换,把大的数从低数位转移到高数位。从极限的角度,假设可以进行无数次变换,那么最大的一定是降序序列。(例如48579,最大一定是98754)由此就能够自然而然地想到这一种解法:首先将数进行降序排序,而后按照从高位到低位的顺序对比排序所得序列(s)和原序列(n),第一个不相同的位置就是需要进行交换的位置(因为数位越高对数的大小影响越大),而与其交换的元素就是该位置i在s序列中对应元素s[i]在n序列中的位置j。

出现的问题

        思路是这样子没错,但是实际编码过程中其实出现了许多的问题。

问题一:赋值以及sort()函数的理解不清

        一开始编写出的代码如下:

class Solution:
    def maximumSwap(self, num: int) -> int:
        n =list(str(num))
        s = n
        s.sort(reverse =-1)
        for i in range(len(n)):
            if n[i] != s[i]:
                j = n.index(s[i])
                n[i],n[j] = n[j],n[i]
                break
        return(int(''.join(n))) 

        看着没有什么问题,基本符合上述的思路,先进行降序排序,再遍历比较,找到不同并进行交换之后使用break语句结束循环返回结果。但是输出的一直是降序序列s(即得到的一直都是假设的极限最大数值),我完全没有找到是哪里的问题,甚至一度认为是break出现了问题导致无法正常结束循环从而一直进行交换。直到后来我试着输出n的值,惊奇地发现n的值就是s!n与s一模一样,根本就没有进行交换!我这才幡然醒悟,这其实是一个小细节所引起的错误:sort()函数,我们都知道sort()函数是直接在原列表上进行修改,而不是先把原列表复制下来再进行修改。当然代码中为了实现复制想当然地使用了's = n'这样的一条语句,但其实这相当于取别名,m与n的id是一模一样的,也就是说把n赋值给s再进行sort()排序,最后其实还是直接在n上进行的修改,而不是如我设想的一样在n的复制体s上进行修改。

修改方法:sorted()函数的使用

        修改的方法其实也很简单:将我们使用的sort()函数换成sorted函数,sorted()函数是不会再原列表上进行改动的。但是要注意的一个小细节是:sorted()与sort()不同,并不是列表的专用函数,所以写法上要进行一些修改。

class Solution:
    def maximumSwap(self, num: int) -> int:
        n =list(str(num))
        s = sorted(n,reverse =-1)  #sorted()函数的使用
        for i in range(len(n)):
            if n[i] != s[i]:
                j = n.index(s[i])
                n[i],n[j] = n[j],n[i]
                return(int(''.join(n)))
        return num
问题二:排除相同数字的干扰

        细心的朋友其实已经发现了一个漏洞,在有相同数字进行干扰的情况下,算法会出现错误。例如:num = 1993 ,正确的答案应该是9913,但是按照上述代码最后得出的却是9193。为什么会这样呢?关键点其实在于index()这个方法,因为Index在定位时如果遇到相同的元素,默认返回的是最前面元素的位置,这其实与我们的想法是相悖的(因为我们前面的处于高位,我们要将小的数尽可能地换到低位)所以只要我们有一个在遇到相同元素情况时默认返回最后的元素的位置的index_from_end()函数就可以解决这个问题,既然没有现成的函数,我们可以自己编一个,实现起来也不难。

修改方法:自定义一个后序index函数
def index_from_end(lst, value):
    for i in range(len(lst)-1, -1, -1):  # 从后往前遍历列表
        if lst[i] == value:
            return i  
正确代码
class Solution:
    def maximumSwap(self, num: int) -> int:
        def index_from_end(lst, value):
            for i in range(len(lst)-1, -1, -1):  # 从后往前遍历列表
                if lst[i] == value:
                    return i  
        n =list(str(num))
        s = sorted(n,reverse =-1)
        for i in range(len(n)):
            if n[i] != s[i]:
                j = index_from_end(n,s[i])
                n[i],n[j] = n[j],n[i]
                return(int(''.join(n)))
        return num

        以上就是本期的全部内容了,如有不妥之处还请大家批评指正。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值