重排数字的最小值

标签: 数学 排序

难度: Medium

给你一个整数 num重排 num 中的各位数字,使其值 最小化 且不含 任何 前导零。

返回不含前导零且值最小的重排数字。

注意,重排各位数字后,num 的符号不会改变。

示例 1:

输入:num = 310
输出:103
解释:310 中各位数字的可行排列有:013、031、103、130、301、310 。
不含任何前导零且值最小的重排数字是 103 。

示例 2:

输入:num = -7605
输出:-7650
解释:-7605 中各位数字的部分可行排列为:-7650、-6705、-5076、-0567。
不含任何前导零且值最小的重排数字是 -7650 。

提示:

  • -1015 <= num <= 1015

Submission

运行时间: 25 ms

内存: 16.0 MB

class Solution:
    def smallestNumber(self, num: int) -> int:
        if num == 0:
            return 0
        elif num < 0:
            s = str(num)[1:]
            index = s.index(max(s))
            min_value = int("-" + str(s[index]) + "".join(sorted(s[:index] + s[index + 1:], reverse=True)))
        else:
            s = str(num)
            index = s.index(min(s, key=lambda x: x if x != "0" else "9"))
            min_value = int(str(s[index]) + "".join(sorted(s[:index] + s[index + 1:])))
        return min_value

Explain

此题解的核心思想是首先将数字转换为字符串以便操作其各个数字。对于正数,找到第一个非零的最小数字作为最小值的首位,然后将剩余数字升序排序并拼接在后面。对于负数,找到最大的数字作为首位,然后将剩余数字降序排序并拼接在后面,最终加上负号,以确保得到的负数尽可能小。如果数字为0,直接返回0。

时间复杂度: O(n log n)

空间复杂度: O(n)

class Solution:
    def smallestNumber(self, num: int) -> int:
        if num == 0:
            return 0  # 如果数字是0,直接返回0
        elif num < 0:
            s = str(num)[1:]  # 去掉负号
            index = s.index(max(s))  # 找到最大的数字的索引,作为负数的最小值的首位
            min_value = int("-" + str(s[index]) + "".join(sorted(s[:index] + s[index + 1:], reverse=True)))  # 降序排序剩余部分
        else:
            s = str(num)
            index = s.index(min(s, key=lambda x: x if x != "0" else "9"))  # 找到第一个非零的最小数字,避免前导零
            min_value = int(str(s[index]) + "".join(sorted(s[:index] + s[index + 1:])))  # 升序排序剩余部分
        return min_value  # 返回结果

Explore

在处理正数时,我们希望数字尽可能小,因此将数字升序排列可以使得较小的数字放在前面,从而形成最小的正数。而在处理负数时,我们需要的是绝对值最小的负数,即尽可能接近零的负数。将数字降序排列后,较大的数字会放在前面,使得负数的绝对值尽可能小。

如果所有数字都相同,无论是正数1111还是负数-2222,排序后的结果仍然是相同的数字顺序。对于正数1111,找到最小的非零数字后进行排序,结果依然是1111。对于负数-2222,找到最大的数字进行降序排序,结果也是-2222。因此,算法在这种情况下会返回输入数字的原值。

在查找最小或最大数字时,如果所有数字都是0,例如输入为0或-0(虽然-0等同于0),在正数处理逻辑中,`min`函数会通过lambda函数将'0'视为'9'进行比较,确保不选择0作为首位,但仍然能找到0因为它是唯一的选择。在负数处理逻辑中,使用`max`函数查找最大数字时,因为所有数字都是0,所以会返回0,不会抛出异常。

对于负数处理,选择最大的数字作为首位是为了使负数的绝对值尽可能小(即负数尽可能接近零)。在这之后,将剩余部分进行降序排序可以保证较大的数字靠前,从而使得整个负数的绝对值最小。如果采用升序排序,剩余较小的数字会靠前,使得负数的绝对值增大,这与我们希望得到尽可能小的负数的目标相悖。