Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/461.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_Algorithm_Combinations_Combinatorics_Set Theory - Fatal编程技术网

Javascript 确定从序列中删除一组值的所有可能方式的算法

Javascript 确定从序列中删除一组值的所有可能方式的算法,javascript,algorithm,combinations,combinatorics,set-theory,Javascript,Algorithm,Combinations,Combinatorics,Set Theory,我试图确定我可以用多少种不同的方法从一个序列中删除一组值,使原始序列保持有序(稳定),并确保每个从原始序列中只删除一个实例值。例如,如果我有 [1,2,1,3,1,4,4]我想删除[1,4,4]我得到的组合是: [1,2,1,3,1,4,4]\[1,4,4]=[2,1,3,1],[1,2,3,1],[1,2,1,3]] 或 [1,2,1,3,1,4,4]\[1,1]=[2,3,1,4,4],[1,2,3,4,4],[2,1,3,4,4] 我编写了javascript代码来生成所有数组值的组合,而

我试图确定我可以用多少种不同的方法从一个序列中删除一组值,使原始序列保持有序(稳定),并确保每个从原始序列中只删除一个实例值。例如,如果我有
[1,2,1,3,1,4,4]
我想删除
[1,4,4]
我得到的组合是:

[1,2,1,3,1,4,4]\[1,4,4]=[2,1,3,1],[1,2,3,1],[1,2,1,3]]

[1,2,1,3,1,4,4]\[1,1]=[2,3,1,4,4],[1,2,3,4,4],[2,1,3,4,4]


我编写了javascript代码来生成所有数组值的组合,而无需删除,删除部分看起来应该很简单,但当需要多次删除多个值时,我看不到算法。

这可以通过简单的组合运算完成

为简单起见,假设原始列表中的值为
1,2,3,…,n

a[i]
为原始列表中
i
的发生次数。
b[i]
为值删除列表中
i
的发生次数

减少
i
的选项数量是
Choose(a[i],b[i])=a[i]/((a[i]-b[i])!b[i]!)

由于您将所有这些合并到“和”闭包中,因此可能的总数为:

Choose(a[1],b[1]) * Choose(a[2],b[2]) * ... * Choose(a[n], b[n])
对于不在缩减集中的值,您不需要担心它们。因为它们在
b
列表中的值将为0,并且
为所有
x
选择(x,0)=1


这就为您留下了线性时间解决方案(假设您可以在进行一些预处理以缓存阶乘值之后在恒定时间内计算Choose(,)


在您的示例中,您有:

a = [3, 1, 1, 2]
b = [1, 0, 0, 2]
Choose(3,1) = 3
Choose(1,0) = 1
Choose(1,0) = 1
Choose(2,2) = 1
#number_possibilities = 3 * 1 * 1 * 1 = 3
(因为问题的原始版本不清楚您是要删除子序列还是无序列表,所以我更新了我的答案以解决这两种情况。)

1.按顺序删除子序列

我们得到一个值序列,例如
[1,5,1,3,4,2,3,2,1,3,1,2]
,以及一个要从第一个序列中删除的值子序列,例如
[1,3,2,1]
。如果我们找到每个值实例在序列中的位置,我们会得到这样一个图:

按顺序查找可从序列中删除值的所有方式,则意味着查找可将底部行中待删除值连接到序列中实例的所有方式,而无需任何线交叉,例如:

为了避免以不导致有效解决方案的方式删除值(例如,从删除最右边的值1开始,之后没有可以删除的值3),我们将首先删除图中导致此类无效解决方案的所有连接

这将通过在子序列上迭代两次来完成。首先,我们从左到右执行此操作,对于每个值,我们查看其最左侧的连接,并删除其右侧与该连接相交或交叉的任何连接;例如,当考虑值2的最左侧连接时,其上的值1有两个连接右侧(以红色表示)被删除,因为它们穿过此连接:

在下一步中,我们从右到左,对于每个值,我们查看其最右侧的连接,并从其左侧的值中删除与该连接相交或交叉的任何连接;例如,当考虑右侧的值1的最右侧连接时,从其左侧的值2的最右侧连接(以红色表示)已删除,因为它与此连接交叉:

然后,我们以下面所示的简化图结束。然后,通过使用递归(例如,使用递归)组合子序列中每个值的每个连接实例来进行组合:您迭代子序列中第一个值的选项,并且每次都与子序列的其余部分递归,因此第一个值的选项与其他值的所有选项组合

简化图中可能存在交叉连接,但这些连接不再有问题。在本例中,您将看到,即使为值3选择了正确的连接,也有一个与值2不交叉的连接:

将其转换为代码相对简单;在代码段下面,您将看到一段代码的运行过程,其中包含示例中的数据

函数移除subseq(seq,sub){
var posi=[];//列出seq中值的位置,然后连接到sub中的位置
sub.forEach(函数(elem){posi[elem]=[]});
seq.forEach(函数(元素,索引){if(posi[elem])posi[elem].push(索引)});
var conn=sub.map(函数(elem){return posi[elem].slice()});
对于(变量i=1;i=右){
conn[i].pop();//从右向左删除交叉连接
}
}
var组合=[],结果=[];
组合(0,-1,[]);//启动递归以查找组合
对于(变量i=0;i=0;j--){
结果[i]。剪接(组合[i][j],1);
}
}
返回结果;
函数combine(step,prev,comb){//使用递归生成组合
对于(变量i=0;i=curr)继续;//跳过交叉连接
if(步长+1==conn.length)组合.push(comb.concat([curr]))
[1,2,1,3,1,4,4] / [1,3] 

Hash = {1: [0,2,4], 3: [3]} // for repeated elements in the to-be-removed array,
                            // you could reserve the first element of the index array


Use the multi-set combination algorithm of your choice to make combinations from the 
hashed indexes, like [0,3], [2,3], etc.; and accumulate results without the corresponding elements.
#include<vector>
#include<algorithm>
#include<iostream>
#include"combi.h"
using namespace std;

int main()
{
    vector<int> list {1,2,1,3,1,4,4};
    vector<int> to_remove {1,4,4};
    vector<int> index;
    for(int i=0; i<list.size(); i++) {
        if(find(to_remove.begin(), to_remove.end(), list[i]) != to_remove.end())
            index.push_back(i);//insert index
    }
    bool sequence;
    nCr ncr(index.size(), to_remove.size());
    while(ncr.next()) {
        sequence = true;
        for(int i=0; i<ncr.size(); i++) 
            if(list[index[ncr[i]-1]] != to_remove[i]) sequence = false;
        if(sequence) {
            for(int i=0, j=0; i<list.size(); i++) {
                if(i == index[ncr[j]-1]) j++;
                else cout << list[i] << ' ';
            }
            cout << endl;
        }
    }
}
class Combination
{
public:
    Combination(int n, int r);
    virtual ~Combination() { delete [] ar;}
    int& operator[](unsigned i) {return ar[i];}
    bool next();
    int size() {return r;}

protected:
    int* ar;
    int n, r;
};

class nCr : public Combination
{
public: 
    nCr(int n, int r);
    bool next();
};

Combination::Combination(int n, int r)
{
    ar = new int[r];
    this->n = n;
    this->r = r;
}

nCr::nCr(int n, int r) : Combination(n, r)
{
    if(r == 0) return;
    for(int i=0; i<r-1; i++) ar[i] = i + 1;
    ar[r-1] = r-1;
}

bool nCr::next()
{
    if(r == 0) return false;
    ar[r-1]++;
    int i = r-1;
    while(ar[i] == n-r+2+i) {
        if(--i == -1) return false;
        ar[i]++;
    }
    while(i < r-1) ar[i+1] = ar[i++] + 1;
    return true;
}
[1 2 1 3 1 4 4] \ [1 4 4 1]
(2 3 1)(2 1 3)(1 2 3) 
[1 2 1 3 1 4 4] \ [1 4 4 1 1]
(2 3)
[1 1 1 1 1] \ [1 1 1]
(1 1)
[1] \ [2]
[zero-length array]
[1 2 1 1 4 4 3 8 6 4 1 1 4 3 2 1] \ [1 1 4 1 1 1 3 4 8 6 2 2 4]
(4 3 1)(3 4 1)(1 4 3)(3 1 4)(4 1 3)(1 3 4) 
(1 2 3)(4 5 6)(7 8 9 10) <- Array with 3 "sub-arrays", 3 "elements"
arg = 1,2,1,3,1,4,4   
vec = 1,4,4   
A = 1,4 // The uniques in vec
B = 1,2 // Occurances of them
C = (1 3 5)(6 7) // 1 appears at indexes 1,3,5 in arg, 4 appears at indexes 6,7
D = (1 3 5)(6 7)(6 7) // B is (1,2) so we take (1 3 5) once and (6 7) twice.
(6 6)(6 7)(7 6)(7 7) // (6 7) combined with (6 7) all possible ways
E = (1 6 6)(1 6 7)(1 7 6)(1 7 7)(3 6 6)(3 6 7)(3 7 6)(3 7 7)(5 6 6)(5 6 7)(5 7 6)(5 7 7) // (1 3 5) combined with (6 6)(6 7)(7 6)(7 7) all possible ways
F = (1 6 7)(1 7 6)(3 6 7)(3 7 6)(5 6 7)(5 7 6) // What is left from E
(1 6 7)(1 6 7)(3 6 7)(3 6 7)(5 6 7)(5 6 7) // F with sub-arrays sorted internally
G = (1 6 7)(3 6 7)(5 6 7)                  // Duplicate sub-arrays removed
(1 2 3 4 5 6 7) without (1 6 7) -> (2 3 4 5). arg[2 3 4 5] is (2 1 3 1)
(1 2 3 4 5 6 7) without (3 6 7) -> (1 2 4 5). arg[1 2 4 5] is (1 2 3 1)
(1 2 3 4 5 6 7) without (5 6 7) -> (1 2 3 4). arg[1 2 3 4] is (1 2 1 3)
(2 1 3 1)(1 2 3 1)(1 2 1 3) 
1 2 1 3 1 4 4 {↑∪{c[b~⍵]}¨{(∊⍵≡¨∪¨⍵)/⍵},⊃∘.,/(+/¨a=¨⊂⍵)/((a←∪⍵)=¨⊂⍺)/¨⊂b←⍳⍴c←⍺} 1 4 4
2 1 3 1
1 2 3 1
1 2 1 3
// Algorithm to strip values from an array
// Note, if not all elements of the stripValues array are found this function will return no solutions

function stripValues(startingValues, stripValues) {
    let solutions = []

    searchForSolutions(startingValues, stripValues, solutions, [])

    return solutions
}

function searchForSolutions(startingValues, stripValues, solvedSolutions, possibleSolution) {
    // If there are values to remove
    if(stripValues.length > 0) {
        // Copy the values of any possible solution to avoid tampering
        let newPossibleSolution = []
        possibleSolution.forEach((value) => {
            newPossibleSolution.push(value)
        })

        // Loop through the starting values looking for an instance of the first remaining value to strip
        for(i = 0; i < startingValues.length; i++) {
            if(startingValues[i] == stripValues[0]) {
                // The value was found, so reduce the arrays and look for the next element to remove
                let remainingStripValues = []
                stripValues.forEach((value, index) => {
                    if(index > 0) {
                        remainingStripValues.push(value)
                    }
                })

                let remainingValues = []
                for(j = i + 1; j< startingValues.length; j++) {
                    remainingValues.push(startingValues[j])
                }

                // Reiterate the search
                searchForSolutions(remainingValues, remainingStripValues, solvedSolutions, newPossibleSolution)
            }

            // Whether or not the value was found we want to continue finding permutations 
            newPossibleSolution.push(startingValues[i])
        }
    } else {
        //There are no remaining values to search for, so we have found a solution
        for(i = 0; i < startingValues.length; i++) {
            newPossibleSolution.push(startingValues[i]);
        }

        solvedSolutions.push(newPossibleSolution)
    }
}
  0  a  g  b  a  b  c  c
0 0  0  0  0  0  0  0  0
a 0 ↖1  1  1 ↖1  1  1  1
b 0  1  1 ↖2  2 ↖2  2  2
c 0  1  1  2  2  2 ↖3 ↖3