Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/378.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 查找未排序列表和已排序列表之间的最小距离_Javascript_Python_Algorithm_Language Agnostic - Fatal编程技术网

Javascript 查找未排序列表和已排序列表之间的最小距离

Javascript 查找未排序列表和已排序列表之间的最小距离,javascript,python,algorithm,language-agnostic,Javascript,Python,Algorithm,Language Agnostic,设A为列表,S为相同元素的排序列表。假设所有元素都不同。如何找到将a转换为S的最小“移动”(在Y(或结束)之前移动X)集合 示例: 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 我

设A为列表,S为相同元素的排序列表。假设所有元素都不同。如何找到将a转换为S的最小“移动”(
在Y(或结束)之前移动X
)集合

示例:

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

我更喜欢javascript或python,但任何语言都可以。

这个问题相当于这个问题

您必须定义一个比较运算符
less
<当且仅当目标序列中
a
b
之前时,code>less(a,b)将返回
true
。现在使用这个比较运算符,计算源序列的最大递增子序列。您必须移动不属于此子序列的每个元素(否则子序列将不会是最大值),并且您可以将其仅移动一次(将其移动到其目标位置)

编辑:根据amit的要求,以下是我对上述陈述的证明: 让我们表示目标序列
B
,并让我们表示源序列
A
。设
n=|A |
k
为上述最长递增序列的长度

  • 让我们假设可以从
    A
    到达
    B
    ,移动次数少于
    n-k
    。这意味着将不会移动
    A
    中的至少
    n-k+1
    元素。设s1、s2、…sm为未移动的元素集。根据这个假设,我们知道
    m>k
    。由于这些元素没有移动,它们之间的相对位置就不会改变。因此,所有这些元素在目标序列
    B
    中的相对位置与
    A
    中的相对位置相同。因此,对于任何
    i
    j
    ,上述定义的运算符less(si,sj)应为真。但如果这是真的,那么s1,s2,…sm是递增序列,而as
    m>k
    这与k是最长递增序列长度的假设相矛盾
  • 现在,让我们展示一种算法,通过移动所有元素(但不包括最长递增序列的元素),从
    A
    到达
    B
    。我们将按元素在B中出现的顺序移动元素。我们不会移动作为最长递增序列一部分的元素。如果当前元素是B中的第一个元素,我们只需将其移动到序列的开头。否则,我们将当前元素向右移动到B中上一个元素的位置之后。请注意,此元素可能是我们移动的上一个元素,也可能是最长递增序列中的元素。请注意,在每个步骤中,当我们将要移动索引为
    i
    的元素时,索引为
    1、2、…i-1
    的所有元素都将彼此具有正确的相对位置
编辑:添加一些代码以使答案更清晰。我觉得自己不是javascript方面的专家,所以请随意更正或批评我的解决方案

让我们定义一个函数
transform(a,s)
,它接受两个参数-如语句中所述列出a和b。首先,我将创建一个映射
positions
,将
a
中的每个元素映射到其在s中的位置:

var positions = {};
for (var i = 0; i < a.length; ++i) {
  positions[a[i]] = i;
}
现在,我将不描述如何在
a
中找到关于该比较运算符的最大递增子序列。你可以看看详细的解释如何做到这一点。我将简单地假设我定义了一个函数:

function max_increasing_subsequence(a, positions)
它返回
a
中相对于上面定义的比较运算符
less
的最大递增子序列(使用
位置
)作为列表。我将用你的第二个例子来说明我们目前的情况:

A = [9,1,2,3,0]
S = [0,1,2,3,9]
位置中的值如下所示:

positions = { 0 : 0,
              1 : 1,
              2 : 2,
              3 : 3,
              9 : 4}
max\u递增子序列(a,位置)
的结果将是
[1,2,3]
。顺便说一下,如果
a
中可能存在重复元素,则最好返回索引,而不是
max\u increasing\u subsequence
中的元素(在此特定示例中,差异将不可见)

现在,我将创建另一个帮助器映射,以指示最大递增子序列中包含的元素:

var included = {};
l = max_increasing_subsequence(a, positions);
for (var i = 0; i < l.length; ++i) {
  included[l[i]] = true;
}
请注意,在上面的解决方案中,我假设每次记录新命令时,都是在执行所有以前的命令之后,根据数组
a
的顺序进行记录

所以总的来说,我认为转换应该是这样的:

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]);
    }
  }
}
函数变换(a,s){
var位置={};
对于(变量i=0;i=0;--i){//注意s.length-2-不要处理最后一个元素
如果(!(包括s[i]){
log(“移动”+s[i]+”到“+s[i+1]);
}
}
}

我希望这段代码能让我的答案更清楚

如果您将两个列表视为两个字符串(例如,数字是ASCII编码中的值),那么问题就相当于找到允许您将第一个字符串转换为第二个字符串的操作。操作的数量依次是字符串之间的Levenshtein或edit距离

可以通过在矩阵中存储两个字符串的所有前缀之间的距离,然后回溯步骤,在矩阵的每一行找到最佳操作(需要最少操作才能到达的操作)

@IvayloStrandjev提出的最长递增子序列算法与最长公共子序列问题有关,而最长公共子序列问题又与最长公共子序列问题有关
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]);
  }
}
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]);
    }
  }
}
import argparse

import numpy as np


class Levenshtein(object):
    def __init__(self, string1, string2):
        self.string1 = string1
        self.string2 = string2
        self.scores_matrix = np.zeros(
            (len(self.string1) + 1, len(self.string2) + 1), dtype=np.int16)
        self.operations_matrix = np.empty_like(
            self.scores_matrix, dtype=(np.str_, 16))
        self.total_steps = 0

    def distance(self):
        m = len(self.string1) + 1
        n = len(self.string2) + 1
        for i in range(m):
            self.scores_matrix[i, 0] = i
        for j in range(n):
            self.scores_matrix[0, j] = j
        for j in range(1, n):
            for i in range(1, m):
                if self.string1[i - 1] == self.string2[j - 1]:
                    self.scores_matrix[i, j] = self.scores_matrix[i - 1, j - 1]
                    self.operations_matrix[i, j] = 'match'
                else:
                    self.scores_matrix[i, j] = self.select_operation(i, j)
                if j == n - 1:  # a row is complete
                    self.determine_best_op_and_print(i)
        return self.scores_matrix[m - 1, n - 1]

    def select_operation(self, i, j):
        possible_ops = ['delete', 'insert', 'substitute']
        ops_scores = [
            self.scores_matrix[i - 1, j] + 1,  # deletion
            self.scores_matrix[i, j - 1] + 1,  # insertion
            self.scores_matrix[i - 1, j - 1] + 1]  # substitution
        chosen_op = min(ops_scores)
        chosen_op_name = possible_ops[ops_scores.index(chosen_op)]
        self.operations_matrix[i, j] = chosen_op_name
        return chosen_op

    def determine_best_op_and_print(self, i):
        reversed_row = self.scores_matrix[i][::-1]
        reversed_pos_min = np.argmin(reversed_row)
        pos_min = len(self.scores_matrix[i]) - (reversed_pos_min + 1)
        best_op_name = self.operations_matrix[i, pos_min]
        if best_op_name != 'match':
            self.total_steps += 1
            print best_op_name, self.string1[i - 1], self.string2[pos_min - 1]


def parse_cli():
    parser = argparse.ArgumentParser()
    parser.add_argument('--list', nargs='*', required=True)
    return parser.parse_args()

if __name__ == '__main__':
    args = parse_cli()
    A = args.list
    S = sorted(A)
    lev = Levenshtein(A, S)
    dist = lev.distance()
    print "{} total steps were needed; edit distance is {}".format(
        lev.total_steps, dist)
$ python levenshtein.py --list 8 1 2 3
substitute 8 1
1 total steps were needed; edit distance is 2

$ python levenshtein.py --list 9 1 2 3 0
substitute 9 0
substitute 0 9
2 total steps were needed; edit distance is 2
sequence = [seq2.index(element) for element in seq]
if len(sequence) <= 1:
    return 0, sequence
else:
    firstHalf = sequence[:int(len(sequence)/2)]
    secondHalf = sequence[int(len(sequence)/2):]
    count1, firstHalf = mergeSortInversionCount(firstHalf)
    count2, secondHalf = mergeSortInversionCount(secondHalf)
    firstN = len(firstHalf)
    secondN = len(secondHalf)
    secondHalfEnd = secondN
    count3 = count1 + count2
    # Count the inversions in the merge
    # Uses a countdown through each sublist
    for i in xrange(firstN-1, -1, -1):
        x = firstHalf[i]
        inversionFound = False
        for j in xrange(secondHalfEnd-1,-1,-1):
            if x > secondHalf[j]:
                inversionFound = True
                break
        if inversionFound:
            secondHalfEnd = j+1
            count3 += j+1
    mergeList = firstHalf + secondHalf
    mergeList.sort()
    return count3, mergeList