发现未分类和排序的列表之间的最小距离未分类、最小、距离、发现

2023-09-10 23:18:49 作者:相见不如怀念

设A是一个列表和S相同的元素的排序列表。假设所有元素是不同的。如何找到一组动作( Y(或结束)前移动X)它可将进入S?

最小

例如:

  A = [8,1,2,3]
S = [1,2,3,8]

A => S理论的一招:
   年底前将8

A = [9,1,2,3,0]
S = [0,1,2,3,9]

A => S理论两个动作:
   0前移至9
   1前移到0
 

我preFER JavaScript或Python的,但任何语言都行。

解决方案

这个问题等价于最长递增子问题。

A列表和C列表对比重复,对比同时不影响A列表和B列表排序 外加20元红包感谢

您必须定义一个比较操作符以下(A,B)返回当且仅当 A 是前 B 目标顺序进行。现在使用这种比较运算符,计算最大增加源序列的子序列。你将不得不将不在此子序列(否则子序列不会最大值)的一部分,每一个元素,你可以将它一次(移动到目标位置)。

编辑:所要求的艾米特这里是我的证明上面的语句: 让我们记靶序列 B ,并允许表示源序列 A 。让 N = | A | K 是最长递增序列的长度如上所述。 让我们假设它是有可能达到 B A 用动作比以下N - K 。这意味着至少 N - 从K + 1 元素的 A 不会移动。设s 1 ,S 2 ,内容S M 是集不会移动元素。从假设,我们知道, M>氏/ code>。现在,作为这些元素都没有移动,比它们的相对于彼此的相对位置不能有变化。因此,靶序列 B 在所有这些元素的相对位置是相同的一个在 A 。为此运营商较少(S 我,S Ĵ)如上述定义应为任何是真实的我Ĵ。但是,如果这是真的,则s 1 ,S 2 ,内容S M 的递增序列,并为米> ķ这导致在假设k是最长递增序列的长度的矛盾。 现在,让显示的算法来达到 B A 移动的所有元素,但那些有一部分最长递增序列。我们会朝着它们出现在B.我们不会移动,它们是最长递增序列的一部分元素的顺序的元素。如果当前元素是第一个在B,我们只需将其移动到该序列的开头。否则我们移动后的当前元素右边的 在B中的previous元件的位置请注意,此元件可以是,我们已经提出的previous元件或从最长的元素递增序列。需要注意的是,在每一步的时候,我们将要移动的元素与指数,与指数的所有元素 1,2,... I-1 将已经是与相对于彼此正确的相对位置。

编辑:添加一些code键使答案更清晰。我不觉得在JavaScript方面的专家,以便随时纠正或批评我的解决方案。

让我们定义一个函数变换(A,S)采用两个参数 - 如在声明中所述名单a和b。首先,我将创建一个地图位置映射在每个元素来其立场:

  VAR位置= {};
对于(VAR I = 0; I<则为a.length; ++ I){
  位置[A [1] =我;
}
 

现在,我有这样的阵列上面我的回答说明我可以定义一个辅助功能较少。更不会取两个值 A B (我刚刚创建的辅助图),并返回true当且仅当 A 是前 B 取值(目标列表)

 功能少(A,B,持仓量){
  归仓[A] LT;位置并[b];
}
 

现在我就不一一介绍了,我们怎么能找到的最大递增子在 A 相对于该比较操作。你可以看看这个问题详细解释如何做到这一点。我会简单地认为我有定义的函数:

 函数max_increasing_subsequence(一,位置)
 

这是相对于比较运算符返回的最大递增子在 A 以上(使用定义位置)的列表。我会用你的第二个例子来说明我们到目前为止有:

  A = [9,1,2,3,0]
S = [0,1,2,3,9]
 

在位置值将是如下:

 位置= {0:0,
              1:1,
              2:2,
              3:3,
              9:4}
 

max_increasing_subsequence的结果(一,位置) [1,2,3] 。顺便说一句,如果有可能在 A 这可能是更好的回报指标,而不是从 max_increasing_subsequence 元素重复元素(在该特定示例中的差异将是不可见)。

现在我将创造另一个辅助地图来表示这是包含在最大递增子元素:

  VAR包括= {};
L = max_increasing_subsequence(一,位置);
对于(VAR I = 0; I< l.length ++我){
  包括[L [我] = TRUE;
}
 

现在你可以完成了该解决方案与单一迭代取值。我将添加一个特殊情况下的最后一个元素,使code更容易理解:

  IF((S![s.length  -  1]包括在内)){
  的console.log(移动+ S [s.length  -  1] +底);
}
对于(VAR I = s.length  -  2; I> = 0; --i){
  如果(!(S [i]于包括在内)){
    的console.log(移动+ S [I] +前的+ S [I + 1]);
  }
}
 

请注意,上述解决方案我认为每次登录一个新的命令时,你就登录到阵列的顺序 A 所有$右后p $ pvious命令已被执行。

因此​​,在总,我相信改变应该是这个样子:

 函数变换(A,S){
  VAR位置= {};
  对于(VAR I = 0; I<则为a.length; ++ I){
    位置[A [1] =我;
  }
  变种包括= {};
  L = max_increasing_subsequence(一,位置);
  变种包括= {};
  对于(VAR I = 0; I< l.length ++我){
    包括[L [我] = TRUE;
  }
  如果((S![s.length  -  1]包括在内)){
    的console.log(移动+ S [s.length  -  1] +底);
  }
  对于(VAR I = s.length  -  2; I> = 0; --i){//注意s.length  -  2  - 不处理最后一个元素
    如果(!(S [i]于包括在内)){
      的console.log(移动+ S [I] +前的+ S [I + 1]);
    }
  }
}
 

我希望这code,使我的回答更加清晰。

Let A be a list and S a sorted list of the same elements. Assume all elements are different. How do I find a minimal set of "moves" (move X before Y (or end)) that turns A into S?

Examples:

A = [8,1,2,3]
S = [1,2,3,8]

A => S requires one move: 
   move 8 before end

A = [9,1,2,3,0]
S = [0,1,2,3,9]

A => S requires two moves:
   move 9 before 0
   move 0 before 1

I prefer javascript or python, but any language will do.

解决方案

This problem is equivalent to longest increasing subsequence problem.

You will have to define a comparison operator less. less(a, b) will return true if and only if a is before b in the target sequence. Now using this comparison operator, compute the maximum increasing sub sequence of the source sequence. You will have to move each element that is not part of this sub sequence (otherwise the sub sequence will not be maximum) and you can move it exactly once(moving it to its target position).

EDIT: As requested by amit here is my proof to the statement above: Lets we denote the target sequence B and lets denote the source sequence A. Let n = |A| and let k be the length of the longest increasing sequence as described above.

Let's assume it is possible to reach B from A with less moves than n - k. This means that at least n - k + 1 elements from the A will not be moved. Let s1,s2,...sm be the set of elements that are not moved. From the assumption we know that m > k. Now as these elements have not moved, than their relative position with respect to each other can not have changed. Thus the relative positions of all this elements in the target sequence B is the same as the one in A. Therefor the operator less(si, sj) as defined above should be true for any i, j. But if this is true then s1,s2,...sm is increasing sequence and as m > k this leads to a contradiction with the assumption that k is the length of the longest increasing sequence. Now lets show an algorithm to reach B from A by moving all elements but the ones that are part of the longest increasing sequence. We will move the elements in the order they appear in B. We will not move elements that are part of the longest increasing sequence. If the current element is the first one in B, we simply move it to the beginning of the sequence. Otherwise we move the current element right after the position of the previous element in B. Note that this element may either be the previous element we've moved or an element from the longest increasing sequence. Note that at each step when we are about to move element with index i, all elements with index 1, 2, ...i-1 will already be with correct relative positions with respect to each other.

EDIT: adding some code to make the answer clearer. I don't feel an expert in javascript so feel free to correct or criticize my solution.

Let's define a function transform(a, s) that takes two parameters - lists a and b as described in the statement. First I will create a map positions that maps each element in a to its position in s:

var positions = {};
for (var i = 0; i < a.length; ++i) {
  positions[a[i]] = i;
}

Now that I have this array I can define a helper function less as described in my answer above. Less will take two values a and b(and the helper map I just created) and return true if and only if a is before b in s(the target list):

function less(a, b, positions) {
  return positions[a] < positions[b];
}

Now I will not describe how can we find the maximum increasing subsequence in a with respect to that comparison operator. You can have a look at this question for detailed explanation how to do that. I will simply assume that I have a function defined:

function max_increasing_subsequence(a, positions)

That returns the maximum increasing subsequence in a with respect to the comparison operator less as defined above (using positions)as a list. I will use your second example to illustrate what we have so far:

A = [9,1,2,3,0]
S = [0,1,2,3,9]

The values in positions will be as follow:

positions = { 0 : 0,
              1 : 1,
              2 : 2,
              3 : 3,
              9 : 4}

And the result of max_increasing_subsequence(a, positions) will be [1, 2, 3]. By the way if there may be repeating elements in a it may be better to return indices instead of the elements from max_increasing_subsequence(in this particular example the difference will not be visible).

Now I will create another helper map to indicate which are the elements included in the maximum increasing subsequence:

var included = {};
l = max_increasing_subsequence(a, positions);
for (var i = 0; i < l.length; ++i) {
  included[l[i]] = true;
}

Now you can finish up the solution with a single iteration over s. I will add a special case for the last element to make code easier to understand:

if (!(s[s.length - 1] in included)) {
  console.log("Move" + s[s.length - 1] + " at the end");
}
for (var i = s.length - 2; i >= 0; --i) {
  if (!(s[i] in included)) {
    console.log("Move" + s[i] + " before " + s[i + 1]);
  }
}

Please note that in the solution above I assume that each time you log a new command, you log it with respect to the ordering of the array a right after all previous commands have been executed.

So in total I believe transform should look something like this:

function transform(a, s) {
  var positions = {};
  for (var i = 0; i < a.length; ++i) {
    positions[a[i]] = i;
  }
  var included = {};
  l = max_increasing_subsequence(a, positions);
  var included = {};
  for (var i = 0; i < l.length; ++i) {
    included[l[i]] = true;
  }
  if (!(s[s.length - 1] in included)) {
    console.log("Move" + s[s.length - 1] + " at the end");
  }
  for (var i = s.length - 2; i >= 0; --i) { // note s.length - 2 - don't process last element
    if (!(s[i] in included)) {
      console.log("Move" + s[i] + " before " + s[i + 1]);
    }
  }
}

I hope this code makes my answer more clear.