断断续续做leetcode,已然数月有余。
做得多了,一种切身感受油然而生:每个人思考问题的方式和角度都是有道可循的,也就是说,一道题上次你用这样的方式解决,这次让你做,即使你已经忘记了上次做过这道题,最终形成的做法和上次大同小异。暂且称之为“思维固定模式论”。
映射到生活中也是如此,这次遇到同样的问题,你使用解决办法了A,并且成功解决了办法,那么下次遇到同样的问题你多半还会使用A办法。这是好事也是坏事,好事是因为A其实就是我们生活的经验,这些经验能够指导我们更好更便捷的处理事情;坏事是因为,这些经验容易让人不假思索,而错过了一些更好更高效的解释办法。
比如:leetcode的discuss区,当我看着着别人的高票解决问题之道,好似看着一道智慧之光,又能隐隐约约听到解题人狡黠的笑声,并沉头低语道:没想到吧!
1.0[位运算] trick one -制作某num的全“1”mask(例如:5-101-111)
学会使用二进制的思维来解决问题
学会使用Integer.highestOneBit(num)方法
见识到简洁代码的威力了吧
例题:476. Number Complement
Given a positive integer, output its complement number. The complement strategy is to flip the bits of its binary representation.
大意为求一个数的二进制取反的int值,例如(5-101-010-2 即返回2)
my solution:
step one:构造表示二进制的字符串
step two:根据二进制字符串一次取反并求值
源码:
public int findComplement(int num) {
String binStr=Integer.toBinaryString(num);
char[] binaStr=binStr.toCharArray();
String compNum="";
for(int i=0;i<binStr.length();i++)
{
String temp=String.valueOf(binaStr[i]);
if(temp.equals("1"))
{
compNum+=0;
}
else {
compNum+=1;
}
}
return getIntFromBinString(compNum);
}
public static int getIntFromBinString(String str)
{
char[] temp=str.toCharArray();
int res=0;
int j=0;
for(int i=temp.length-1;i>0;i--)
{
String st=String.valueOf(temp[i]);
if(st.equals("1"))
{
res+=Math.pow(2, j);
}
j++;
}
return res;
}
better solution:
step one:构造mask,找到highestOneBit
step two:对num取反
step three:上述两个数AND
源码:
public int findComplement(int num) {
return ~num & ((Integer.highestOneBit(num) << 1) - 1);
}
Integer.highestOneBit(num)的详细介绍
简言之就是取到这个数二进制的最高位
1.1[位运算] trick one -为重复而生的异或^运算-无视顺序-高效解决
所有偶数个的重复问题都可以通过异或运算求解
百度面试题
例题:136. Single Number
Given an array of integers, every element appears twice except for one. Find that single one.
很简单的一道题,直接的解题步骤:
两重循环全遍历,时间复杂度:O(n)=n^2
better solution:
对所有数值进行异或运算
源码:
public class Solution {
public int singleNumber(int[] nums) {
int result = 0;
for (int i = 0; i<nums.length; i++)result ^=nums[i];
return result;
}
}
原理就不在多说了
first , we have to know the bitwise XOR in java
0 ^ N = N
N ^ N = 0
无关乎顺序,就酱
题外衍生一下,之前遇到的百度面试题也是类似的解法,题目如下
箱子里有100个黑球和100个白球,每次取出(不放回)两个球,如果取出的两个球是同色则放回一个黑球,如果取出的两个球是不同颜色则放回一个白球,问最后剩一个黑球的概率是多少?
类似的,所谓同色放黑,异色放白,也就是一种异或运算。此处取黑色为“0”,白色为“1”
黑^黑=白^白=1^1=0^0
白^黑=黑^白=1^0
故一百个白球和一百个黑球异或也就是:
1^1^1^1^1^1^1^1^1^1^1^……^0^0^0^0^0^0^0^0^0^0^=0^0=0
所以最后剩一个黑球的概率必然是100%
1.2[位运算] trick one -异或^移位<<与&运算实现加法
从就计算机的角度看基本操作-加减乘除都是基本的寄存器中数据到运算器中运算的复杂化,同样的其他的负责操作又可以由加减乘除复杂化得来。把握底层的实现细节是件好事
例题:371. Sum of Two Integers
Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -.
不用+或-实现加减法
better solution:
step one :^实现a和b的各位相加,&和<<运算实现进位
step two:进位后如果进位数不为0,则循环step one
源码:
public class Solution {
public int getSum(int a, int b) {
return b==0? a:getSum(a^b, (a&b)<<1); //be careful about the terminating condition;
}
}
以上题为例,
a^b实现各位相加(比如:5+6 a^b=1001^1010=0011)
(a&b)<<1实现进位(比如 :5+6 a&b<<1=10000)
由于b不等于零,然后将b&到前面的a^b中即得到了:10011=11;
1.3 [位运算]trick one -异实现字符的查差
做题时,要有一种将字母和数字,将数字和二进制位统一起来的意识
举个栗子:看到”a’的时候要能够看到它其实是一个八位的ascall码