文章目录
- 7.**位运算**
- 剑指 Offer 15 .[二进制中1的个数 ](https://leetcode-cn.com/problems/er-jin-zhi-zhong-1de-ge-shu-lcof)
- 剑指 Offer 56 - 基础题
- 剑指 Offer 56 - I [数组中数字出现的次数 ](https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof)
- 剑指 Offer 56 - II [数组中数字出现的次数 II ](https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-ii-lcof)
- 剑指 Offer 64 .[求1+2+…+n ](https://leetcode-cn.com/problems/qiu-12n-lcof)
- 剑指 Offer 65 .[不用加减乘除做加法 ](https://leetcode-cn.com/problems/bu-yong-jia-jian-cheng-chu-zuo-jia-fa-lcof)
- 剑指 Offer 66 .[构建乘积数组 ](https://leetcode-cn.com/problems/gou-jian-cheng-ji-shu-zu-lcof)
7.位运算
// jdk中二进制转十进制方式
System.out.println(Integer.parseInt("1001", 2));
// jdk中十进制转二进制方式
System.out.println(Integer.toBinaryString(9));
System.out.println(Integer.toString(9, 2));
剑指 Offer 15 .二进制中1的个数
思考:那就记住吧。只能用>>>。而不能用>>。
public class Offer15 {
public static void main(String[] args) {
int n = 9;
System.out.println(hammingWeight(n));
}
public static int hammingWeight(int n) {
int res = 0;
while (n != 0) {
res += n & 1;
n >>>= 1;
}
return res;
}
}
// 在传递时也把符号一起传递,比如+3、-2在传递再传出时依然是+3、-2,而使用>>>时就会统一变为3、2。带符号于无符号的差别就在此。
public class Offer15_1 {
public static void main(String[] args) {
System.out.println(2 >> 1);//1
System.out.println(2 >>> 1);//1
System.out.println(-2 >> 1);//-1
System.out.println(-2 >>> 1); //2147483647
}
}
// 感觉也不是呀。
剑指 Offer 56 - 基础题
基础内容:
如果除了一个数字以外,其他数字都出现了两次,那么如何找到出现一次的数字?
另一种是,一个数组中一个数字出现了奇数次,其他数字都出现了偶数次,求出这个出现奇数次的数字。
答案很简单:全员进行异或操作即可。考虑异或操作的性质:对于两个操作数的每一位,相同结果为 0,不同结果为 1。那么在计算过程中,成对出现的数字的所有位会两两抵消为 0,最终得到的结果就是那个出现了一次的数字。
在一开始设置的为0。
n&(n-1)会删掉二进制中最后一个1。
public class Offer56_1_3 {
public static void main(String[] args) {
// 找出数组中只出现一次的数。
int[] nums = new int[]{1, 1, 2, 2, 3};
System.out.println(singleNumbers(nums));
}
public static int singleNumbers(int[] nums) {
int res = 0;
for (int num : nums) {
res = res ^ num;
}
return res;
}
}
// 结果为3
剑指 Offer 56 - I 数组中数字出现的次数
一个整型数组 nums
里除一个数字之外,其他数字都出现了两次。请写程序找出这个只出现一次的数字。全员异或操作即可得到结果。
(1)位运算
题解:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/solution/jian-zhi-offer-56-i-shu-zu-zhong-shu-zi-tykom/
// 位运算
import java.util.Arrays;
import java.util.HashMap;
public class Offer56_1_2 {
//一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
public static void main(String[] args) {
int[] nums = new int[]{4, 1, 4, 6};
System.out.println(Arrays.toString(singleNumbers(nums)));
}
public static int[] singleNumbers(int[] nums) {
//xor用来计算nums的异或和
int xor = 0;
// 计算异或和 并存到xor
// e.g. [2,4,2,3,3,6] 异或和:(2^2)^(3^3)^(4^6)=2=010
for (int num : nums) {
xor ^= num;
// System.out.println(Integer.toBinaryString(xor));
}
//设置mask为1,则二进制为0001
// mask是一个二进制数,且其中只有一位是1,其他位全是0,比如000010,
// 表示我们用倒数第二位作为分组标准,倒数第二位是0的数字分到一组,倒数第二位是1的分到另一组
int mask = 1;
// & operator只有1&1时等于1 其余等于0
// 用上面的e.g. 4和6的二进制是不同的 我们从右到左找到第一个不同的位就可以分组 4=0100 6=0110
// 根据e.g. 010 & 001 = 000 = 0则 mask=010
// 010 & 010 != 0 所以mask=010
// 之后就可以用mask来将数组里的两个数分区分开
System.out.println("xor=" + Integer.toBinaryString(xor));
System.out.println("mask=" + Integer.toBinaryString(mask));
while ((xor & mask) == 0) {
mask <<= 1;
System.out.println(Integer.toBinaryString(mask));
}
System.out.println("mask=" + Integer.toBinaryString(mask));
//两个只出现一次的数字
int a = 0, b = 0;
for (int num : nums) {
//根据&是否为0区分将两个数字分区,并分别求异或和
if ((num & mask) == 0) a ^= num;
else {
b ^= num;
}
}
return new int[]{a, b};
}
}
(2)hashmap
// hashmap
import java.util.Arrays;
import java.util.HashMap;
public class Offer56_1 {
//一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
public static void main(String[] args) {
int[] nums = new int[]{4, 1, 4, 6};
System.out.println(Arrays.toString(singleNumbers(nums)));
}
public static int[] singleNumbers(int[] nums) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int count = map.getOrDefault(nums[i], 0) + 1;
map.put(nums[i], count);
}
int[] res = new int[2];
int index = 0;
for (Integer key : map.keySet()) {
if (map.get(key) == 1) {
res[index++] = key;
if (index == 2) {
break;
}
}
}
return res;
}
}
剑指 Offer 56 - II 数组中数字出现的次数 II
(1)位运算
思考:
首先遍历一个数,将其转为二进制形式。数组形式。
比如 n=11=8+2+1=1011B
import java.util.Arrays;
public class Offer56_2_1 {
public static void main(String[] args) {
int n = 11;
int[] count = new int[32];
System.out.println("n=" + n + "二进制位:" + Integer.toBinaryString(n));
for (int i = 0; i < 32; i++) {
count[i] += n & 1;
n >>>= 1;
System.out.println("i=" + i + " count=" + Arrays.toString(count));
}
}
}
n=11二进制位:1011 你看,下面的结果是逆序的。这个是和自己一开始考虑的不一样哦。
i=0 count=[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
i=1 count=[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
i=2 count=[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
i=3 count=[1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
i=4 count=[1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
i=5 count=[1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
public class Offer56_2 {
public static void main(String[] args) {
int[] nums = new int[]{9, 1, 7, 9, 7, 9, 7};
System.out.println(singleNumber(nums));
}
public static int singleNumber(int[] nums) {
int[] count = new int[32];
// System.out.println(Arrays.toString(count));
for (int i = 0; i < nums.length; i++) {
for (int j = 0; j < 32; j++) {
count[j] += nums[i] & 1;
nums[i] >>>= 1;
// System.out.println(Arrays.toString(count));
}
}
// System.out.println(Arrays.toString(count));
for (int i = 0; i < 32; i++) {
count[i] = count[i] % 3;
}
// System.out.println(Arrays.toString(count));
int res = 0;//[0,0,0,1]=0001
for (int i = count.length - 1; i >= 0; i--) {
res <<= 1;
res |= count[i];
}
return res;
}
}
(2)简单做法 HashMap
import java.util.HashMap;
public class Offer56_2 {
public static void main(String[] args) {
int[] nums = new int[]{9, 1, 7, 9, 7, 9, 7};
System.out.println(singleNumber(nums));
}
// 在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
public static int singleNumber(int[] nums) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int count = map.getOrDefault(nums[i], 0) + 1;
map.put(nums[i], count);
}
// 遍历 map 的 values
int res = -1;
for (Integer key : map.keySet()) {
if (map.get(key) == 1) {
res = key;
break;
}
}
return res;
}
}
剑指 Offer 64 .求1+2+…+n
思考:
// 但是这里使用了if,不满足题意。要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
public class Offer64 {
public static void main(String[] args) {
int n = 9;
System.out.println(sumNums(n));
}
public static int sumNums(int n) {
//终止条件
if(n==1){
return 1;
}
n+=sumNums(n-1);
return n;
}
}
// 使用 &&
public class Offer64_1 {
public static void main(String[] args) {
int n = 9;
System.out.println(sumNums(n));
}
static int res = 0;
static boolean flag;
public static int sumNums(int n) {
System.out.println("flag=" + (n > 1 && sumNums(n - 1) > 0) + " n=" + n);
flag = n > 1 && sumNums(n - 1) > 0;
res += n;
return res;
}
}
剑指 Offer 65 .不用加减乘除做加法
思考:虽然系统分类是简单。但并不容易吧。
public class Offer65 {
public static void main(String[] args) {
int a = 20;
int b = 17;
System.out.println(add(a, b));
}
public static int add(int a, int b) {
if (b == 0) {
return a;
}
// 转换成非进位和 + 进位
return add(a ^ b, (a & b) << 1);
}
}
剑指 Offer 66 .构建乘积数组
思考:
自己手写了一张笔记,还需要上传。
(1)在不使用除法的情况下
import java.util.Arrays;
public class Offer66_1 {
public static void main(String[] args) {
int[] nums = new int[]{1, 2, 3, 4, 5};
System.out.println(Arrays.toString(constructArr(nums)));
}
public static int[] constructArr(int[] a) {
//输入判断
if (a == null || a.length == 0) {
return new int[0];
}
int len = a.length;
int[] res = new int[len];
int[] left = new int[len];
int[] right = new int[len];
left[0] = right[len - 1] = 1;
for (int i = 1; i < len; i++) {
left[i] = left[i - 1] * a[i - 1];
}
for (int i = len - 2; i >= 0; i--) {
right[i] = right[i + 1] * a[i + 1];
}
for (int i = 0; i < len; i++) {
res[i] = left[i] * right[i];
}
return res;
}
}
(2)在使用除法的情况下
import java.util.Arrays;
public class Offer66 {
public static void main(String[] args) {
int[] nums = new int[]{1, 2, 3, 4, 5};
System.out.println(Arrays.toString(constructArr(nums)));
}
public static int[] constructArr(int[] a) {
int[] res = new int[a.length];
int value = 1;
for (int i = 0; i < a.length; i++) {
value *= a[i];
}
for (int i = 0; i < res.length; i++) {
res[i] = value / a[i];
}
return res;
}
}