How come these two outputs differ if 2 subsequent 'if' statements is the equivalent of saying "If statement 1 is true and statement 2 is true, return 'i'..
public int majorityElement(int[] nums) {
if (nums.length == 1)
return nums[0];
HashMap<Integer, Integer> elements = new HashMap<>();
for(int i : nums) {
if(elements.containsKey(i) && (elements.get(i) 1 > nums.length / 2)) {
return i;
} else {
elements.put(i, elements.getOrDefault(i,0) 1);
}
}
return -999;
}
/*
Input
nums = [2,2,1,1,1,2,2]
Output: 2
Expected: 2
*/
Compared to this snippet:
public int majorityElement(int[] nums) {
if (nums.length == 1)
return nums[0];
HashMap<Integer, Integer> elements = new HashMap<>();
for (int i : nums) {
if(elements.containsKey(i)){
if(elements.get(i) 1 > nums.length / 2){
return i;
}
} else {
elements.put(i, elements.getOrDefault(i,0) 1);
}
}
return -999;
}
/*
Input
nums = [2,2,1,1,1,2,2]
Output: -999
Expected: 2
*/
CodePudding user response:
Well, time to find a phone, you have a call to make.
The difference isn't in the if
. Indeed, this:
if (a) {
if (b) { foo(); }
}
is semantically identical to:
if (a && b) { foo(); }
even including the shortcircuiting behaviour (in both of those, if a
resolves to false
, expression b
is not calculated at all. So if b
has sideeffects, say its someMethod()
where the method changes things or prints things, or it's a side-effect-having expression like c > 5
(which as a side effect, increments c), that method doesn't run, and c doesn't get incremented.
What's different is the else
, though. Your first snippet does:
if (a) {
if (b) { foo(); }
} else {
bar();
}
and your second is:
if (a && b) foo();
else bar();
foo() is invoked only if both a
and b
. However, bar()
in the first snippet is invoked if not a. Whereas in the second case it's invoked if not a or not b.
In your first snippet, it boils down to:
a=true | a=false | |
---|---|---|
b=true | foo() |
bar() |
b=false | nothing happens | bar() |
your second one is subtly different:
a=true | a=false | |
---|---|---|
b=true | foo() |
bar() |
b=false | bar() |
bar() |
CodePudding user response:
It's AND in the sense that the code inside the block only execute if both conditions are true
if(elements.containsKey(i) && (elements.get(i) 1 > nums.length / 2)){
return i;
}
same as
if(elements.containsKey(i)){
if(elements.get(i) 1 > nums.length / 2){
return i;
}
}
But you also have an else statement, and the behavior is different for that part since the else is for the outer condition only:
if(!(elements.containsKey(i) && (elements.get(i) 1 > nums.length / 2))){
elements.put(i, elements.getOrDefault(i,0) 1);
}
is not the same as
if(!(elements.containsKey(i)){
elements.put(i, elements.getOrDefault(i,0) 1);
}
CodePudding user response:
The two techniques you provide are not at all equivalent. In the first example, it is possible that the following might happen:
elements.containsKey(i) <-- true
elements.get(i) 1 > nums.length / 2 <-- false
In this case, neither the
return i
nor the
elements.put(i, elements.getOrDefault(i,0) 1);
Will be executed and your code will produce unexpected results. Hence your question here.
CodePudding user response:
Your first example has only two possible states:
if (a && b) {
state 1 // your code returns, so you don't even need "else" in this case
} else {
state 2 // your code updates the list
}
but your second example has three:
if (a) {
if (b) {
state 1 // the return call
}
state 3 // you do not have code here, so it "kicks in" but does nothing
} else {
state 2 // the update call
}
So in a situation where a
is true, but b
is not, you hit state 3 instead of state 2, and because you have no code there, nothing happens:
- we don't return so we stay in the function, and
- we don't hit the
else
becausea
was true, so:
Nothing gets updated.
At every iteration of the loop we end up "doing nothing", the loop finishes, and we hit the end of the function where you return -999.