Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.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
C++ 排列计算中唯一性的困惑_C++_Algorithm - Fatal编程技术网

C++ 排列计算中唯一性的困惑

C++ 排列计算中唯一性的困惑,c++,algorithm,C++,Algorithm,将下面的问题作为一个算法难题来解决。参考了一些类似的解决方案(并在下面发布其中的一个),尝试了一下,效果很好。问题是,对于“swap(num[i],num[k]);”行,我们如何确保始终可以交换到以前从未尝试过的数字(例如,假设我们在for循环的当前迭代中用2交换1,那么我们有可能在递归调用的相同级别/层的相同for循环的下一次迭代中用1交换2)?我有点困惑,因为我们通过引用传递num,很可能稍后(较低级别/层)递归调用会修改num的内容,这会导致我们已经计算过的数字调回。然而,我尝试了,它适用

将下面的问题作为一个算法难题来解决。参考了一些类似的解决方案(并在下面发布其中的一个),尝试了一下,效果很好。问题是,对于“swap(num[i],num[k]);”行,我们如何确保始终可以交换到以前从未尝试过的数字(例如,假设我们在for循环的当前迭代中用2交换1,那么我们有可能在递归调用的相同级别/层的相同for循环的下一次迭代中用1交换2)?我有点困惑,因为我们通过引用传递num,很可能稍后(较低级别/层)递归调用会修改num的内容,这会导致我们已经计算过的数字调回。然而,我尝试了,它适用于我所有的测试用例。想知道下面的解决方案是否100%正确,或者是否碰巧通过了我的测试用例?:)

下面是我正在调试的详细问题说明和代码

给定可能包含重复项的数字集合,返回所有可能的唯一排列

比如说,, [1,1,2]具有以下独特排列: [1,1,2]、[1,2,1]和[2,1,1]

class Solution {
public:
    void recursion(vector<int> num, int i, int j, vector<vector<int> > &res) {
        if (i == j-1) {
            res.push_back(num);
            return;
        }
        for (int k = i; k < j; k++) {
            if (i != k && num[i] == num[k]) continue;
            swap(num[i], num[k]);
            recursion(num, i+1, j, res);
        }
    }
    vector<vector<int> > permuteUnique(vector<int> &num) {
        sort(num.begin(), num.end());
        vector<vector<int> >res;
        recursion(num, 0, num.size(), res);
        return res;
    }
};
类解决方案{
公众:
无效递归(vector num、int i、int j、vector&res){
如果(i==j-1){
res.push_back(num);
返回;
}
对于(int k=i;k
提前感谢,,
Lin

在下面,您可以找到一个用Java编写的解决方案。很抱歉,没有在C++中提供解决方案,我很久没有使用它了。但语法将是类似的

解决方案是使用回溯() 另外,我使用hashset检查唯一性,可能有一个解决方案不使用任何hashset类型的数据结构,因为我的解决方案使用额外的内存来提供唯一的解决方案

样本输入和输出

input  :  [1, 1, 2]
output :  [1, 1, 2]
          [1, 2, 1]
          [2, 1, 1]
解决办法是,

public class permutation {

    public static void main(String[] args) {
        permutation p = new permutation();
        p.permute(new int[] { 1, 1, 2 });
    }

    HashSet<String> set = new HashSet<String>();

    private void permute(int[] arr) {
        set.clear();
        this.permute(arr, 0, arr.length - 1);
    }

    private void permute(int[] arr, int l, int r) {
        if (l == r) {
            String key = Arrays.toString(arr);
            if (set.contains(key))
                return;
            set.add(key);
            System.out.println(key);
        } else {
            for (int i = l; i <= r; i++) {
                swap(arr, l, i);
                permute(arr, l + 1, r);
                swap(arr, i, l);
            }
        }
    }

    private void swap(int[] arr, int l, int r) {
        int tmp = arr[l];
        arr[l] = arr[r];
        arr[r] = tmp;
    }
}
公共类置换{
公共静态void main(字符串[]args){
置换p=新置换();
p、 置换(新的int[]{1,1,2});
}
HashSet=newhashset();
私有无效置换(int[]arr){
set.clear();
此.permute(arr,0,arr.length-1);
}
私有无效置换(int[]arr,int l,int r){
如果(l==r){
字符串键=Arrays.toString(arr);
if(设置包含(键))
返回;
set.add(键);
系统输出打印项次(键);
}否则{

对于(int i=l;i,正如@notmyfriend在评论中所说,
num
实际上是在每个函数调用中复制的。
所以现在可以归结为:

  • 在所有数组值中,选择一个作为第一个数组值并将其放置在那里。
    每个值在循环中循环一次,然后递归:
    • 在第一个值之后的所有值中,选择一个作为第一个值并将其放置在那里
…等等,再加上检查以过滤掉没有变化的掉期,即过滤掉重复项

如果
num
是一个真正的参考,它将不再工作(至少没有额外的步骤)。
例1 2是一个简单的上下文示例,它将给出以下结果:

112, 121, 211, 112, 121  
也就是说,尽管进行了检查,但仍存在重复项(并且可能存在重复项
是一些根本不生成置换的示例)

关于评论:

默认情况下,C++中的每个正常函数参数都复制 (正常=没有明确的参考符号“&”等)。
也许你在考虑C风格的数组:本质上,传递给它的是一个指针(指向第一个值)。指针被复制,但原始和复制的指针都指向同一个内存位置

虽然
std::vector
的目的是(也)包含数组,但向量本身是单个类对象(其中包含指向某个位置的值的指针)。类可以定义自己应该如何复制(使用复制构造函数)。
从技术上讲,向量类可以实现复制作为指针复制,然后它将具有与传递整个向量作为参考的相同效果;但是C++创建者希望保持复制语义,即,复制容器类应该复制所有值的真实拷贝。
对于非复制,已经有引用了…

num没有通过引用传递到
recursion()
-每个调用都会获得一个全新的数字数组副本。在我看来,“if(i!=k&&num[i]==num[k])continue”行创建了大量重复检查,if(num[i]==num[k])更简单继续;这样更好,因为该循环中的第一次遍历不会进入递归调用,而且int j参数始终是num.size,因此您可能需要将其删除simplicity@user1316208没有
i!=k
,第一个递归(没有任何更改/某些内容与自身交换)不会发生=>没有结果。
i!=k
是必需的。@deviantfan在我看来,结果将在for循环中进一步获得。但可能是wrong@user1316208尝试使用12(手动,或代码,你喜欢的)。不会有任何结果(但可能我也错了:)除了错误的语言,OP已经有了一个有效的解决方案(也比你的好),只是不理解它。谢谢DeviceFan,如果它是按值复制的。那我就理解了。但是为什么它是按值复制的?我可能错了,但我认为如果我们传递一个向量if integer,它是按引用传递的?不?谢谢你提供更多的细节。@LinMa看到答案中的加法。谢谢DeviceFan对传递引用行为的澄清对于一个向量,我想知道当只为整型向量或向量传递一个对向量的引用时,是否制作一个真正的副本