【问题标题】:If condition can be either true or false, why is it necessary如果条件可以为真或假,为什么有必要
【发布时间】:2019-04-05 13:15:52
【问题描述】:

我对此感到非常困惑。该代码是生成给定整数列表的所有排列。一旦你这样做了,他们会添加另一个约束,即给定的输入可以有重复,我们只需要唯一的排列。

我的代码有效...我只是对我注意到的一些事情感到惊讶。在查看了代码之后,我质疑我所拥有的特定条件是否是必要的,所以我否定它,看看会发生什么。该代码在 100 个测试用例中仍然可以正常工作。本质上,无论此条件是true 还是false,此代码都有效。

很自然,我想我可以删除条件,因为它似乎没有必要。长话短说......代码现在返回一个空的结果集。我希望比我更聪明的人能解释一下这是怎么可能的,因为我现在怀疑我是否属于这个行业。

有问题的代码行是:

if(seen[i] || (i > 0 && nums[i] == nums[i - 1] && !seen[i - 1]))

特别是!seen[i - 1] 如果您按原样运行此代码,它可以工作。如果您删除否定并将其作为seen[i - 1] 运行,它仍然有效。如果您完全删除 !seen[i - 1] 使得条件看起来像:

if(seen[i] || (i > 0 && nums[i] == nums[i - 1])) 然后代码返回空结果集。我完全糊涂了。

我使用[1,1,2] 作为方法的输入,我的预期结果集是:[[1,1,2],[1,2,1],[2,1,1]]

class PermutationGenerator {
  List<List<Integer>> result = new ArrayList<>();

  public List<List<Integer>> permuteUnique(int[] nums) {
    if(nums == null || nums.length == 0){
        return result;
    }
    Arrays.sort(nums);
    backtrack(nums, new ArrayList<>(), new boolean[100]);
    return result;
   }

  private void backtrack(int[] nums, List<Integer> permutation, boolean[] seen){
    if(permutation.size() == nums.length){
        result.add(new ArrayList<>(permutation));
        return;
    }

    for(int i = 0; i < nums.length; i++){
        if(seen[i] || (i > 0 && nums[i] == nums[i - 1] && !seen[i - 1])){
            continue;
        }
        seen[i] = true;
        permutation.add(nums[i]);
        backtrack(nums, permutation, seen);
        seen[i] = false;
        permutation.remove(permutation.size() - 1);
    }
  }
}

我的问题很简单,这怎么可能?无论是真还是假,代码都可以工作,但完全删除它是行不通的。

【问题讨论】:

  • 实际上,我不知道它是如何工作的,因为你在第一次迭代时尝试seen[i - 1] 时有java.lang.IndexOutOfBoundsException
  • @Dred 条件也有i &gt; 0,所以不确定你是如何越界异常的。
  • @Patrick 是的,我已经尝试了很多不同的这种有条件的安排。删除|| 会产生重复排列,这是我们想要避免的,因此仅将条件设置为seen[i] 是不够的。此外,如果是这种情况,则在删除有问题的部分时代码仍然可以工作,因为条件的第一部分优先。如果seen[i] 足够,则代码的其他部分将永远不会被执行。
  • 是的,我删除了评论,因为我误读了这个问题,我不确定是什么原因导致它给出了相同的否定结果。可能需要使用调试器单步执行它并查看 i、nums[i] 等的值,以了解此条件在做什么
  • 我建议在纸上写出并逐步完成程序,或者使用调试器。否定似乎在做同样的事情,但它会改变是否在递归调用或我相信的 for 循环中找到重复项。无论哪种方式都有效,但绝对需要条件。

标签: java algorithm permutation


【解决方案1】:

我可以确认,无论是否否定条件的最后一部分,您的代码都会产生相同的结果,并且当条件被删除时,它会产生不同的结果。

这似乎是一个奇迹,除非您考虑到整个条件在循环中被多次评估,并且很可能这三种情况(有条件、有否定条件、无条件)都有不同的处理方式并得出结果。我想说的是,在条件和否定条件下,可以达到相同的结果但方式不同

这里就是这种情况。如果您在循环中引入一些 printf-debugging,您将看到以完全不同的方式达到结果。带有否定的现有条件让完整的条件在其他迭代中变为真,而不是没有否定的条件。最终两者都导致相同的结果纯属偶然(无需进一步研究算法)。

这里是数字i的执行轨迹,完整条件的结果,以及numsseenresult的中间值在这个位置:

无条件:

0 F [1, 1, 2] [0, 0, 0] []
0 T [1, 1, 2] [True, 0, 0] []
1 T [1, 1, 2] [True, 0, 0] []
2 F [1, 1, 2] [True, 0, 0] []
0 T [1, 1, 2] [True, 0, True] []
1 T [1, 1, 2] [True, 0, True] []
2 T [1, 1, 2] [True, 0, True] []
1 T [1, 1, 2] [False, 0, False] []
2 F [1, 1, 2] [False, 0, False] []
0 F [1, 1, 2] [False, 0, True] []
0 T [1, 1, 2] [True, 0, True] []
1 T [1, 1, 2] [True, 0, True] []
2 T [1, 1, 2] [True, 0, True] []
1 T [1, 1, 2] [False, 0, True] []
2 T [1, 1, 2] [False, 0, True] []

条件为seen[i-1]:

0 F [1, 1, 2] [0, 0, 0] []
0 T [1, 1, 2] [True, 0, 0] []
1 T [1, 1, 2] [True, 0, 0] []
2 F [1, 1, 2] [True, 0, 0] []
0 T [1, 1, 2] [True, 0, True] []
1 T [1, 1, 2] [True, 0, True] []
2 T [1, 1, 2] [True, 0, True] []
1 F [1, 1, 2] [False, 0, False] []
0 F [1, 1, 2] [False, True, False] []
0 T [1, 1, 2] [True, True, False] []
1 T [1, 1, 2] [True, True, False] []
2 F [1, 1, 2] [True, True, False] []
1 T [1, 1, 2] [False, True, False] [[1, 1, 2]]
2 F [1, 1, 2] [False, True, False] [[1, 1, 2]]
0 F [1, 1, 2] [False, True, True] [[1, 1, 2]]
1 T [1, 1, 2] [False, True, True] [[1, 1, 2], [1, 2, 1]]
2 T [1, 1, 2] [False, True, True] [[1, 1, 2], [1, 2, 1]]
2 F [1, 1, 2] [False, False, False] [[1, 1, 2], [1, 2, 1]]
0 F [1, 1, 2] [False, False, True] [[1, 1, 2], [1, 2, 1]]
0 T [1, 1, 2] [True, False, True] [[1, 1, 2], [1, 2, 1]]
1 T [1, 1, 2] [True, False, True] [[1, 1, 2], [1, 2, 1]]
2 T [1, 1, 2] [True, False, True] [[1, 1, 2], [1, 2, 1]]
1 F [1, 1, 2] [False, False, True] [[1, 1, 2], [1, 2, 1]]
0 F [1, 1, 2] [False, True, True] [[1, 1, 2], [1, 2, 1]]
1 T [1, 1, 2] [False, True, True] [[1, 1, 2], [1, 2, 1], [2, 1, 1]]
2 T [1, 1, 2] [False, True, True] [[1, 1, 2], [1, 2, 1], [2, 1, 1]]
2 T [1, 1, 2] [False, False, True] [[1, 1, 2], [1, 2, 1], [2, 1, 1]]

加上否定条件!seen[i-1]

0 F [1, 1, 2] [0, 0, 0] []
0 T [1, 1, 2] [True, 0, 0] []
1 F [1, 1, 2] [True, 0, 0] []
0 T [1, 1, 2] [True, True, 0] []
1 T [1, 1, 2] [True, True, 0] []
2 F [1, 1, 2] [True, True, 0] []
2 F [1, 1, 2] [True, False, False] [[1, 1, 2]]
0 T [1, 1, 2] [True, False, True] [[1, 1, 2]]
1 F [1, 1, 2] [True, False, True] [[1, 1, 2]]
2 T [1, 1, 2] [True, False, True] [[1, 1, 2], [1, 2, 1]]
1 T [1, 1, 2] [False, False, False] [[1, 1, 2], [1, 2, 1]]
2 F [1, 1, 2] [False, False, False] [[1, 1, 2], [1, 2, 1]]
0 F [1, 1, 2] [False, False, True] [[1, 1, 2], [1, 2, 1]]
0 T [1, 1, 2] [True, False, True] [[1, 1, 2], [1, 2, 1]]
1 F [1, 1, 2] [True, False, True] [[1, 1, 2], [1, 2, 1]]
2 T [1, 1, 2] [True, False, True] [[1, 1, 2], [1, 2, 1], [2, 1, 1]]
1 T [1, 1, 2] [False, False, True] [[1, 1, 2], [1, 2, 1], [2, 1, 1]]
2 T [1, 1, 2] [False, False, True] [[1, 1, 2], [1, 2, 1], [2, 1, 1]]

这三种情况的执行步骤都不同。两个(偶然)有相同的结果。

【讨论】:

    【解决方案2】:

    当您删除 seen[i-1] 或 !seen[i -1] 时,对于 2 个或更多 int 数组值匹配且满足的输入类型

      nums[i] == nums[i - 1]
    

    if 条件为 TRUE 并迭代 int 数组,而不添加。

    并且“permutation.add”和“permutation.remove”被依次调用,对于第一个/最后一个元素导致一个空集。尝试使用 {1,1,2} OR {1,2,2} OR {1,2,1} 时的调用顺序

    Add called
    Add called
    Remove called
    Remove called
    Add called
    Add called
    Remove called
    Remove called
    []
    

    对于{2,2,2}

    Add called
    Remove called
    []
    

    使用的代码:

           for(int i = 0; i < nums.length; i++){
                //System.out.println(seen[i]);
                if(seen[i] || (i > 0 && nums[i] == nums[i - 1])){
                    //System.out.println("Inside if");
                    continue;
                }
                seen[i] = true;
                System.out.println("Add called");
                permutation.add(nums[i]);
                backtrack(nums, permutation, seen);
                seen[i] = false;
                System.out.println("Remove called");
                permutation.remove(permutation.size() - 1);
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-07
      • 2015-12-05
      • 2022-10-24
      • 1970-01-01
      • 2019-01-30
      • 2018-07-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多