& 1 JavaScript. How does it work? Clever or good? [duplicate] - javascript

This question already has answers here:
Is there a & logical operator in Javascript
(8 answers)
Closed 6 years ago.
I'm looking over the solutions for a CodeWars problem (IQ Test) in which you're given a string of numbers and all the numbers but 1 are either even or odd. You need to return the index plus 1 of the position of the number that's not like the rest of the numbers.
I'm confused about the line that says & 1 in the solution posted below. The code doesn't work w/ && or w/ the & 1 taken away.
function iqTest(numbers){
numbers = numbers.split(' ')
var evens = []
var odds = []
for (var i = 0; i < numbers.length; i++) {
if (numbers[i] & 1) { //PLEASE EXPLAIN THIS LINE!
odds.push(i + 1)
} else {
evens.push(i + 1)
}
}
return evens.length === 1 ? evens[0] : odds[0]
}
Also, would you consider using & 1 to be best practice or is it just "clever" code?

The single & is a 'bitwise' operator. This specific operator (&) is the bitwise AND operator - which returns a one in each bit position for which the corresponding bits of both operands are ones.
The way it's being used here is to test if numbers[i] is an even or odd number. As i loops from 0 to numbers.length, for the first iteration the if statement evaluates 0 & 1 which evaluates to 0, or false. On the next iteration of the loop, the statement will be 1 & 1, which evaluates to 1, or true.
The result - when numbers[i] & 1 evaluates to 0, or false, then numbers[i] is pushed to the odd array. If numbers[i] & 1 evaluates to 1, or true, then numbers[i] is pushed to the even array.
An alternative to the & operator to test for even and odd is to use the modulo operator. numbers[i] % 2 results in the same output. That is, 1 % 2 results in 1, or true as will any odd number, because an odd number divided by 2 results in a remainder of 1. And any even number, like 2 % 2 results in 0 or false because an even number divided by 2 results in a remainder of 0.
As for your second question, is it 'clever or good?'. It's definitely clever. Whether it's good depends on who you ask and what your goal is. Many would say its less logical and harder to read than using num % 2.

Binary number is 0 and 1 and each of them is called bit.
Single & is add operation and it works bitwise.
like
1 = 01
2 = 10
3 = 11
4 = 100
You can see that every last bit of odd number is 1 and even number is 0.
In add operation
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
So only odd number will return 1 and even number will return 0 and in programming only 0 consider falsy.
If we wanna to check 5 is a odd or even
5 = 101
and perform and(&) operation with 1
101
& 001
-----
001
and value of binary 001 is 1 in 10 base number
So it'll perform easy odd even process.

Related

Improvements in Algo/code for following HackerRank problem

I'm aware, SO is not a place for homework and hence, being very specific to the scope of question.
I was trying to solve this problem on HackerRank: Array Manipulation - Crush. The problem statement is quite simple and I implemented following code:
function arrayManipulation(n, queries) {
const arr = new Array(n).fill(0)
for (let j = 0; j < queries.length; j++) {
const query = queries[j];
const i = query[0] - 1;
const limit = query[1];
const value = query[2];
while (i < limit) {
arr[i++] += value;
}
}
return Math.max.apply(null, arr);
}
Now, it works fine for half the test-cases but breaks with following message: Terminated due to timeout for test-cases 7 - 13 as the time limit is 1 sec.
So the question is, what are the areas where I can improve this code. In my understanding, with current algo, there is not much scope (I may be wrong), so how can I improve algo?
Note: Not looking for alternates using array functions like .map or .reduce as for is faster. Also, using Math.max.apply(context, array) as it is faster that having custom loop. Attaching references for them.
References:
How might I find the largest number contained in a JavaScript array?
Javascript efficiency: 'for' vs 'forEach'
We could make some observations for this problem
Let's keep a running sum representing the current value when we iterate from start to end of the array.
If we break each operation into two other operation (a b k) -> (a k) and (b -k) with (a k) means adding k into the running sum at position a and (b -k) means subtracting k from the sum at position b.
We could sort all of these operations by first their position, then their operator (addition preceding subtraction) we could see that we could always obtain the correct result.
Time complexty O (q log q) with q is the amount of queries.
Example:
a b k
1 5 3
4 8 7
6 9 1
we will break it into
(1 3) (5 -3) (4 7) (8 -7) (6 1) (9 -1)
Sort them:
(1 3) (4 7) (5 -3) (6 1) (8 -7) (9 -1)
Then go through one by one:
Start sum = 0
-> (1 3) -> sum = 3
-> (4 7) -> sum = 10
-> (5 -3) -> sum = 7
-> (6 1) -> sum = 8
-> (8 -7) -> sum = 1
-> (9 -1) -> sum = 0
The max sum is 10 -> answer for the problem.
My Java code which passed all tests https://ideone.com/jNbKHa
This algorithm will help.
https://www.geeksforgeeks.org/difference-array-range-update-query-o1/
Using this algorithm you can solve the problen in O(n+q) where n = size of the array and q = no of queries.
Why your brute force solution will not pass all test cases?
Today generation system can perform 10^8 operation in one second. keep this in mind you have to process N=10^7 input per query in the worse case. as you are using two nested for loops(one for adding K element and other for processing m queries) then the complexity of your solution is O(NM).
if you use your solution with O(NM) complexity it has to handle (10^7 *10 ^5)= 10^12 operation in worse case (which can not be computed in 1 sec at all)
That is the reason you will get the time out error for your brute force solution.
So you need to optimise your code which can be done with the help of prefix sum array.
instead of adding k to all the elements within a range from a to b in an array, accumulate the difference array
Whenever we add anything at any index into an array and apply prefix sum algorithm the same element will be added to every element till the end of the array.
ex- n=5, m=1, a=2 b=5 k=5
i 0.....1.....2.....3.....4.....5.....6 //take array of size N+2 to avoid index out of bound
A[i] 0 0 0 0 0 0 0
Add k=5 to at a=2
A[a]=A[a]+k // start index from where k element should be added
i 0.....1.....2.....3.....4.....5.....6
A[i] 0 0 5 0 0 0 0
now apply prefix sum algorithm
i 0.....1.....2.....3.....4.....5.....6
A[i] 0 0 5 5 5 5 5
so you can see K=5 add to all the element till the end after applying prefix sum but we don't have to add k till the end. so to negate this effect we have to add -K also after b+1 index so that only from [a,b] range only will have K element addition effect.
A[b+1]=A[b]-k // to remove the effect of previously added k element after bth index.
that's why adding -k in the initial array along with +k.
i 0.....1.....2.....3.....4.....5.....6
A[i] 0 0 5 0 0 0 -5
Now apply prefix sum Array
i 0.....1.....2.....3.....4.....5.....6
A[i] 0 0 5 5 5 5 0
You can see now K=5 got added from a=2 to b=5 which was expected.
Here we are only updating two indices for every query so complexity will be O(1).
Now apply the same algorithm in the input
# 0.....1.....2.....3.....4.....5.....6 //taken array of size N+2 to avoid index out of bound
5 3 # 0 0 0 0 0 0 0
1 2 100 # 0 100 0 -100 0 0 0
2 5 100 # 0 100 100 -100 0 0 -100
3 4 100 # 0 100 100 0 0 -100 -100
To calculate the max prefix sum, accumulate the difference array to 𝑁 while taking the maximum accumulated prefix.
After performing all the operation now apply prefix sum Array
i 0.....1.....2.....3.....4.....5.....6
A[i] 0 100 200 200 200 100 0
Now you can traverse this array to find max which is 200.
traversing the array will take O(N) time and updating the two indices for each query will take O(1)* number of queries(m)
overall complexity=O(N)+O(M)
= O(N+M)
it means = (10^7+10^5) which is less than 10^8 (per second)
Note: If searching for video tutorial , you must check it out here for detailed explanation.
I think the trick is not to actually perform the manipulations on arrays.
You can simply track the changes in index-intervals.
Keep a sorted list of intervals ( sorted by begin-index).
e.g. Input: Internal representation
5 3 NOTHING TO DO
1 2 100 [1 2 value 100]
2 5 100 [1 1 value 100][2 2 value 200(100+100)][3 5 value 100]
3 4 100 [1 1 value 100][2 2 value 200(100+100)][3 4 value 200(100+100)][5 5 value 100]
as an optimization you could merge intervals with same value
-> [1 1 value 100][2 4 value 200][5 5 value 100]
In the last step you iterate through your intervals and take the highest value.

Print all possible strings that can be made by placing spaces

I came across this problem.
Print all possible strings that can be made by placing spaces.
I also came across this solution.
var spacer = function (input) {
var result = '' ;
var inputArray = input.split('');
var length = inputArray.length;
var resultSize = Math.pow(2,length-1); // how this works
for(var i = 0 ; i< resultSize ; i++){
for(var j=0;j<length;j++){
result += inputArray[j];
if((i & (1<<j))>0){ // how this works
result += ' ' ;
}
}
result += '\n' ;
}
return result;
}
var main = function() {
var input = 'abcd' ;
var result = spacer(input);
console.log(result);
}
main();
I am not getting how the marked lines work?
Can you clarify on what technique is being used? And what is the basic logic behind this? What are some of other areas where we can use this?
Thanks.
Let's take string abcd as an example.
There are 3 possible places where space can be put:
Between "a" and "b"
Between "b" and "c"
Between "c" and "d"
So generally if length of your string is length then you have length - 1 places for spaces.
Assume that each such place is represented with a separate digit in a binary number. This digit is 0 when we don't put space there, and 1 when we do. E.g.:
a b c d
0 0 0 means that we don't put any spaces - abcd
0 0 1 means that we put space between "c" and "d" only - abc d
0 1 0 means that we put space between "b" and "c" only - ab cd
0 1 1 means ab c d
1 0 0 means a bcd
1 0 1 means a bc d
1 1 0 means a b cd
1 1 1 means a b c d
Converting 000, 001, 010, ..., 111 from binary to decimal will give us values 0, 1, 2, ..., 7.
With 3 places for spaces we have 8 options to put them. It's exactly 2^3 or 2^(length - 1).
Thus we need to iterate all numbers between 0 (inclusive) and 2^(length - 1) (exclusive).
Condition (i & (1 << j)) > 0 in the code you provided just checks whether digit at position j (starting from the end, 0-based) is 0 (and we don't need to insert space) or 1 (and space should be added).
Let's take value 6 (110 in binary) for example.
(6 & (1 << 0)) = 110 & 001 = 000 = 0 (condition > 0 is not met)
(6 & (1 << 1)) = 110 & 010 = 010 = 2 (condition > 0 is met)
(6 & (1 << 2)) = 110 & 100 = 100 = 4 (condition > 0 is met)
simple solution Using Javascript
String.prototype.splice = function(idx, rem, str) {
return this.slice(0, idx) + str + this.slice(idx + Math.abs(rem));
};
function printPattern(str, i, n){
if(i==n){
return;
}
var buff = str;
var j = str.length - n + i;
buff = str.splice(j,0," ");
console.log(buff);
printPattern(str, i+1, n);
printPattern(buff, i+1, n);
}
var str = "ABCD"
printPattern(str, 1, str.length);
console.log(str);
There are 2 possibilities between each 2 characters: either has space or not. If spaces are allowed only between characters then the number of possibilities for 4 characters is 2 * 2 * 2 or 2 ^ (length - 1)
resultSize = Math.pow(2, length - 1) says there are 2^n-1 possible ways to print a string given the problem definition. As far as to why that is the number of solutions is pretty easy to understand if you start with a string that has 2 characters and work your way upward. So pretend you have the string "ab". There is two solutions, you can put a space between a and b or you can not put a space between a and b. Lets add a character to get "abc". Well, we already know that there are two solutions for the string "ab" so we need multiply that solution by the number of ways you can put a space between b and c. Which is 2 so that gives us 2 * 2 solutions. You can extend that to a string of n size. So that means that the number of solutions is 2 * 2 * 2 * 2 * ... n - 1. Or in otherwords 2 ^ n-1.
The next part is a little trickier, but its a clever way of determining how many spaces and where they go in any given solution. The bitwise & takes the each bit of two numbers, compares them, then spits out a new number where each bit is a 1 if both the bits of the two numbers were 1, or 0 if the bits were not 1 and 1. For example (binary numbers):
01 & 01 = 01
10 & 01 = 00
Or a bigger example:
10010010 & 10100010 = 10000010
The << operator just moves all bits n position to left where n is the right hand expression (multiply by 2 n times).
For example:
1 << 1 = 2
2 << 1 = 4
2 << 2 = 8
1 << 4 = 8
So back to your code now. Lets break down the if statement
if(i & (1 << j) > 0){ ... }
In english this says, if the number index of the solution we are looking at shares any 1 bits with 1 shifted by the index of the character we are looking at, then put a space after that character. Olexiy Sadovnikov's answer has some good examples of what this would look like for some of the iterations.
Its also worth noting that this is not the only way to do this. You could pretty easily determine that the max number of spaces is n - 1 then just linearly find all of the solutions that have 0 spaces in them, then find all the solutions that have 1 space in them, then 2 spaces .... to n - 1 spaces. Though the solution you posted would be faster than doing it this way. Of course when your talking about algorithms of exponential complexity it ultimately won't matter because strings bigger than about 60 chars will take longer than you probably care to wait for even with a strictly 2^n algorithm.
In answer to the question of how these techniques can be used in other places. Bit shifting is used very frequently in encryption algorithms as well as the bitwise & and | operators.
'''
The idea was to fix each character from the beginning and print space separated rest of the string.
Like for "ABCD":
A BCD # Fix A and print rest string
AB CD # Add B to previous value A and print rest of the string
ABC D # Add C to previous value AB and print rest of the string
Similarly we can add a space to produce all permutations.
Like:
In second step above we got "AB CD" by having "A" as prefix
So now we can get "A B CD" by having "A " as a prefix
'''
def printPermute(arr, s, app):
if len(arr) <= 1:
return
else:
print(app +''+arr[0:s] +' '+ arr[s:len(arr)])
prefix = app + ''+arr[0:s]
suffix = arr[s:len(arr)]
printPermute(suffix, 1, prefix)
printPermute(suffix, 1, prefix+' ') #Appending space
printPermute("ABCDE", 1, '') #Empty string
.pow is a method from Math which stands for "power". It takes two arguments: the base (here 2) and the exponent. Read here for more information.
& is the bitwise AND operator, it takes the two binary representation of the numbers and performs a logical AND, here's a thread on bitwise operators
EDIT: why Math.pow(2,length-1) gives us the number of possible strings?
I remember doing it in an exercise last year in math class, but I'll try to explain it without sums.
Essentially we want to determine the number of strings you can make by adding one or no space in between letters. Your initial string has n letters. Here's the reason why:
Starting from the left or the word after each letter you have two choices
1 - to put a space
2 - not to put a space
You will have to choose between the two options exactly n-1 times.
This means you will have a total of 2^(n-1) possible solutions.

I don't understand what is happening with this XOR

I am working on this problem.
"Given an array, find the int that appears an odd number of times.
There will always be only one integer that appears an odd number of times."
I came up with this solution online:
function findOdd(A) {
var n = 0;
for(var i = 0; i < A.length; i++){
n = n^A[i];
}
return n;
}
This works but I am not sure why and i was hoping someone could explain it to me. I just don't understand the line:
n = n^A[i];
Could you please tell me what it is doing in this instance?
Xoring any number with itself will result in 0. If you know that there's only one number that appears an odd number of times, the others will cancel themselves out by self-xoring, and the answer will be the remaining number that appears an odd number of times.
XOR of two same numbers is always zero. That is,
A^A=0
So, if you XOR a particular number with itself repeatedly for even number of times, the result will be zero.
Here, initially the value of n is zero. The number that will be XOR-ed even number of times, will result zero. And the number that is present odd number of times, say 2m+1number of times, will result in zero for 2m occurrences, and that same number for the final one occurrence.
This is how this solution works.
^ is an exor bit wise operator . so when you do
1 ^ 1 is 0
0 ^ 1 is 1
1 ^ 0 is 1
0 ^ 0 is 0
so to find the odd number of 1's the following code does is
initially result is arr[0] is 1 .
so in the arrary 0^ 0 becomes 0 and 2 ^ 2 becomes 0 and there are 3 1's so 1^1 gets 0 and with 0 ^1 we are leftout with the number which repeats odd nubmer of times
var arr=[1,1,1,0,0,2,2];
var result=arr[0];
for(var i=1;i<arr.length;i++)
result=result ^ arr[i];
console.log(result);
Hope it helps
Bitwise operators work on 32 bits numbers. Any numeric operand in the operation is converted into a 32 bit number. The result is converted back to a JavaScript number. ^ is a bitwise XOR javascript operator.
Bitwise XOR Operator returns a one in each bit position for which the corresponding bits of either but not both operands are ones.
a XOR b yields 1 if a and b are different. The truth table for the XOR operation is:
a b a XOR b
0 0 0
0 1 1
1 0 1
1 1 0
Explanation for expression n = n^A[i];
let A = [1,2,3,4,5]
for n=0, i=0 => 0 ^ A[0] => 0 ^ 1 => converted to binary 0000 ^ 0001 results to 0001 which is equal to 1
for n=1, i=1 => 1 ^ A[1] => 1 ^ 1 => converted to binary 1111 ^ 0010 results to 1101 which is equal to 13
and so on... Hope this solution helps you to understand the above expression and clear your all doubts.

iterating a selection in javascript

This is a simple code to change the style of even numbered list elements but as a newbie, i really did not understand how the following if statement can be true and false. Because i think that key is always true. However, when i run the code, i see that it is not always true. Can someone explain why?
$(document).ready(
function()
{
$('ul#rubberSoul li').each(
function(key)
{
if (key & 1) {
$(this).addClass('rubberSoulEven');
}
}
);
}
);
& operator does a bitwise AND operation on each of the bits of two 32 bit expression (the operands). If the bit value from both the sides are 1, the result is 1. Otherwise, the result is 0. Bitwise ANDing any number with 0 yields 0
For example , take this expression x & y
x value y value result
-----------------------------
1 1 1
1 0 0
0 1 0
0 0 0
So in your case, it is going to check bit representation of key variable value & bit representation of 1 in your if condition and return the result of that.
operand1(key) operand1-binary operand2 operand2-binary result
------------------------------------------------------------------
1 1 1 1 1
2 10 1 01 0
3 11 1 01 1
4 100 1 001 0
key is index of each and (key & 1) is true for odd indexes.
<ul id="rubberSoul ">
<li class="">One</li> # 0
<li class="">Two</li> # 1
<li class="">Three</li> # 2
</ul>
Your If loop will show true for only the second statement (<li class="">Two</li> # 1) as it validates (if (key & 1))

Why does (0 < 5 < 3) return true?

I was playing around in jsfiddle.net and I'm curious as to why this returns true?
if(0 < 5 < 3) {
alert("True");
}
So does this:
if(0 < 5 < 2) {
alert("True");
}
But this doesn't:
if(0 < 5 < 1) {
alert("True");
}
Is this quirk ever useful?
Order of operations causes (0 < 5 < 3) to be interpreted in javascript as ((0 < 5) < 3) which produces (true < 3) and true is counted as 1, causing it to return true.
This is also why (0 < 5 < 1) returns false, (0 < 5) returns true, which is interpreted as 1, resulting in (1 < 1).
My guess is because 0 < 5 is true, and true < 3 gets cast to 1 < 3 which is true.
probably because true is assumed as 1 so
0 < 5 < 3 --> true < 3 --> 1 < 3 --> true
Because true < 3, because true == 1
As to your question whether this quirk is ever useful: I suppose there could be some case where it would useful (if condensed code is what you are after), but relying on it will (most likely) severely reduce the understandability of your code.
It's kind of like using post/pre increment/decrement as a part of bigger expressions. Can you determine what this code's result is at a glance?
int x = 5;
int result = ++x + x++ + --x;
Note: with this code, you can sometimes even get different results depending on the language and compiler.
It's a good idea to make life easy for yourself and the next guy who will read your code. Clearly write out what you actually want to have happen rather then relying on side effects like the implicit conversion of booleans.
The answer to the second part of the question, "is this quirk ever useful?" is perhaps no, as noted by a previous answer, if it is indeed a quirk of the language (Javascript) that true is cast to 1, but that the programmer does not in general view 1 and true (and 0 and false) as the same thing.
If however you have a mental model of 1 being true and 0 being false, then it leads to all sorts of nice boolean techniques that are extremely useful, powerful, and direct. For example, you could increment a counter directly with the result of A > 100, which would increment the counter if A is greater than 100. This technique might be viewed as a quirk or a trick in Java, but in an array or functional language may be idiomatic.
A classic example in the array language APL would be to count the number of items in an array that are (say) greater than 100:
+/A>100
Where if A is the 5 item array 107 22 256 110 3 then:
A>100
yields the 5 item boolean array:
1 0 1 1 0
and summing this boolean result:
+/1 0 1 1 0
yields the final answer:
3
This question is a perfect example of where this technique would be very useful, especially if the problem is generalized to determine if n out of m boolean values are true.
Check if at least two out of three booleans are true
That's easy.
(0 < 5 < 3)
Start with left to right so it evaluates the first 0 < 5. Is it true? Yes. Since TRUE=1, it evaluates 1 < 3. Since 1 is less than 3 so it's true.
Now with this
(0 < 5 < 1)
Is 0 less than 5? Yes. So make it TRUE which also means 1. Now with that fact in mind, it evaluates to (1 < 1). Is 1 less than 1? No, therefore it's false. It has to be equal.
is it evaluating 0<5 which would return 1 for true when 1<3 which is true?
C# want let you do this "Operator '<' cannot be applied to operands of type 'bool' and 'int'"
I ran into this a little while ago in Obj-C and was very puzzled by it. I got the results I wanted by doing something like this:
if(0 < 5 && 5 < 3) {
alert("True");}
Which of course is false so you wouldn't get that "true" alert.
Glad I read this, I now know why.
In addition to python, CoffeeScript is another language that supports chained comparisons, thus 3 < x < 10 would be converted to (3 < x && x < 10) in vanilla JS
0 < 5 < 3
==> ( ( 0 < 5 ) < 3 )
==> true < 3
==> 1 < 3
==> true
A boolean operand when operated over a math operator returns a number.
to check this we do
true + 1 which gives you 2.
So 0 < 5, the returned boolean(true) operated with math operator(<) will return a number. So it boils to 1<3 which returns true
because 0 is less then 5 then that returns true, and by default true is anything including and can be evaluated to 1 which is still less than 3 which again returns true
try phrasing your results as Number()
if(Number(0) < Number(5) < Number(3)) {
alert("True");
}
or try this:
if(Number(0) < Number(5) && Number(5) < Number(3)) {
alert("True");
}
I googled this because I was getting (3 >= 20) //returning true and I guess javascript was trying to check 3 as a boolean because I was getting this value from the elm.getAttribute(); function which console.log(); was printing in String form.

Categories

Resources