当前位置: 首页 > news >正文

LeetCode_位运算

位运算

    • 1.总结
      • 1.1.异或
      • 1.2.不用额外变量交换两个整数
      • 1.3.所有偶数位为和所有奇数位为1
      • 1.4.针对数组中元素两两组合的写法
      • 1.4.Brian Kernighan 算法
    • 2.异或(力扣136)
    • 3.汉明距离(力扣461)
    • 4.只出现一次的数字(力扣268)
    • 5.只出现一次的数字 III(力扣260)
    • 6.颠倒二进制位(力扣190)
    • 7.2的幂(力扣231)
    • 8.4的幂(力扣342)
    • 9.交替位二进制数(力扣693 )
    • 10.数字的补数(力扣476)
    • 11.两整数之和(力扣371)
    • 12.最大单词长度乘积(力扣318)
    • 13.比特位计数(力扣338)

1.总结

1.1.异或

异或运算有以下三个性质。
1.任何数和 0做异或运算,结果仍然是原来的数,即a^0=a
2.任何数和其自身做异或运算,结果是 0,即a^a=0
3.异或运算满足交换律和结合律,即a^b^a=b^a^a=b^(a^a)=b^0=b

1.2.不用额外变量交换两个整数

给定两个整数a和b
a = a ^ a ^ b = b;
b = b ^ b ^ a = a;

a = a ^ b;
b = a ^ b;
a = a ^ b;

1.3.所有偶数位为和所有奇数位为1

0xaaaaaaaa 和 0xAAAAAAAA 一样,表示所有偶数位为1
0x55555555表示所有奇数位为1

1.4.针对数组中元素两两组合的写法

		for (int i = 0; i < len - 1; i++) {for (int j = i + 1; j < len; j++) {}}
		for(int i = 0;i < len;i ++){for(int j = 0;j < i;j ++){}}

1.4.Brian Kernighan 算法

Brian Kernighan算法可以用于清除二进制数中最右侧的1。x&(x-1)
1.x=111,x-1 = 110,x&(x-1)=110,清除了最右侧的1
2.x=110,x-1 = 101,x&(x-1)=100,清除了最右侧的1

2.异或(力扣136)

//1.异或运算public int singleNumber(int[] nums) {int len = nums.length;int res = nums[0];for(int i = 1;i < len;i ++){res ^= nums[i];}return res;}

3.汉明距离(力扣461)

//1.利用javaAPIpublic static int hammingDistance(int x, int y) {return Integer.bitCount(x ^ y);}
//2.移位计算public static int hammingDistance2(int x, int y) {int z = x ^ y;int count = 0;while (z > 0){//看z的最后一位是否为1count += z & 1;//z右移z >>= 1;}return count;}
//3.Brian Kernighan 算法(只统计1的个数,略过0)public static int hammingDistance3(int x, int y) {int z = x ^ y;int count = 0;while (z != 0){z &= z - 1;count ++;}return count;}

4.只出现一次的数字(力扣268)

//1.数学方法public static int missingNumber(int[] nums) {int sum = 0;for (int i : nums){sum += i;}int len = nums.length;return len * (1 + len) / 2 - sum;}
//2.位运算public static int missingNumber(int[] nums) {int len = nums.length;int sum = 0;for (int i = 0; i < len; i++) {sum ^= (i ^ nums[i]);}return sum ^ len;}

5.只出现一次的数字 III(力扣260)

//1.哈希集合(最先想到的方法)public static int[] singleNumber(int[] nums) {//或者是用map也可以Set<Integer> set = new HashSet<>();for (int i : nums){if (set.contains(i)){set.remove(i);}else{set.add(i);}}int[] res = new int[2];int j = 0;for (int i : set){res[j ++] = i;}return res;}
//2.位运算/** 就是通过先求二进制异或和,选择一个为1的位,那么两个数在这个位上一* 定是一个为1一个为0,通过与运算就可以把它们分组,就变成了只出现一次* 的数字Ⅰ问题,再异或一次就好* */public static int[] singleNumber2(int[] nums) {int nAdd = 0;for (int num : nums){nAdd ^= num;}int i = 1;while ((i & nAdd) == 0){i <<= 1;}int nAdd1 = 0,nAdd2 = 0;for (int num : nums){if ((i & num) != 0){nAdd1 ^= num;}else{nAdd2 ^= num;}}return new int[]{nAdd1,nAdd2};}

6.颠倒二进制位(力扣190)

//1.位运算public int reverseBits(int n) {int res = 0;for(int i = 0;i < 32;i ++){if(n == 0) break;//找到为1的位并反转int temp = ((n & 1) << (31 - i));//将所有反转之后的1组合res |= temp;//n无符号右移n >>>= 1;}return res;}
//2.调用javaAPIpublic int reverseBits2(int n) {return Integer.reverse(n);}

7.2的幂(力扣231)

//1.自己想的,统计1出现的次数public boolean isPowerOfTwo(int n) {int countOne = 0;while(n > 0){countOne += (n & 1);n >>= 1;}return countOne == 1 ? true : false;}
//2.技巧public static boolean isPowerOfTwo2(int n) {//如果n是2的幂次方,则n和n-1的每一个对应位必定是一个为0一个为1return n > 0 && (n & (n - 1)) == 0;}
//3.技巧public static boolean isPowerOfTwo3(int n) {//如果n是2的幂次方,则n和-n按位做与,最终结果定是nreturn n > 0 && (n & -n) == n;}
//4.技巧public static boolean isPowerOfTwo4(int n) {return n > 0 && Integer.bitCount(n) == 1;}

8.4的幂(力扣342)

//1.使用循环public static boolean isPowerOfFour(int n) {while ( n > 0 && Integer.bitCount(n) == 1){if ((n & 1) == 1){return true;}n >>= 2;}return false;}
//2.技巧public static boolean isPowerOfFour2(int n) {//0xaaaaaaaa  和   0xAAAAAAAA 一样,表示所有偶数位为1return n > 0 && (n & (n - 1)) == 0 && (n & 0xaaaaaaaa) == 0;
//        0x55555555表示所有奇数位为1
//        return n > 0 && (n & (n - 1)) == 0 && (n & 0x55555555) != 0;}
//3.技巧public static boolean isPowerOfFour3(int n) {//是2的幂次方并且模上3为1,则为4的幂次方//假设4的幂次方为4^x,则4^x % 3 = 4^(x-1) * (4%3) = 4^(x-1),所以最终为1return n > 0 && (n & (n - 1)) == 0 && n % 3 == 1;}

9.交替位二进制数(力扣693 )

//1.自己想的public static boolean hasAlternatingBits(int n) {//看相邻位是否相同while (n > 0){if ((n & 1) == (n >> 1 & 1)){return false;}n >>= 1;}return true;}
/*2.* 分析:* 如果n是交替的01,对于它右移一位后得到的m,* 存在n跟m在二进制下必然是0和1对应的(对位)。异或运算必定都是1;** 举个栗子:5=101 5>>1=10,5^(5>>1)=111*  101*   10  =111*假设异或结果共有N位为1,则将此结果加1之后,第N+1位为1,从1到N位都为0,*此时再将两者做与运算,则最终结果必为0*/public static boolean hasAlternatingBits2(int n) {int temp=n^(n>>1);return (temp&(temp+1))==0;}
//3.和1的思路是一样的public static boolean hasAlternatingBits3(int n) {while (n > 0){if ((n % 2 == n / 2 % 2)){return false;}n /= 2;}return true;}

10.数字的补数(力扣476)

//1.自己想的public int findComplement(int num) {int res = 0;//用来记录当前到了第几位int count = 0;while(num > 0){//如果当前位为1,则取反为0,不计数if((num & 1) == 1){count ++;}else{//如果当前位为0,则取反为1,计数res += (1 << count);count ++;}num >>= 1;}return res;}
//2.求掩码/*思路:5 -> 101 , 其补码为 010 ,将 101 与 111 做 异或即可达到他对应的补码问题的关键为:求掩码*//*1     ->     111    ->     3111   ->     71111  ->     15...* */public static int findComplement2(int num) {int pre = 1,i = 1;while (pre < num){pre += Math.pow(2,i);i ++;}return pre ^ num;}
//3.思路和1一样public static int findComplement3(int num) {int temp = num;int pre = 0;while(temp > 0){temp >>= 1;pre = (pre << 1) + 1;}return num ^ pre;}

11.两整数之和(力扣371)

//1.位运算//可以将b作为进位来看待public int getSum(int a, int b) {//如果存在进位,就要加入到总和中去while(b != 0){//计算对应位能形成进位的位置int temp = (a & b) << 1;//计算对应位不能形成进位的位置a = a ^ b;b = temp;}//如果不存在进位了,返回结果return a;}

12.最大单词长度乘积(力扣318)

//1.位运算public static int maxProduct(String[] words) {int len = words.length;int[] arr = new int[len];for (int i = 0;i < len;i ++){for (char c : words[i].toCharArray()){/*arr[i]记录的是第i个字符串中26个字母是否出现abc     ->       000111def     ->       111000如果相与为0,则两个字符串中没有相同的字母* */arr[i] |= 1 << (c - 'a');}}int max = 0;for (int i = 0; i < len - 1; i++) {for (int j = i + 1; j < len; j++) {if ((arr[i] & arr[j]) == 0){max = Math.max(max,words[i].length() * words[j].length());}}}
//        for(int i = 0;i < len;i ++){
//            for(int j = 0;j < i;j ++){
//                if ((arr[i] & arr[j]) == 0){
//                    max = Math.max(max,words[i].length() * words[j].length());
//                }
//            }
//        }return max;}

13.比特位计数(力扣338)

//1.分别计算每个数的位为1的个数,再加和,时间复杂度为O(nlogn)public int[] countBits(int n) {int[] ans = new int[n + 1];for (int i = 0; i <= n; i++) {ans[i] = countOne(i);}return ans;}public int countOne(int n) {int res = 0;while (n > 0) {if ((n & 1) == 1) {res++;}n >>= 1;}return res;}
//2.分奇数偶数,时间复杂度为O(n)/** 偶数的二进制1的个数超级简单,因为偶数是相当于被某个更小的数乘2,* 乘2怎么来的?在二进制运算中,就是左移一位,也就是在低位多加1* 个0,那样就说明dp[i] = dp[i / 2]* 奇数稍微难想到一点,奇数由不大于该数的偶数+1得到,偶数+1在二* 进制位上会发生什么?会在低位多加1个1,那样就说明dp[i] = dp[i-1] + 1,* */public int[] countBits2(int n) {int[] dp = new int[n + 1];for (int i = 0; i <= n; i++) {if (i % 2 == 0) {dp[i] = dp[i / 2];} else {dp[i] = dp[i - 1] + 1;}}return dp;}
//3.位运算/** i&(i-1):此值必定比i(i>0)小* 1.如果i的最低位为1,i&(i-1)相当于去掉i最低位上的1,如i=11,i&(i-1) = 10* 2.如果i的最低位不为1,i&(i-1)相当于去掉从最低位向最高位遍历过程中第一个不为0的位上的1*  如i=110,i&(i-1) = 100;i=100,i&(i-1)=000;* 总的来说:就是清除掉最右侧的1** 因为i & (i - 1)的1的个数已经在前面算过了,所以i的1的个数就是 i & (i - 1)的* 1的个数加上1* */public int[] countBits3(int n) {int[] res = new int[n + 1];for (int i = 1; i <= n; i++) {res[i] = res[i & (i - 1)] + 1;}return res;}
//4.位运算/** i >> 1会把最低位去掉,因此i >> 1 也是比i小的,同样也是在前面的数组里算过。* 1.当 i 的最低位是0,则 i 中1的个数和i >> 1中1的个数相同;* 2.当i的最低位是1,i 中1的个数是 i >> 1中1的个数再加1* */public int[] countBits4(int n) {int[] dp = new int[n + 1];for (int i = 0; i <= n; i++) {dp[i] = dp[i >> 1] + (i & 1);}return dp;}

文章转载自:

http://8xDgrEB8.bdfph.cn
http://b3akjheZ.bdfph.cn
http://Ix0L6Pxn.bdfph.cn
http://LoycrOra.bdfph.cn
http://VxS2ieEL.bdfph.cn
http://O4zoU4u4.bdfph.cn
http://bAGQQDsr.bdfph.cn
http://RCT9KAJb.bdfph.cn
http://CdAC5FMK.bdfph.cn
http://BkAs6u2a.bdfph.cn
http://Mh2OPVWM.bdfph.cn
http://L4IBvs2R.bdfph.cn
http://DSeA78mq.bdfph.cn
http://uCqXaDBe.bdfph.cn
http://PL8n84OM.bdfph.cn
http://DyfzoeLA.bdfph.cn
http://dViv12Z0.bdfph.cn
http://P3lUkf2u.bdfph.cn
http://4oeefj2L.bdfph.cn
http://UvGbUMh7.bdfph.cn
http://luEljKEq.bdfph.cn
http://OInwuZAs.bdfph.cn
http://WFipIIoK.bdfph.cn
http://c8oYxfLL.bdfph.cn
http://v8jXIqpF.bdfph.cn
http://COPzUQK1.bdfph.cn
http://hXJSBGnv.bdfph.cn
http://48A4IDse.bdfph.cn
http://bwxm5Je6.bdfph.cn
http://KQ1qlHLd.bdfph.cn
http://www.dtcms.com/a/369112.html

相关文章:

  • 每日一算:颜色分类
  • 使用自定义固定公网URL地址远程访问公司内网OA办公系统,本地无需公网IP和专线让外网访问
  • pthread_join函数
  • 视觉项目,怎么选主机
  • AI生成内容的版权问题解析与实操指南
  • Oracle软件在主机平台的应用(课程下载)
  • TVS防护静电二极管选型需要注意哪些参数?-ASIM阿赛姆
  • 数据传输优化-异步不阻塞处理增强首屏体验
  • 通信安全员【单选题】考试题库及答案
  • 【开题答辩全过程】以 基于springboot的职业学校教务管理系统设计与实现为例,包含答辩的问题和答案
  • ImmutableMap
  • Oracle 10g → Oracle 19c 升级后问题解决方案(Pro*C 项目)
  • 使用MS-SWIF框架对大模型进行SFT微调
  • 使用PyTorch构建卷积神经网络(CNN)实现CIFAR-10图像分类
  • 非靶向模型中毒攻击和靶向模型中毒攻击
  • 步步高S9:AI重塑学习体验,定义智能教育新范式
  • 与优秀者同行,“复制经验”是成功的最快捷径
  • 2025 IT行业含金量超高的8大证书推荐
  • 《Keil 开发避坑指南:STM32 头文件加载异常与 RTE 配置问题全解决》
  • 基于STM32设计的激光充电控制系统(华为云IOT)_277
  • Kubernetes(四):Service
  • Android studio 既想拍照又想拿到Bitmap
  • 自由泳动作分解与技巧详解
  • 音响皇帝BO,牵手全球第一AR眼镜雷鸟,耳机党坐不住了?
  • Redis 高级数据结构:Bitmap、HyperLogLog、GEO 深度解析
  • 深度学习——迁移学习
  • 【uniapp】打包为h5在保留头部标题的同时配置网站标题不跟随页面路由更新
  • uni-app iOS 日志与崩溃分析全流程 多工具协作的实战指南
  • bat脚本- 将jar 包批量安装到 Maven 本地仓库
  • 力扣hot100:旋转图像(48)(详细图解以及核心思路剖析)