一、常用技巧
1. 与运算& / 异或运算^ / 移位运算>> / 按位取反运算 ~
- 与运算 & 规则 :都为1时才为1
可以实现二进制的进位运算
System.out.println( 7 & 9);
/*
* 7二进制 0111
* 9二进制 1001
* -----------
* 0001 ==1
* */
-
异或运算
可以实现二进制的加法结果,不包含进位
Java中的位运算符中有一个叫做异或的运算符,符号为(^),其主要是对两个操作数进行位的异或运算,相同取0,相反取1。即两操作数相同时,互相抵消
- 常用小技巧
0和任何数做异或运算都等于该数
x与1做异或运算,若x为奇数,等价于x-1;x为偶数,等价于x+1 -
位移运算
箭头指向哪 就是X移位

-
~ 按位进行取反运算(NOT)

2. 如何计算一个十进制数变成二进制后有多少个1 **
public int countOne(int val){
int count = 0;
while(val!=0){
val = (val-1) & val;
count++;
}
return count;
}
3. 二进制与十进制的转化 (调用函数)
- 二进制变成十进制
Long.parseLong(binaryStr, 2)
Integer.parseInt(s, 2)
- 十进制变成二进制
String num = Long.toBinaryString(Long.parseLong(line));//十进制变成二进制
String temp = Integer.toString(val, 2); //十进制变二进制
4. 判断奇数偶数
val&1==1 //奇数
val&1==0 //偶数
5. 十进制与二进制转换(不调用函数)
class Solution {
public int singleNumber(int[] nums) {
//32位数组
int[] bitsmap = new int[32];
//每个数变为二进制,范围为32位
for(int num:nums){
for(int i=0;i<32;i++){
if( ( (num >>i ) & 1 )== 1){
bitsmap[i]++;
}
}
}
//对每个值对3取模,要么是0 要么是1
int res =0;
for(int i=0;i<32;i++){
if(bitsmap[i]%3 == 1){
res += (1<<i);//二进制变十进制
}
}
return res;
}
}
二、典型题目
T1356. 二进制下1的数目排序 (计算二进制1的数目)

class Solution {
public int[] sortByBits(int[] arr) {
Arrays.sort(arr);
int len = arr.length;
//计算每个数1的个数
int[] count = new int[len];
for(int i=0;i<len;i++){
count[i] = countOne(arr[i]);
}
//数字:1的个数
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
for(int i=0;i<len;i++){
map.put(arr[i],count[i]);
}
//冒泡排序
for(int i=0;i<len-1;i++){
for(int j=0;j<len-1-i;j++){
if( map.get(arr[j]) > map.get(arr[j+1]) ){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
return arr;
}
public int countOne(int val){
int count = 0;
while(val!=0){
val = (val-1) & val;
count++;
}
return count;
}
}
T393. UTF-8 编码验证
华为od:HJ33 整数与IP地址间的转换 (十进制,二进制的转换)

import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNext()) {
String line = in.nextLine();
//输入IP地址
if (line.contains(".")) {
String[] parts = line.split("\\.");//此处需要转义符号\\
StringBuilder sb = new StringBuilder();
for (int i = 0; i < parts.length; i++) {
int val = Integer.parseInt(parts[i]);
String temp = Integer.toString(val, 2); //十进制变二进制
while (temp.length() < 8) {
temp = "0" + temp;
}
sb.append(temp);
}
String binaryStr = sb.toString();
System.out.println(Long.parseLong(binaryStr, 2)); //二进制变成十进制
} else { //输入十进制的IP地址
String num = Long.toBinaryString(Long.parseLong(
line));//十进制变成二进制
while (num.length() < 32) {
num = "0" + num;
}
String[] res = new String[4];//把32位的二进制划分成四个
for (int i = 0; i < 4; i++) {
String s = num.substring(i * 8, 8 * i + 8);
s = Integer.toString(Integer.parseInt(s, 2));
res[i] = s;
}
System.out.println(String.join(".", res));
}
}
}
}
剑指 Offer II 001. 整数除法 (实现一个除法,难度较大)
T136. 只出现一次的数字 (异或运算)

class Solution {
public int singleNumber(int[] nums) {
//异或运算:相同的数进行异或运算,结果为0
//异或运算满足交换律,a^b^a=a^a^b=b,因此ans相当于nums[0]^nums[1]^nums[2]^nums[3]^nums[4].....
// 根据交换律把相等的合并到一块儿进行异或(结果为0)
if(nums.length == 1){
return nums[0];
}
int res = nums[0];
for(int i =1;i<nums.length;i++){
res = res ^ nums[i];
}
return res;
}
}
剑指 Offer II 004. 只出现一次的数字 (上一题的深入)

与上一题相比 次数由2变成3不能简单利用 异或运算^ 了
- 32位二进制数组
class Solution {
public int singleNumber(int[] nums) {
//32位数组
int[] bitsmap = new int[32];
//每个数变为二进制,范围为32位
for(int num:nums){
for(int i=0;i<32;i++){
if( ( (num >>i ) & 1 )== 1){
bitsmap[i]++;
}
}
}
//对每个值对3取模,要么是0 要么是1
int res =0;
for(int i=0;i<32;i++){
if(bitsmap[i]%3 == 1){
res += (1<<i);
}
}
return res;
}
}
剑指 Offer II 002. 二进制加法 (模拟/利用位运算实现二进制加法)

- 竖式模拟
class Solution {
public String addBinary(String a, String b) {
int lenA = a.length();
int lenB = b.length();
StringBuilder sb = new StringBuilder();
int n = Math.max(lenA,lenB);//求最大长度
int add = 0;//和
for(int i=0;i<n;i++){
//如果没有到达最大长度 就取值;否则取0
//和可能是0,1,2,3
add += i<lenA ? (a.charAt(lenA-i-1)-'0') : 0;
add += i<lenB ? (b.charAt(lenB-i-1)-'0') : 0;
sb.append( (char) (add%2 + '0'));
add /= 2;//当和为2,3需要进位1
}
if(add>0){
sb.append('1');
}
return sb.reverse().toString();//反转 转字符串
}
}
- 位运算
class Solution {
//利用与&和异或^运算
public String addBinary(String a, String b) {
int lenA = a.length();
int lenB = b.length();
StringBuilder sb = new StringBuilder();
int n = Math.max(lenA,lenB);//求最大长度
int temp=0,carry=0;
for(int i=0;i<n;i++){
int x = i<lenA ? (a.charAt(lenA-i-1)-'0') : 0;
int y = i<lenB ? (b.charAt(lenB-i-1)-'0') : 0;
temp = x ^ y ^ carry;//没有进位的结果
if(x == 0 || y==0){
carry = (x^y) & carry;
}else{
carry = 1;//两个数为1
}
sb.append( (char) (temp + '0'));
}
if(carry>0){
sb.append('1');
}
return sb.reverse().toString();//反转 转字符串
}
}
文章介绍了位运算的基本技巧,包括与运算、异或运算、移位运算和按位取反,提供了计算二进制1数量的方法,并展示了这些运算在解决编程问题如二进制下1的数目排序、UTF-8编码验证、整数与IP地址转换、整数除法和寻找数组中只出现一次的数字等问题中的应用。
983

被折叠的 条评论
为什么被折叠?



