同事偷偷给我介绍私活,说1万报酬全给我结果甲方私下告诉我说,同事在当中白拿了2万,我觉得被要了,媳妇却让我要知足,说我一点不亏
嘴上说私活一万全给你,听着像活菩萨,结果甲方那边一抖包袱:哥们在中间白捞了两万。你这哪是接私活,你这是被人当工具人顺手套现了。
最逗的是,媳妇还劝你知足,说反正你也没亏。账不是这么算的。你干活拿一万,没问题;可人家靠你多吃两万,还提前装得跟雷锋似的,这味儿就不对了。评论区有人说,有活就行,别跟钱过不去。也有人说,这种同事以后赶紧拉黑,合作一次长记性。
我看后者靠谱。钱到手不算输,但这人品已经写脸上了。下次他再来介绍“好机会”,你最好先问清楚,别最后活是你干,局是别人做。
面试题:位1的个数
整数明明就在那,二进制里到底塞了几个 1,很多人第一反应还是一位一位右移去数。能做,但我一般第一眼不太信这种写法。原因很简单,32 位整数你就老老实实循环 32 次,数据量一大,这种“每次都扫满”的写法看着就笨。
这题真正值钱的地方,不是会不会转二进制,而是你能不能想到:每做一次运算,就干掉一个 1。
比如 n = 12,二进制是 1100。 做一次 n & (n - 1):
1100
1011
----
1000
最低位那个 1 直接没了。
再来一次:
1000
0111
----
0000
又干掉一个。
12 里有两个 1,所以只需要做两次。这个思路比“固定扫 32 次”顺手得多,尤其是在面试里,写出来就知道不是在背模板。
Java 代码我一般会这么写,够短,也不拧巴:
publicclassSolution{
publicinthammingWeight(int n){
int count = 0;
while (n != 0) {
n = n & (n - 1);
count++;
}
return count;
}
}
这个写法有个好处,count 的次数,刚好就是 1 的个数。整数里有几个 1,循环就跑几次,不多跑。
有人会担心负数。这个题如果用 Java 写,其实也不用慌。Java 的 int 本来就是 32 位补码表示,n & (n - 1) 这个性质对补码一样成立。哪怕是负数,也是在不断消掉二进制里的 1,最后会变成 0。
当然,你也可以写成最朴素的版本:
publicinthammingWeightSlow(int n){
int count = 0;
for (int i = 0; i < 32; i++) {
count += (n >>> i) & 1;
}
return count;
}
注意这里我用了 >>>,不是 >>。这地方很容易写顺手就错。>> 是带符号右移,负数高位会补 1,处理起来容易把自己绕进去;>>> 才是无符号右移,按位看更干净。
这题不难,坑也不深,但很适合看基本功。会写第一种,说明你知道按位运算不是拿来摆设的;只会第二种,也不是不行,就是味道差点。
说到底,这题核心就一句:**n & (n - 1) 每次都会消掉最低位的一个 1。** 后面就只是把这个性质翻成代码而已。