摘自菜鸟教程
^可以利用实现相加并且不进位(a^b 为a+b在不考虑进位的情况下)
&可以实现地板除以2,实现进位(a&b <<1 为a+b的进位)
在该题不允许使用加减乘除,因此使用位运算,在我们^得到不进位的情况下加上&<<1就是+号的效果。
但是要注意在进位情况下,想要添加上进位效果又要使用+号,因此需要再次进行不进位+进位,当进位的值被一直^到0以后,就可以实现加法
思路:
c = (a&b)<<1 (进行左移一位得到可以加的进位)
a = a^b (进行不考虑进位的加法运算)
b = c (将进位赋值给b,循环进行前两步,最后b为0时a就为最终答案)
code:
/**
* @param {number} a
* @param {number} b
* @return {number}
*/
var add = function(a, b) {
var c ;
while(b){
c = (a&b)<<1;
a = a^b;
b = c;
}
return a;
};
利用&与运算,当n&1为1时结果加1,循环进行右移一位即可
这里有一个坑,提交遇到大数值时会超出时间限制,因为右移运算的问题
JavaScript带符号整数表示范围(默认最大2147483647)如果被超过,符号位就会被占用(是一个不带符号的整数),在>>时会被认为是一个负数,而在算术移位时把它认定为负数会导致循环。
而>>是算术移动,相当于//2,>>>是不考虑符号位的逻辑移动因此使用>>>并不会出现问题。
/**
* @param {number} n - a positive integer
* @return {number}
*/
var hammingWeight = function(n) {
var res = 0;
while(n){
res += n&1;
n>>>=1
}
return res;
};
改进:
我们知道n&0为0,n&1如果n末尾是1则为1,如果使用n-1&n的话,n为1的位就必变为0,并且这样每次总会有一个1进入并且其变为0,减少了移位的操作。
/**
* @param {number} n - a positive integer
* @return {number}
*/
var hammingWeight = function(n) {
var res = 0;
while(n){
n &= n-1;
res ++;
}
return res;
};
首先我们知道如果数组中i出现了两次,其进行异或运算之后,因为相等所以会变为0,因此可以遍历数组来进行异或运算最终结果为数组中两个数都没有重复出现的异或运算结果,因为无法利用这个数分割为两个数,所以需要分两部分来进行求解两个值。
定义一个变量为1,用1与所有数的异或结果做运算,如果为0则前移一位,因为异或的性质问题,如果当前位与1做与运算后为1,则证明那两个数在当前位置做异或的结果为1(1&1 = 1,其他情况都不为1),而异或结果为1则证明那两个数在该位置的值不同,进而分为两波。
code:
/**
* @param {number[]} nums
* @return {number[]}
*/
var singleNumbers = function(nums) {
var a = 0,b = 0,temp = 0,i;
for(i of nums){
temp = temp ^ i;
}
var t = 1;
while(!(temp & t)){
t<<=1;//找到答案当中不为0的位,此位的两个数异或结果为1证明两个数是不同的
}
for(i of nums){
if(t&i)a^=i;
else b^=i;
}
return [a,b]
};
剑指 Offer 56 - II. 数组中数字出现的次数 II
该题说明了数组中只有一个数没有出现三次,可以定义两个集合用一次遍历来得知所有出现过的数值以及重复的数值,之后在所有出现的数值当中写一个filter方法,过滤掉重复的数值,留下来的结果就是唯一的值。
filter的写法与sort方法非常相似,均为写一个函数。
code:
/**
* @param {number[]} nums
* @return {number}
*/
var singleNumber = function(nums) {
var s1 = new Set();
var s2 = new Set();
for(var i of nums){
if(s1.has(i)){
s2.add(i);
}
else{
s1.add(i);
}
}
var res = [...s1].filter(function(x){return !s2.has(x)});
return [...res][0];
};