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

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://www.xdnf.cn/news/20369.html

相关文章:

  • 安卓学习 之 EditText 控件
  • C/C++中的可变参数 (Variadic Arguments)函数机制
  • Linux学习-硬件(串口通信)
  • 【Android】SQLite使用——增删查改
  • 有哪些AI产品可以真正提高办公和学习效率?
  • 【LeetCode】2749. 得到整数零需要执行的最少操作数
  • 关于无法导入父路径的问题
  • MySQL源码部署(rhel7)
  • SQL面试题及详细答案150道(61-80) --- 多表连接查询篇
  • java面试中经常会问到的集合问题有哪些(基础版)
  • GigaDevice(兆易创新)GD25Q64CSJGR 64Mbit FLASH
  • c#动态树形表达式详解
  • uni-app 和 uni-app x 的区别
  • 【Cell Systems】SpotGF空间转录组去噪算法文献分享
  • 图像去雾:从暗通道先验到可学习融合——一份可跑的 PyTorch 教程
  • <video> 标签基础用法
  • MySQL-安装MySQL
  • UE4 Mac构建编译报错 no template named “is_void_v” in namespace “std”
  • 无需bootloader,BootROM -> Linux Kernel 启动模式
  • Java全栈开发工程师面试实录:从基础到实战的深度探讨
  • PyTorch图像数据转换为张量(Tensor)并进行归一化的标准操作
  • 管理中心理学问:动机与管理的关联
  • 什么是CRM?定义、作用、功能、选型|CRM百科
  • 使用若依加Trae快速搭建一对儿多对多CRUD
  • 移植Qt4.8.7到ARM40-A5
  • PiscCode基于 Mediapipe 实现轨迹跟踪
  • TOGAF之架构标准规范-迁移计划
  • nginx 反向代理使用变量的坑
  • 亚马逊商品转化率怎么提高?从传统运营到智能广告的系统化突破
  • Nginx 配置片段主要用于实现​​正向代理​​,可以用来转发 HTTP 和 HTTPS 请求