对数器二分法异或

对数器

  • 1.你想要测的方法a
  • 2.实现复杂度不好但是容易实现的方法b
  • 3.实现一个随机样本产生器
  • 4.把方法a和方法b跑相同的随机样本,看看得到的结果是否一样
  • 5.如果有一个随机样本使得比对结果不一致,打印样本进行人工干预,改对方法a和方法b
  • 6.当样本数量很多时比对测试依然正确,可以确定方法a已经正确。
    三个可以参考的对数器:
package duishuqi;
import java.util.List;
import java.util.ArrayList;
import java.util.Random;
public class util2 {
	public static void generateTree(int size, int min, int max){
        //对于当前的树结构,有几个选项
        Random random = new Random();
        List<Object> list = new ArrayList<>();
        int rest;
        if(size == 0)
            rest = 0;
        else{
            rest = 1;
            size--;
            int val = random.nextInt(max - min + 1) + min;
            list.add(val);
        }
        while(rest > 0 && size > 0){
            //对于当前的rest节点,我们有两种选择
            //选择一,在rest > 1 时 可以选择放入两个null
            //选择二,在rest == 1时 必须让节点后继有人
            if(rest > 1){
                rest--;
                size--;
                int rand;
                if(size == 1)
                    rand = random.nextInt(2 + 1);
                else
                    rand = random.nextInt(3 + 1);
                if(rand == 0){
                    //没有后继节点
                    list.add("null");
                    list.add("null");
                    size++;
                }
                else if(rand == 1){
                    //只有左节点
                    int val = random.nextInt(max - min + 1) + min;
                    list.add(val);
                    list.add("null");
                    rest++;
                }
                else if(rand == 2){
                    //只有右节点
                    int val = random.nextInt(max - min + 1) + min;
                    list.add("null");
                    list.add(val);
                    rest++;
                }
                else {
                    //左右都有
                    int left = random.nextInt(max - min + 1) + min;
                    int right = random.nextInt(max - min + 1) + min;
                    list.add(left);
                    list.add(right);
                    rest += 2;
                    size--;
                }
            }
            else {
                rest--;
                size--;
                int rand;
                if(size == 1)
                    rand = random.nextInt(2 - 1 + 1) + 1;
                else
                    rand = random.nextInt(3 - 1 + 1) + 1;
                if(rand == 1){
                    //只有左节点
                    int val = random.nextInt(max - min + 1) + min;
                    list.add(val);
                    list.add("null");
                    rest++;
                }
                else if(rand == 2){
                    //只有右节点
                    int val = random.nextInt(max - min + 1) + min;
                    list.add("null");
                    list.add(val);
                    rest++;
                }
                else {
                    //左右都有
                    int left = random.nextInt(max - min + 1) + min;
                    int right = random.nextInt(max - min + 1) + min;
                    list.add(left);
                    list.add(right);
                    rest += 2;
                    size--;
                }
            }
        }
        System.out.println(list);
    }
}
package duishuqi;
import java.util.HashSet;
import java.util.Random;
public class Util1 {
    public static void generateNoReuseSingleLevelArrSpecial(int arrLen, int minVal, int maxVal, int target){
        //ArrayList<Integer> list = new ArrayList<>();
        HashSet<Integer> set = new HashSet<>();
        HashSet<Integer> filter = new HashSet<>();
        Random random = new Random();
        for(int i = 0; i < arrLen - 2;){
            //list.add(random.nextInt(maxVal - minVal + 1) + minVal);
            int val = random.nextInt(maxVal - minVal + 1) + minVal;
            if(!filter.contains(val)){
                if(set.contains(val))
                    continue;
                set.add(val);
                filter.add(val);
                filter.add(target - val);
                i++;
            }
        }
        //尝试构建最后的匹配值
        int onePiece = random.nextInt(100000000 - (-100000000) + 1) + (-10000000);
        if(set.contains(onePiece)){
            set.add(target - onePiece);
        }
        else {
            set.add(onePiece);
            set.add(target - onePiece);
        }
        System.out.println(set);
        //System.out.println(list);
    }

    public static void generateString(int len, char startC, char endC){
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for(int i = 0; i < len; i++){
            int val = random.nextInt(endC - startC + 1) + startC;
            char c = (char)val;
            sb.append(c);
        }
        System.out.println("\"" + sb.toString() + "\"");
    }

    public static String getString(int len, char startC, char endC){
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for(int i = 0; i < len; i++){
            int val = random.nextInt(endC - startC + 1) + startC;
            char c = (char)val;
            sb.append(c);
        }
        return sb.toString();
    }
}

package duishuqi;
import java.util.List;
import java.util.ArrayList;
import java.util.Random;
public class util2 {
	public static void generateTree(int size, int min, int max){
        //对于当前的树结构,有几个选项
        Random random = new Random();
        List<Object> list = new ArrayList<>();
        int rest;
        if(size == 0)
            rest = 0;
        else{
            rest = 1;
            size--;
            int val = random.nextInt(max - min + 1) + min;
            list.add(val);
        }
        while(rest > 0 && size > 0){
            //对于当前的rest节点,我们有两种选择
            //选择一,在rest > 1 时 可以选择放入两个null
            //选择二,在rest == 1时 必须让节点后继有人
            if(rest > 1){
                rest--;
                size--;
                int rand;
                if(size == 1)
                    rand = random.nextInt(2 + 1);
                else
                    rand = random.nextInt(3 + 1);
                if(rand == 0){
                    //没有后继节点
                    list.add("null");
                    list.add("null");
                    size++;
                }
                else if(rand == 1){
                    //只有左节点
                    int val = random.nextInt(max - min + 1) + min;
                    list.add(val);
                    list.add("null");
                    rest++;
                }
                else if(rand == 2){
                    //只有右节点
                    int val = random.nextInt(max - min + 1) + min;
                    list.add("null");
                    list.add(val);
                    rest++;
                }
                else {
                    //左右都有
                    int left = random.nextInt(max - min + 1) + min;
                    int right = random.nextInt(max - min + 1) + min;
                    list.add(left);
                    list.add(right);
                    rest += 2;
                    size--;
                }
            }
            else {
                rest--;
                size--;
                int rand;
                if(size == 1)
                    rand = random.nextInt(2 - 1 + 1) + 1;
                else
                    rand = random.nextInt(3 - 1 + 1) + 1;
                if(rand == 1){
                    //只有左节点
                    int val = random.nextInt(max - min + 1) + min;
                    list.add(val);
                    list.add("null");
                    rest++;
                }
                else if(rand == 2){
                    //只有右节点
                    int val = random.nextInt(max - min + 1) + min;
                    list.add("null");
                    list.add(val);
                    rest++;
                }
                else {
                    //左右都有
                    int left = random.nextInt(max - min + 1) + min;
                    int right = random.nextInt(max - min + 1) + min;
                    list.add(left);
                    list.add(right);
                    rest += 2;
                    size--;
                }
            }
        }
        System.out.println(list);
    }
}

二分法

经常见到的类型是在一个有序数组上,开展二分搜索但有序真的是所有问题求解时使用二分的必要条件吗?只要能正确构建左右两侧的淘汰逻辑,你就可以二分。

认识二分法
1)在一个有序数组中,找某个数是否存在
2)在一个有序数组中,找>=某个数最左侧的位置
3)在一个有序数组中,找<=某个数最右侧的位置
4)局部最小值问题

有序数组中,找某个数是否存在

package dichotomy;
import java.util.Arrays;
public class BSExist {
	public static boolean Exist(int[] sortedArr,int num){
		if (sortedArr == null || sortedArr.length == 0) {
			return false;
		}
		int L = 0;
		int R = sortedArr.length - 1;
		int mid = 0;
		while(L<R){
			//mid=(L+R)/2
			//mid=L+(R-L)/2
			//N/2-> N>>1
			mid=L+((R-L)>>1);
			if(sortedArr[mid]==num){
				return true;
			}else if(sortedArr[mid]>num){
				R=mid-1;
			}else {
				L=mid+1;
			}
		}
		return sortedArr[L]==num;
	}

	// for test
	public static boolean test(int[] sortedArr, int num) {
		for(int cur : sortedArr) {
			if(cur == num) {
				return true;
			}
		}
		return false;
	}
	
	// for test
	public static int[] generateRandomArray(int maxSize, int maxValue) {
		int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
		for (int i = 0; i < arr.length; i++) {
			arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
		}
		return arr;
	}
	public static void main(String[] args) {
		int testTime = 500000;
		int maxSize = 10;
		int maxValue = 100;
		boolean succeed = true;
		for (int i = 0; i < testTime; i++) {
			int[] arr = generateRandomArray(maxSize, maxValue);
			Arrays.sort(arr);
			int value = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
			if (test(arr, value) != Exist(arr, value)) {
				succeed = false;
				break;
			}
		}
		System.out.println(succeed ? "Nice!" : "Fucking fucked!");
	}
}
//Nice!

上述的位运算可以提高速度,如果遇到N*2+1,就可以写成((N<<1)|1) 往左移一位,最低位是0,或上1,就补成1

有序数组中,找>=某个数最左侧的位置

package dichotomy;
public class BSNearLeft {
	public static int nearestIndex(int[] arr, int value) {
		int L=0;
		int R=arr.length;
		int index=-1;
		while(L<=R){
			int mid=L+((R-L)>>1);
			if (arr[mid]>value) {
				R=mid-1;
				index=mid;
			}else {
				L=mid+1;
			}	
		}
		return index;
	}
	public static void main(String[] args) {
		int [] arr={1,2,3,4,5,5,6,7,8};
		int value=2;
		System.out.println(nearestIndex(arr, value));
	}
}
//2

有序数组中,找<=某个数最右侧的位置

package dichotomy;
public class BSNearRight {
	public static int nearestIndex(int[] arr, int value) {
		int L=0;
		int R=arr.length;
		int index=-1;
		while(L<=R){
			int mid=L+((R-L)>>1);
			if (arr[mid]<=value) {
				L=mid+1;
				index=mid;
			}else {
				R=mid-1;
			}	
		}
		return index;
	}
	public static void main(String[] args) {
		int [] arr={1,2,3,4,5,5,6,7,8};
		int value=2;
		System.out.println(nearestIndex(arr, value));
	}
}
//1

局部最小值问题

下列代码返回的是下标

package dichotomy;
public class BSAwesome {
	public static int getLessIndex(int[] arr) {
		if (arr==null||arr.length==0) {
			return -1;
		}
		if (arr.length==1||arr[0]<arr[1]) {
			return 0;
		}
		if (arr[arr.length-1]<arr[arr.length-2]) {
			return arr.length-1;
		}
		int Left=1;
		int Right=arr.length-2;
		int mid=0;
		while(Left<Right){
			mid=(Left+Right)/2;
			if(arr[mid]>arr[mid-1]){
				Right=mid-1;
			}
			else if (arr[mid]>arr[mid+1]) {
				Left=mid+1;
			}
			else {
				return mid;
			}
		}
		return Left;
	}
	public static void main(String[] args) {
		int [] arr={3,2,5,4,3,5,5,6,7,8};
		System.out.println(getLessIndex(arr));
	}
}
//4

认识异或运算

异或运算:相同为0,不同为1
同或运算:相同以1,不同为0
能长时间记住的概率接近0%
所以,异或运算就记成无进位相加

异或运算的性质
1)0异或NN , N异或N0,^
2)异或运算满足交换律和结合率
上面的两个性质用无进位相加来理解就非常的容易

如何不用额外变量交换两个数

在这里插入图片描述

package dichotomy;
public class swap {
	public static void main(String[] args) {
		//单个数字转换
		int a=16;
		int b=163;
		a=a^b;
		b=a^b;
		a=a^b;
		System.out.println(a);
		System.out.println(b);
		//数组转换
		int[] arr = {3,1,100};
		swap(arr, 0, 2);
		System.out.println(arr[0]+" "+arr[1]+" "+arr[2]);
	}
	public static void swap(int[] arr,int i,int j){
		arr[i]=arr[i]^arr[j];
		arr[j]=arr[i]^arr[j];
		arr[i]=arr[i]^arr[j];
	}
}

上述面试建议不使用,炫技太多,巨无聊,容易给人装逼的感觉

数组中出现一种奇数次的数

一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数

^n+1:取反加1,就是相当于把最后的一个1保留起来,其它都是不一样的

数组中出现两种奇数次的数

一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数

package dichotomy;
public class EvenTimesOddTimes {
	// arr中,只有一种数,出现奇数次
	public static void printOddTimesNum1(int[] arr) {
		int err=0;
		for(int i=0;i<arr.length;i++){
			err^=arr[i];
		}
		System.out.println(err);
	}
	// arr中,有两种数,出现奇数次
	public static void printOddTimesNum2(int[] arr) {
		int err=0;
		for(int i=0;i<arr.length;i++){
			err^=arr[i];
		}
		// a 和 b是两种数
		// eor != 0
		// eor最右侧的1,提取出来
		// eor :     00110010110111000
		// rightOne :00000000000001000
		int rightone=err&(~err+1);//提取最右的1;
		int onlyone=0;
		for(int i=0;i<arr.length;i++){
			if((arr[i]&rightone)==0){//把最右一位是1的找出来,所有异或就可以找出其中一个
				onlyone^=arr[i];
			}
		}
		System.out.println(onlyone+" "+(err^onlyone));
	}
	//二进制上面有多少个1
	public static int bit1counts(int N){
		int count=0;
		while(N!=0){
			int rightone=N&(~N+1);
			count++;
			N^=rightone;
		}
		return count;
	}
	public static void main(String[] args) {
		int[] arr1 = { 3, 3, 2, 3, 1, 1, 1, 3, 1, 1, 1 };
		printOddTimesNum1(arr1);

		int[] arr2 = { 4, 3, 4, 2, 2, 2, 4, 1, 1, 1, 3, 3, 1, 1, 1, 4, 2, 2 };
		printOddTimesNum2(arr2);
		System.out.println(bit1counts(5));
	}
}
/*
2
2 3
2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值