当前位置: 首页 > 知识库问答 >
问题:

通过交换给定整数中的一对数字来找到最小整数的算法

万俟皓
2023-03-14

给定一个正整数(以数字数组的形式)。我们可以交换给定数字中的一对数字。我们需要返回可以获得的最小整数。注意,它应该是一个有效的整数,即不应该包含前导0。

例如:-

  1. 93561 返回 13569
  2. 596 返回 569
  3. 10234 返回 10234
  4. 120 返回 102
  5. 10091 返回 10019
  6. 18761119 98761111退货

这个问题是否有O(n)算法。我想出了几种方法:-

    < li >找到min。给定整数(0除外)中的数字(< code>minDIgit),如果< code>MSB!= minDigit。如果< code>MSB==minDigit,则查找下一个min。数位,并将其与除1位以外的最高有效位交换,依此类推。最坏的情况可能是 O(n^2)。 < li >生成数字和索引的< code>std::pair的< code >数组/向量,并按升序排序(根据数字值;首先为匹配的数字值保留较低的索引)。遍历排序后的数组。将MSB与第一个数字交换。如果最小数位的索引为MSB,则将MSB与下一个最小数位交换1位。如果下一个min数字对应的索引是MSB,但只有1位,那么用这个下一个min交换MSB,但只有2位。数字等等。这应该是< code>O(nlog(n))。

有人可以建议一个更好的算法。

更新1:经过一点思考,我提出的第二个算法将非常好地工作(可能除了少数可以单独处理的拐角情况外)。此外,我可以使用计数排序(根据数字值)对对(数字、索引)进行排序,这在O(n)时间内是一种稳定的排序。我的论点有缺陷吗?

更新2:我的第二个算法可以工作(尽管需要更多检查角点大小写和0),在O(n)时间内,使用计数排序。但@GaborSch给出的解决方案要简单得多,所以我不会为我的算法给出合适的代码。

共有3个答案

越鸿才
2023-03-14

我会从右端开始遍历数组。将右侧的数字存储为最小数字和最大数字,然后开始向左移动,如果你碰到一个新的较小的数字,将其称为潜在最小数。如果你继续向左移动,找到一个较小的数字,将较小的数字设为潜在数。如果你找到一个较大的数字,将潜在数设为最小int,并将较大的整数存储为最大数字。每次你碰到比最小数更大的数字,将其设为新的最大数字。如果你碰到结尾,交换最大数字和最小数字。在python中(这是有效的,并且是O(n))

def swap_max(digits):
    i = len(digits) - 1
    while i > 0:
        if digits[i] == 0:
            i-= 1
        else:
            break
    max_i = i
    min_i = i
    pot_i = i
    z_i   = -1
    nz_i  = i
    i = len(digits) - 1
    while i >= 0:
        if digits[i] > digits[pot_i]:
            max_i = i
            min_i = pot_i
        if digits[i] < digits[min_i] and digits[i] != 0:
            pot_i = i
        if digits[i] == 0 and z_i == -1:
            z_i = i
        if digits[i] != 0 and i > 0:
            nz_i = i
        i -= 1
    if z_i != -1 and max_i != 0 and max_i < z_i:
        min_i = z_i
        i = nz_i
        max_i = i
    elif max_i == min_i and z_i != -1:
        i = nz_i
        if i < z_i:
            min_i = z_i
            max_i = i

    v = digits[min_i]
    digits[min_i] = digits[max_i]
    digits[max_i] = v
    return digits


#TESTING THE FUNCTION
tests =   [93561,596,10234,120,10091,98761111,1001,1010,1103,120,93218910471211292416]
results = [13569,569,10234,102,10019,18761119,1001,1001,1013,102,13218910471211292496]
tests = map(list,map(str,tests))
results = map(list,map(str,results))
for i in range(len(tests)):
    res ="".join(map(str,swap_max(map(int,tests[i]))))
    print res,"".join(results[i])
    if res=="".join(results[i]):
        print "PASSED\n"
    else:
        print "FAILED\n"

这最终适用于所有示例。它还具有O(1)内存使用的优势。

华飞驰
2023-03-14

首先计算每个数字,将其存储在一个数组中(计数[10])。

从左侧开始,检查数字(以下是循环说明):

检查< code >计数中是否有比它小的数字。挑个最小的。例外:第一个数字不允许< code>0。

  • 如果有一个,swap,就完成了(退出循环!)
  • 否则,减少计数中的数字,并转到下一个数字

对于每个数字,你做O(1)工作。所以整个算法是O(n)。

对于交换,您需要使用最低有效数字(进一步向右)。您可以在初始查找时存储这些位置,也可以在交换之前从末尾开始搜索第一个匹配的数字。

杜骏祥
2023-03-14

作为准备工作,我们遍历数字,并标记数组中数字的最后位置[10](称为最后)(包括0秒)。那就是 O(n)。

接下来,我们开始从左到右遍历数字。对于每个位置,我们试图找到最后一个位置大于当前位置的最小数字(位置约束)。此外,该数字必须小于当前数字。

如果我们处于第一个位置,我们将从1开始在最后一个>上开始循环(否则从0

如果我们找到这样一个数字(关于位置约束),我们就交换(并中断循环)。如果我们不这样做,我们就前进到下一个数字。成本最多为O(n*9),即O(n)。

总成本为O(n)O(n)*O(9)=O(n)。

该算法如何在示例上工作:

93561 ->   it can swap in the first cycle

596   ->   skipping the first cycle, 
           then finds '6' because of the position constraint 
           (comparing position '1' with last[5] = 0, last[6] = 2)

10234 ->   does not find anything because of the position constraint

93218910471211292416 -> finds the last occurrence of '1' to replace '9'

98761111 -> it can swap in the first cycle
            (last[1] = 7, so it will change the last occurrence)

555555555555555555596 -> iterates until the '9', then you skip last[5]
            but finds last[6] as a good swap

120 ->      at pos 0 (1) cannot find a non-zero element less than 1, so skip
            at pos 1 (2) can find 0 on position 2, so we swap

同样,这里我们对数字进行一次迭代(用于预解析数据),然后一次迭代寻找MSB。在第二次迭代中,我们迭代< code>last,它的大小不变(最多为9)。

您可以通过添加跟踪最小值来进一步优化算法,当值得在last上开始循环时,但这已经是一种优化了。prevoius版本包含它,如果您感兴趣,请查看历史记录:)

 类似资料:
  • 给定一个无序整数列表,以这种方式打印两个总计为的整数(int 1小于或等于int 2,它们之间用空格隔开)。假设整数列表中总是有的解。int1和int2必须是正整数。 如果有多个解决方案,请打印差异最小的整数对。 例子: 这是我的代码,但是根据我们的编译器(这是我们班的一个练习),我对隐藏的测试用例有错误的输出。 更新:代码工作!

  • 我试着写一个代码,它接受一个介于1和1_000_000之间的整数,并返回一个比相同数字的整数大的最小整数,如果它不存在,则打印0。 举个例子 输入:156 输出165 输入330 输出0 输入27711 输出71127 我的问题是,下面的代码没有为其他输入返回正确的输出。 例如,在输入4231中,输出应该是4312。 我很难找到为每个输入返回正确输出的最佳算法。 TNX提前 }

  • 给定一个2d数组,我需要返回一个具有路径的矩阵,该路径递归地求和到给定的数字。 路径矩阵应为零,但总计为给定数字的路径除外,该路径将标记为1。 路径只能在 我尝试过所有的可能性,首先检查我是否已经去过下一个街区。 问题是在一些迭代之后,它会停止,并且不会返回并再次将块清除为0。 给定 在通话中 我以为算法会回来 我得到 相反 调用paintPath(mat1400,path,0,0);我想 或 问

  • 我知道这是一个背包问题,其中权重和值相等,但我认为我在编码逻辑上犯了一个错误,因为即使对于数组中元素的数量(N)为50并且所需的最大总和(M)4500。 为了澄清这个问题,我们得到了一个由N个正整数和一个正整数M组成的数组。数组元素只能使用一次。我们必须找到这个数组的子集(不一定是连续的),使得总和最接近M,但不超过它。 这是我使用动态编程的尝试: 那么在我的代码中是否有任何可能的优化可以帮助我降

  • 正整数的二进制权重是其二进制表示中1的个数。例如,十进制数1的二进制权重为1,十进制数7(二进制为111)的二进制权重为3。 给定一个正整数N,找出与N具有相同二进制权重的大于N的最小整数。 我的解决方案运行良好,但它的复杂性似乎是O(NlogN)。这可以通过其他方法在O(N)或O(logn)中实现吗?

  • 我试图解决下面提供的Codness中的一个问题, 编写一个函数: 给定一个由N个整数组成的数组A,返回A中不出现的最小正整数(大于0)。 例如,给定A=[1,3,6,4,1,2],函数应该返回5。 假定: N是范围[1...100,000]内的整数;数组A的每个元素都是范围[−1,000,000..1,000,000]内的整数。 预期最坏情况时间复杂度为O(N);预计最坏情况下的空间复杂度为O(N