Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.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 - Fatal编程技术网

更好地理解查找字符串排列的解决方案-javascript

更好地理解查找字符串排列的解决方案-javascript,javascript,Javascript,我试图更好地理解递归和函数编程,我认为一个很好的实践例子是使用递归和现代方法(如reduce、filter和map)创建字符串的排列 我发现了这段漂亮的代码 const flatte=xs=> x.reduce((cum,next)=>[…cum,…next]); 不带常数=(xs,x)=> 过滤器(y=>y!==x); 常量置换=xs=> 展平(x.map)(x=> xs.长度[x,…perm]) )); 置换([1,2,3]) //[[1,2,3],[1,3,2],[2,1,3],[2,3

我试图更好地理解递归和函数编程,我认为一个很好的实践例子是使用递归和现代方法(如reduce、filter和map)创建字符串的排列

我发现了这段漂亮的代码

const flatte=xs=>
x.reduce((cum,next)=>[…cum,…next]);
不带常数=(xs,x)=>
过滤器(y=>y!==x);
常量置换=xs=>
展平(x.map)(x=>
xs.长度<2
?[xs]
:置换(不带(xs,x)).map(perm=>[x,…perm])
));
置换([1,2,3])

//[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]
要获得所有置换,我们需要执行以下操作:

我们从左到右取数组中的一个元素

 xs.map(x => // 1
对于所有其他元素,我们递归生成置换:

 permutations(without(xs, x)) // [[2, 3], [3, 2]]
对于每一个排列,我们都会添加我们在开始时提取的值:

 .map(perm => [xs, ...perm]) // [[1, 2, 3], [1, 3, 2]]
现在,对所有数组元素重复此操作,结果是:

 [
  // 1
  [[1, 2, 3], [1, 3, 2]],
  // 2
  [[2, 1, 3], [2, 3, 1]],
  // 3
  [[3, 1, 2], [3, 2, 1]]
]
现在我们只需将(…)数组展平即可获得所需的结果

整个过程可以表示为递归调用树:

 [1, 2, 3]
        - [2, 3] -> 
                   - [3] -> [1, 2, 3]
                   - [2] -> [1, 3, 2]
        - [1, 3] ->
                  - [1] -> [2, 3, 1]
                  - [3] -> [2, 1, 3]
        - [1, 2] -> 
                 - [1] -> [3, 2, 1]
                 - [2] -> [3, 1, 2]
为了添加一些控制台日志来调试它,我对它进行了一些分隔

这当然有帮助。但是请记住,简单的递归定义通常会导致复杂的执行跟踪

这实际上是递归如此有用的原因之一。因为有些算法具有复杂的迭代,所以允许使用简单的递归描述。因此,理解递归算法的目标应该是找出其定义中的归纳(而不是迭代)推理

让我们忘掉javascript,专注于算法。让我们看看,我们可以得到集合
a
元素的排列,我们将其表示为
P(a)

注意:在原始算法中,输入是一个列表是不相关的,因为原始顺序根本不重要。同样,我们将返回一组列表而不是一组列表也没有关系,因为我们不关心解决方案的计算顺序

基本情况:

最简单的情况是空集。对于0元素的排列,只有一种解决方案,该解决方案是空序列
[]
。所以

P(A) = {[]}
递归大小写:

为了使用递归,您需要描述如何从
p(A')
中获取
p(A)
,对于一些小于
A
A'

注意:如果你这样做,它就完成了。在操作上,程序将通过使用越来越小的参数连续调用
P
,直到达到基本情况,然后它将从较短的结果中生成较长的结果

因此,这里有一种方法可以编写一个具有n+1个元素的
a
的特殊排列。您需要为每个位置依次选择一个
A
元素:

 _   _ ... _ 
n+1  n     1
所以你选择了一个
x∈ A
用于第一个

 x   _ ... _ 
     n     1
然后你需要在
p(a\{x})
中选择一个排列

这告诉您一种构建大小为
n
的所有排列的方法。考虑<代码> x>代码> >代码< A/COD>(作为第一个元素)的所有可能的选择,并在每次选择“代码> P(A{x})< /C> >之前,将每个代码放在代码> x <代码>之前。最后,结合您为每个
x
选项找到的所有解决方案

让我们使用点运算符表示将
x
放在序列
s
前面,使用菱形运算符表示将
x
放在每个
s前面∈ S
。就是

x⋅s = [x, s1, s2, ..., sn] 
x⟡S = {x⋅s : s ∈ S}
然后对于非空
a

P(A) = ⋃ {x⟡P(A\{x}) : x ∈ A} 
此表达式与case base一起提供集合
a
中元素的所有排列

javascript代码

为了理解您所显示的代码是如何实现这个AlgRoTimthm的,您需要考虑下面的

  • 当您有0或1个元素时,该代码通过编写
    xs.length<2
    来考虑两种基本情况。我们也可以这么做,这无关紧要。你可以把2改成1,它应该还能用

  • 映射对应于我们的操作
    x⟡S={x⋅s:s∈ S} 

  • 不带对应于
    p(A\{x})

  • 展平对应于
    它连接所有解决方案


置换是以循序渐进的方式创建的,它首先检查是否只存在一个元素,然后除了它自身之外没有置换。然后递归地应用一个简单的步骤,尝试每一项并使用REST进行排列。递归魔法如何在排列()中生成排列?一旦它从without()中获取其他元素