Day001:
1、主要讲解位运算之异或(^)和二分搜索策略
2、二分主要的模板就是两个指针left 和 right ,用这俩玩意儿来求mid ,(公式:mid = left + ((right - left) >> 1))。你可以把他想象成一个线段的运算,是不是就恍然大悟啦!
心得:
1、异或运算简而言之就是两个数做减法运算,比如9^1 = 8; 8^4 = 4; 原因很简单就是减数的二进制位跟被减数的二进制位相等的地方就抹掉,换成0了,所以起到了减法的运算效果,懂得这个,那么下面的两个代码就可以很轻松的理解了。
例题:
1、一个无序数组中,只有一个数出现了一次,其余的数全部是成对出现的,现在请你找出这个只出现了一次的数。
public class Main01 {
// 结果输出:4
public static void main(String[] args) {
int[] arr = new int[] {1,1,5,6,7,3,4,3,7,6,5};
int ero = arr[0];
for (int i = 1; i < arr.length; i++) {
ero ^= arr[i];
}
System.out.println(ero);
}
}
2、一个无序数组中,只有两个数出现了一次,其余的数全部是成对出现的,现在请你找出这个只出现了一次的这两个数。
public class Main02 {
// 结果输出:9 1
public static void main(String[] args) {
int[] arr = new int[] {1,4,6,7,5,7,6,9,4,5};
int ero = arr[0];
// 找出这两个数做异或操作的结果,通过这个操作来找到这两个数不一样的二进制位
for (int i = 1; i < arr.length; i++) {
ero ^= arr[i];
}
// 提取出最右边的的1
// ~:java中的二进制取反操作
int rightEro = ero & (~ero + 1);
// 存放结果
int onlyOne = 0;
// 所有的数跟rightEro做异或操作
for (int i = 0; i < arr.length; i++) {
// 如果rightEro这一位上的数是rightEro或0,则放到一组
if ((rightEro & arr[i]) == rightEro) {
onlyOne ^= arr[i];
}
}
// 现在onlyOne就是其中一个结果唯一的数,那么另一个数就是ero和onlyOne的异或运算
System.out.println(onlyOne + " " + (onlyOne ^ ero));
}
}
3、利用二分法查找一个数在有序数组中的所在位置
public class Main03 {
// 结果输出:11
public static void main(String[] args) {
int[] arr = new int[] {1,2,3,4,5,6,7,8,9,10,16,24};
// 利用二分的思想
/*
ansNum:我要找的这个数
mid:中间下标,也就是结果的下标
right:右边数的下标
*/
int ansNum = arr[11];
int mid = arr.length>>1;
int right = arr.length;
for (int i = 0; i < arr.length; i++) {
if (arr[mid] == ansNum) {
// 找到了这个数的下标
System.out.println(mid);
break;
}
else if (arr[mid] < ansNum) {
// 往右边二分
mid += ((right -mid)>>1);
}
else if (arr[mid] > ansNum) {
// 往左边二分
mid >>= 1;
}
}
}
}
4、在一个有序数组中找到 >= 某个数最左侧的位置
public class Main04 {
// 结果输出:5
public static void main(String[] args) {
// 二分思想
int[] arr = new int[] {1,1,2,2,2,3,3,3,4,4,4,4,5,5,5,5,5,6,6,7,7,7,8,8,8,9,9,10};
// 要查找的元素
int ansNum = 3;
int left = 0;
int right = arr.length-1;
int leftMinIndex = 0;
while (left <= right) {
int mid = left + ((right-left)>>1);
if (arr[mid] >= ansNum) {
// 左边二分, 修改right的值
leftMinIndex = mid;
right = mid-1;
}
else if (arr[mid] < ansNum) {
// 右边二分,修改left的值
left = mid + 1;
}
}
System.out.println(leftMinIndex);
}
}
每日一句:
无意中看到我朋友的一句话:“你也不想看着别人实现你的梦想是吧”,所以,加油吧,少年郎!