Ternary operator confusion in Java.

huangapple go评论120阅读模式
英文:

Ternary operator confusion in Java

问题

以下是您提供的代码的中文翻译:

我正在解决LeetCode 437路径总和 III问题https://leetcode.com/problems/path-sum-iii/
我的原始代码如下已通过所有测试

public int pathSum(TreeNode root, int sum) {
    if (root == null) {
        return 0;
    }
    return pathSumStartWithRoot(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum);
}

private int pathSumStartWithRoot(TreeNode root, int sum) {
    if (root == null) return 0;
    int res = root.val == sum ? 1 : 0;
    return res
        + pathSumStartWithRoot(root.left, sum - root.val) 
        + pathSumStartWithRoot(root.right, sum - root.val);
}

关于私有方法中的 int res = root.val == sum ? 1 : 0;,我理解您的困惑。当我试图简化代码时,我删除了这行并将返回值更改为:

return root.val == sum ? 1 : 0 
   + pathSumStartWithRoot(root.left, sum - root.val) + pathSumStartWithRoot(root.right, sum - root.val);

然而,这个更改导致了一些测试失败。例如,

TreeNode: [1,-2,-3,1,3,-2,null,-1], Sum: -1

正确的输出应该是4,但通过这个更改后,输出变成了3。

更令人惊讶的是,当我改变加法的顺序,例如将三元运算符放在最后:

return pathSumStartWithRoot(root.left, sum - root.val) 
+ pathSumStartWithRoot(root.right, sum - root.val)
+ root.val == sum ? 1 : 0;

输出变成了2。

我真的不知道发生了什么。在我看来,加法的顺序不应该影响最终结果。我对三元运算符不是很熟悉,我猜测这个问题可能是由于不正确的使用引起的?我在互联网上搜索了很多,但仍然找不到原因。感谢任何人的解释。

英文:

I am doing LeetCode 437 Path Sum III https://leetcode.com/problems/path-sum-iii/
and my original code is as follows which passed all tests:

public int pathSum(TreeNode root, int sum) {
        if (root == null) {
            return 0;
        }
        return pathSumStartWithRoot(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum);
    }
    
    private int pathSumStartWithRoot(TreeNode root, int sum) {
        if (root == null) return 0;
        int res = root.val == sum ? 1 : 0;
        return res
            + pathSumStartWithRoot(root.left, sum - root.val) 
            + pathSumStartWithRoot(root.right, sum - root.val);
    }

My confusion is from int res = root.val == sum ? 1 : 0; in the private method. When I tried to shorten my code, I deleted this line and changed the return value to

    return root.val == sum ? 1 : 0 
   + pathSumStartWithRoot(root.left, sum - root.val) + pathSumStartWithRoot(root.right, sum - root.val);

However, this change caused some tests to fail. For example,

> TreeNode: [1,-2,-3,1,3,-2,null,-1], Sum: -1

The correct output should be 4 but with this change the output is 3.

More surprisingly, when I change the order of addition, say put the ternary to the last:

        return pathSumStartWithRoot(root.left, sum - root.val) 
        + pathSumStartWithRoot(root.right, sum - root.val)
        + root.val == sum ? 1 : 0;

the output is changed to 2.

I really had no idea what happened here. In my opinion, the order of addition should not matter the final result. I'm not very familiar with the ternary operator and I guess this issue might be due to the incorrect use? I searched a lot on the Internet but still couldn't find out the reason. Thanks for anyone's explanation.

答案1

得分: 5

> 在我看来

不幸的是,你的看法对编译器不相关。

int a = condition ? 1 : 0;
int b = a + c;

等同于:

int b = (condition ? 1 : 0) + c;

而不等同于:

int b = condition ? 1 : 0 + c;

因为这与以下表达式相同:

int b = condition ? 1 : (0 + c);

这是因为 + 的优先级高于 ?:。(查看运算符的优先级表)。

所以,如果你想内联条件表达式,需要使用括号来表示预期的优先级。

return (root.val == sum ? 1 : 0)
    // ^-----------------------^ 额外的括号。
   + pathSumStartWithRoot(root.left, sum - root.val)
   + pathSumStartWithRoot(root.right, sum - root.val);
英文:

> In my opinion

Unfortunately, your opinion isn't relevant to the compiler.

int a = condition ? 1 : 0;
int b = a + c;

is equivalent to:

int b = (condition ? 1 : 0) + c;

It's not equivalent to:

int b = condition ? 1 : 0 + c;

because that's the same as:

int b = condition ? 1 : (0 + c);

owing to + having higher precedence than ?:. (See table of precedence of the operators).

So if you want to inline the conditional expression, you need to use parentheses to indicate the intended precedence.

return (root.val == sum ? 1 : 0)
    // ^-----------------------^ Extra parens.
   + pathSumStartWithRoot(root.left, sum - root.val)
   + pathSumStartWithRoot(root.right, sum - root.val);

答案2

得分: 0

你甚至在面试时也不应该这样做。那个“缩短”代码与算法设计无关,与效率(时间或内存)无关,我猜。

另一个观点是,[tag:java] 和 [tag:c++] 并不适用于编写一行代码。

只需遵循惯例:

public class Solution {
    public final int pathSum(TreeNode root, int sum) {
        HashMap<Integer, Integer> prefixSum = new HashMap<>();
        prefixSum.put(0, 1);
        return helper(root, 0, sum, prefixSum);
    }

    private static final int helper(TreeNode node, int currSum, int target, HashMap<Integer, Integer> prefixSum) {
        if (node == null)
            return 0;

        currSum += node.val;
        int res = prefixSum.getOrDefault(currSum - target, 0);
        prefixSum.put(currSum, 1 + prefixSum.getOrDefault(currSum, 0));
        res += helper(node.left, currSum, target, prefixSum) + helper(node.right, currSum, target, prefixSum);
        prefixSum.put(currSum, prefixSum.get(currSum) - 1);
        return res;
    }
}

参考资料

  • 若要了解更多细节,您可以查看讨论板。那里有许多已接受的解决方案,涵盖了各种编程语言和解释,高效的算法,以及渐近的时间/空间复杂性分析<sup>12</sup>。
英文:

You should not even do that for interviews. That "shortening" code is irrelevant to algorithm design, and has nothing to do with efficiency (time or memory), I guess.

Another point is that [tag:java] and [tag:c++] are not designed for writing one liners.

Just follow the conventions:

public class Solution {
    public final int pathSum(TreeNode root, int sum) {
        HashMap&lt;Integer, Integer&gt; prefixSum = new HashMap&lt;&gt;();
        prefixSum.put(0, 1);
        return helper(root, 0, sum, prefixSum);
    }

    private static final int helper(TreeNode node, int currSum, int target, HashMap&lt;Integer, Integer&gt; prefixSum) {
        if (node == null)
            return 0;

        currSum += node.val;
        int res = prefixSum.getOrDefault(currSum - target, 0);
        prefixSum.put(currSum, 1 + prefixSum.getOrDefault(currSum, 0));
        res += helper(node.left, currSum, target, prefixSum) + helper(node.right, currSum, target, prefixSum);
        prefixSum.put(currSum, prefixSum.get(currSum) - 1);
        return res;
    }
}

References

  • For additional details, you can see the Discussion Board. There are plenty of accepted solutions with a variety of languages and explanations, efficient algorithms, as well as asymptotic time/space complexity analysis<sup>1, 2</sup> in there.

答案3

得分: 0

+ 运算符的优先级高于三元运算符 ?:,因此你的代码部分会首先执行加法操作,然后才是三元运算部分,如下所示:

return ((pathSumStartWithRoot(root.left, sum - root.val) 
        + pathSumStartWithRoot(root.right, sum - root.val)
        + root.val) == sum) ? 1 : 0;

因此,你可以在三元运算部分使用括号来明确优先级:

return pathSumStartWithRoot(root.left, sum - root.val) 
        + pathSumStartWithRoot(root.right, sum - root.val)
        + (root.val == sum ? 1 : 0);
英文:

+ operator precedence is higher than ternary operator ?: so you code

pathSumStartWithRoot(root.left, sum - root.val) 
 + pathSumStartWithRoot(root.right, sum - root.val)+ root.val

this addition part will works first then ternary part like

return ((pathSumStartWithRoot(root.left, sum - root.val) 
        + pathSumStartWithRoot(root.right, sum - root.val)
        + root.val) == sum) ? 1 : 0;

So you can use bracket for tenary portion

return pathSumStartWithRoot(root.left, sum - root.val) 
        + pathSumStartWithRoot(root.right, sum - root.val)
        + (root.val == sum ? 1 : 0);

huangapple
  • 本文由 发表于 2020年7月23日 02:25:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/63040862.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定