如何找到给定数字的所有数字的排列,使其最接近目标数字

时间:2017-10-23 06:18:41

标签: algorithm permutation

我刚从书中看到这个有趣的问题,我无法找到答案。

我有一个给定的数字X和一个目标数字Y,任务是找到X的所有数字的这种排列,使它最接近Y. 数字是数组的形式。没有给出数组大小限制。

实施例

Given number X = 1212
Target number Y = 1500
Answer = 1221
Here, abs(1500-1221) is smallest among all permutations of X.

Given number X = 1212
Target number Y = 1900
Answer = 2112
Here, abs(1900-2112) is smallest among all permutations of X.

Given number X = 1029
Target number Y = 2000
Answer = 2019
Here, abs(2000-2019) is smallest among all permutations of X.

我能找到的解决方案之一是生成给定数字的所有排列,并在每个阶段计算差异。但这很慢。

我试图找到贪婪的方法,在那里我将迭代目标数Y的所有索引,并且在每个索引处我将把给定数字X的那个数字放在abs(Y [i] - X [i] ])是最小的。但是在很多情况下都失败了。

我正在考虑使用DP方法,但无法提出任何方法。

任何导致答案的人都会有所帮助。

编辑 - 为我的贪婪方法添加伪代码

for each index i in [0,Y]:

    min_index = 0;
    for each index j in [1, X.length]:
        if abs(X[j] - Y[i]) < abs(X[min_index] - Y[i]):
            min_val = j

    print X[min_index]
    remove min_index from X

Example X = 1212 and Y = 1900.
step 1 - output 1 and remove index 0 from X.
step 2 - output 2 and remove index 1 from X.
step 3 - output 1 and remove index 2 from X.
step 2 - output 1 and remove index 3 from X.
answer = 1212 which is wrong (correct answer is 2112).
So fails for this test case and lots more.

2 个答案:

答案 0 :(得分:1)

宽度为3的

Beam search可能是一种方法。我们的想法是构建从最大到最小数字的数字,并用零填充其余数字。您可以为每个步骤中的每个数字构建最近和最接近的第二个数字,并丢弃所有比前三个更差的数字。 (实际上你最多只需要两个光束。如果光束中两个条目的距离相等,则只需要三个情况。)在计算过程中构造的数字A和{{1永远不应该相等(除了B只包含相同数字的特殊情况。)

以下是第二个例子的光束。 X表示最佳光束,没有*表示两者同样好:

*

这是第一个例子:

2000* -> 2100* -> 2112*
         2200  -> 2211
1000  -> 1200  
         1100

第三个例子需要第二步的光束尺寸为3,因为第二个最佳光束1900和2100到2000的距离是100:

1000  -> 1200* -> 1221*
         1100  -> 1122
2000  -> 2100
         2200

注意:我已加入所有示例中的3.和4.步骤。

数字1000 -> 1900 -> 1901 1100 2000* -> 2000* -> 2019* 2100 2109 X = 1992是一个有趣的例子

Y = 2000

因为最好的光束在计算过程中会发生变化。

我写了一个小的python程序用于演示:

1000  -> 1900  -> 1992*
         1200
2000* -> 2100  -> 2199
         2900

代码不是最优的,但是这个算法最多有多项式运行时间, O n ²l n ),这个估计非常慷慨。

答案 1 :(得分:1)

所以,问题可以看作如下:

从最大有效数字开始,对于每个索引,有三种情况:

  • 当前数字将小于所需数字,因此对于其余数字,我们尝试创建可能的最大数字=&gt;对于其余的数字,我们按降序对它们进行排序,即如果我们有0,2,7,5左 - >&gt;我们将创建7520

  • 当前数字将大于所需数字,因此对于其余数字,我们尝试创建尽可能小的数字=&gt;对于其余的数字,我们按升序对它们进行排序,即如果我们有0,2,7,5左 - >&gt;我们将创建0275

  • 如果当前数字等于所需数字,我们会将其附加到prefix并尝试在下一次迭代中找到更好的匹配。

的伪代码:

int prefix, result;
for each index i from 0 to Y.length() {

       int larger = prefix + smallestDigitLargerThan(Y(i)) + OtherDigitInAscendingOrder;
       int smaller = prefix + largestDigitSmallerThan(Y(i)) + OtherDigitInDescendingOrder;
       update result based on larger and smaller;
       if there is no digit equals to Y(i)
          break;
       else {
          remove Y(i) in X
          prefix = prefix*10 + Y(i)
       } 
    }
}
if prefix == Y {
   //We have a full match
   return prefix;
}
return result;

例如

X = 1029
Y = 2000

At index 0 -> Y(0) = 2, 

int smaller = 0 (prefix) + 1(largest digit that is less than 2) + 920 (other digit in descending order) = 1920
int larger = 0 (prefix) + 9(smallest digit that is greater than 2) + 012 (other digit in ascending order) = 9012
int result = 1920
int prefix = 2

At index 1 -> Y(1) = 0,

int smaller = //Not exist
int larger = 2 + 1 + 09 = 2109
int result = 1920
int prefix = 20

At index 2 -> Y(2) = 0,

int smaller = //Not exist
int larger = 20 + 1 + 9 = 2019
int result = 2019
//Break as there is no digit match Y(2) = 0 from X

其他例子:

X = 1212
Y = 1500

At index 0 -> Y(0) = 1, 

int smaller = //Not exist
int larger = 0 + 2 + 112 = 2112
int result = 2112
int prefix = 1

At index 1 -> Y(1) = 5,

int smaller = 1 + 2 + 21 = 1221
int larger = //Not exist
int result = 1221
//Break from here as there is no digit match Y(1) = 5 in X