Java 中的三元运算符混淆
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 值更改为
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。
我真的不知道这里发生了什么。在我看来,添加的顺序与最终结果无关。我对三元运算符不是很熟悉,我想这个问题可能是由于使用不当造成的?在网上找了很多也没有找到原因。感谢任何人的解释。
In my opinion
很遗憾,您的意见与编译器无关。
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);
由于 +
的优先级高于 ?:
。 (See table of precedence of the operators).
所以如果你想内联条件表达式,你需要使用括号来表示预期的优先级。
return (root.val == sum ? 1 : 0)
// ^-----------------------^ Extra parens.
+ pathSumStartWithRoot(root.left, sum - root.val)
+ pathSumStartWithRoot(root.right, sum - root.val);
你甚至不应该在面试时这样做。我猜,“缩短”代码与算法设计无关,与效率(时间或内存)无关。
遵循约定即可:
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;
}
}
参考资料
+
运算符优先级高于三元运算符 ?:
所以你编码
pathSumStartWithRoot(root.left, sum - root.val)
+ pathSumStartWithRoot(root.right, sum - root.val)+ root.val
这个加法部分将首先起作用,然后是三元部分,例如
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);
我正在做 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 值更改为
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。
我真的不知道这里发生了什么。在我看来,添加的顺序与最终结果无关。我对三元运算符不是很熟悉,我想这个问题可能是由于使用不当造成的?在网上找了很多也没有找到原因。感谢任何人的解释。
In my opinion
很遗憾,您的意见与编译器无关。
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);
由于 +
的优先级高于 ?:
。 (See table of precedence of the operators).
所以如果你想内联条件表达式,你需要使用括号来表示预期的优先级。
return (root.val == sum ? 1 : 0)
// ^-----------------------^ Extra parens.
+ pathSumStartWithRoot(root.left, sum - root.val)
+ pathSumStartWithRoot(root.right, sum - root.val);
你甚至不应该在面试时这样做。我猜,“缩短”代码与算法设计无关,与效率(时间或内存)无关。
遵循约定即可:
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;
}
}
参考资料
+
运算符优先级高于三元运算符 ?:
所以你编码
pathSumStartWithRoot(root.left, sum - root.val)
+ pathSumStartWithRoot(root.right, sum - root.val)+ root.val
这个加法部分将首先起作用,然后是三元部分,例如
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);