蓝桥杯算法学习(1)
00 学习建议
好程序员是练出来的,编程是手上的活儿,要重视实践
知识盲区需要自己见多识广去补充
参考权威《程序员面试金典》《挑战程序设计竞赛》《程序员代码面试实践》《剑指offer》《编程之美》《算法导论》
关于学习:阅读(听课)–》笔记 --》实践 --》反思 --》提问 (所有步骤需要重复)
01 位运算的奇巧淫技
1 相关基础
在处理整形数值时,可以直接对组成整形数值的各个位进行操作。这意味着可以使用屏蔽技术获得整数中的各个位
&(与)、|(或)、^(异或)、~(非/取反)
<<和>> 运算符将二进制位进行左移或者右移操作
运算符>>>将用0填充高位;运算符>>用符号位填充高位,没有运算符<<<
对于int型,1<<35与1<<3是相同的,而左边的操作数是long型时需对右侧操作数模64
与:都为1结果为1,或:有一个为1结果为1,异或:两者不同时结果为1
2 用处
判断奇偶数
获取二进制位是1还是0(两种解决方案)
交换两个整数变量的值
不用判断语句,求整数的绝对值
异或,可以理解为不进位加法:1+1=0,0+0=0,1+0=1
性质
1、交换律可任意交换运算因子的位置,结果不变
2、结合律(即(ab)c==a(bc))
3、对于任何数x,都有xx=0,x0=x,同自己求异或为0,同0求异或为自己
4、自反性ABB=A^0=A,连续和同一个因子做异或运算,最终结果为自己
3 相关题解
题1:找出唯一成对的数
1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,能否设计一个算法实现?
package org.lanqiao.algo.elementary._01xor;
import org.lanqiao.algo.util.Util;
import java.util.Random;
public class _01唯一成对的数 {
public static void main(String[] args) {
int N = 1001;
int[] arr = new int[N];
for (int i = 0; i < arr.length - 1; i++) {
arr[i] = i + 1;
}
//最后一个数,是随机数
arr[arr.length - 1] = new Random().nextInt(N - 1) + 1;
//随机下标
int index = new Random().nextInt(N);
Util.swap(arr, index, arr.length - 1);
Util.print(arr);
int x1 = 0;
for (int i = 1; i <= N - 1; i++) {
x1 = (x1 ^ i);
}
for (int i = 0; i < N; i++) {
x1 = x1 ^ arr[i];
}
System.out.println(x1);
System.out.println("==========");
int[] helper = new int[N];
for (int i = 0; i < N; i++) {
helper[arr[i]]++;
}
for (int i = 0; i < N; i++) {
if (helper[i] == 2) {
System.out.println(i);
break;
}
}
}
}
题2:找出落单的那个数
一个数组里除了某一个数字之外,其他的数字都出现了两次。请写程序找出这个只出现一次的数字。
题3:二进制中1的个数
请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。
例:9的二进制表示为1001,有2位是1
package org.lanqiao.algo.elementary._01xor;
import java.util.Scanner;
public class _03_1的个数 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
System.out.println(Integer.toString(N, 2));
int count = 0;
//比对每一位
for (int i = 0; i < 32; i++) {
if ((N & (1 << i)) == (1 << i)) {
count++;
}
}
System.out.println(count);
count = 0;
for (int i = 0; i < 32; i++) {
if (((N >>> i) & 1) == 1)
count++;
}
System.out.println(count);
count = 0;
while (N != 0) {
N = ((N - 1) & N);
count++;
}
System.out.println(count);
}
}
题4:是不是2的整数次方
用一条语句判断一个整数是不是2的整数次方。(利用位运算操作判断)
题5:将整数的奇偶位互换
package org.lanqiao.algo.elementary._01xor;
import org.assertj.core.api.Assertions;
public class _05_交换奇偶位 {
public static void main(String[] args) {
int a = 0b01000000_00000000_00000000_00000000;
System.out.println(a);
int b = m(a);
System.out.println(b);
Assertions.assertThat(b).isEqualTo(0b10000000_00000000_00000000_00000000);
}
private static int m(int i) {
int ou = i & 0xaaaaaaaa;//和1010 1010 1010 。。。。做与运算取出偶数位
int ji = i & 0x55555555;//和0101 0101 0101.。。。。做与运算取出奇数位
return (ou >> 1) ^ (ji << 1); // 连起来
}
}
题6:0~1间浮点实数的二进制表示
给定一个介于0和1之间的实数,(如0.625),类型为double,打印它的二进制表示(0.101,因为小数点后的二进制分别表示0.5,0.25.0.125…) 。
如果该数字无法精确地用32位以内的二进制表示,则打印“ERROR”
package org.lanqiao.algo.elementary._01xor;
public class _06_二进制小数 {
public static void main(String[] args) {
double num = 0.625;
StringBuilder sb = new StringBuilder("0.");
while (num > 0) {
//乘2:挪整
double r = num * 2;
//判断整数部分
if (r >= 1) {
sb.append("1");
//消掉整数部分
num = r - 1;
} else {
sb.append("0");
num = r;
}
if (sb.length() > 34) {
System.out.println("ERROR");
return;
}
}
System.out.println(sb.toString());
}
}
题7:出现k次与出现1次
数组中只有一个数出现了1次,其他的数都出现了k次,请输出只出现了1次的数。
note:2个相同的二进制数做不进位加法,结果为0
10个相同的10进制数做不进位加法,结果为0
K个相同的K进制数做不进位加法,结果为0
package org.lanqiao.algo.elementary._01xor;
public class _07_出现K次 {
public static void main(String[] args) {
int[] arr = {2, 2, 2, 9, 7, 7, 7, 3, 3, 3, 6, 6, 6, 0, 0, 0};
int len = arr.length;
char[][] kRadix = new char[len][];
int k = 3;
int maxLen = 0;
//转成k进制字符数组
//对于每个数字
for (int i = 0; i < len; i++) {
//求每个数字的三进制字符串并翻转,然后转为字符数组
kRadix[i] = new StringBuilder(Integer.toString(arr[i], k)).reverse().toString().toCharArray();
if (kRadix[i].length > maxLen)
maxLen = kRadix[i].length;
}
//不进位加法
int[] resArr = new int[maxLen];
for (int i = 0; i < len; i++) {
// 不进位加法
for (int j = 0; j < maxLen; j++) {
if (j >= kRadix[i].length)
resArr[j] += 0;
else
resArr[j] += (kRadix[i][j] - '0');
}
}
int res = 0;
for (int i = 0; i < maxLen; i++) {
res += (resArr[i] % k) * (int) (Math.pow(k, i));// 8%3=2,
}
System.out.println(res);
}
}