左神算法笔记

总结

一、

1.1 选择排序

  • 每次循环找出最小与之换位
  • 时间 O(N^2) 空间O(1)
    public static void sort(int[] arr){
        //判断数组为空 如果数组没有元素或者只有一个 都当排好序
        if(arr == null||arr.length < 2){
            return;
        }
        //arr.lenth - 1 是因为内循环 每次都是跟下一个比较 否之越界
        for(int i = 0;i < arr.length - 1;i++){
            int index = i;
            //j = i + 1 让最小下标每次与下一个比较
            for(int j = i + 1;j < arr.length;j++){
                //最小下标元素大于后面元素 则下标等于后面元素
                if(arr[index] > arr[j]){
                    index = j;
                }
            }
            //每次循环后找出最小下标与i交换位置
            //如果没找到最小的会与自己交换位置
            swap(arr,index,i);
        }
    }
    private static void swap(int[] arr, int i, int index) {
        int temp = arr[i];
        arr[i] = arr[index];
        arr[index] = temp;
    }

1.2 冒泡排序

  • 相邻两个数比较 大的交换
  • 时间O(N^2)空间O(0)
public static void sort(int[] arr){
        if(arr == null||arr.length < 2){
            return;
        }
    	//每次冒泡出最大数 所以是后往前排序
    	//内循环需要比较下一个 所以arr.lenth - 1 并且最前面不用排序 i > 0
        for(int i = arr.length - 1;i > 0;i--){
            for(int j = 0;j < i;j++){
                //相邻两个数比较 前面大就换位置
                //不会有元素自我比较 所以用异或
                if(arr[j] > arr[j + 1]){
                    swap(arr,j,j + 1);
                }
            }
        }
    }
    private static void swap(int[] arr, int i, int j) {
        arr[j] = arr[j] ^ arr[i];
        arr[i] = arr[j] ^ arr[i];
        arr[j] = arr[j] ^ arr[i];
    }

1.3 插入排序 时间【N^2】最优

  • 每次循环与前面的数比 大则换位置
  • 时间O(N^2)空间O(0)
  • 它的最差排序 才是时间复杂度
public static void sort(int[] arr){
        if(arr == null||arr.length < 2){
            return;
        }
        for(int i = 1;i < arr.length;i++){
            for(int j = i;j > 0&&arr[j] < arr[j - 1];j--){
                swap(arr,j,j - 1);
            }
        }
    }
    private static void swap(int[] arr, int i, int j) {
        arr[j] = arr[j] ^ arr[i];
        arr[i] = arr[j] ^ arr[i];
        arr[j] = arr[j] ^ arr[i];
    }

1.4 二分法查找

1.4.1 二分法查找
  • 每次去中间下标 如果等于返回 否之边界交换
  • 时间O(log2 N)空间O(1)
public static int sel(int[] arr,int num){
        if(arr == null||arr.length == 0){
            return -1;
        }
        int start = 0;
        int end = arr.length - 1;
        while(start <= end){
            int mid = start + ((end - start) >> 1);
            if(arr[mid] == num){
                return mid;
            }else if(arr[mid] > num){
                end = mid - 1;
            }else {
                start = mid + 1;
            }
        }
        return -1;
    }

1.4.2 用二分法查找找出大于等于 num 最左边的下标
  • 在二分查找的基础上 添加一个局部变量存储最左边下标
    public static int max(int[] arr,int num){
        if(arr == null||arr.length == 0){
            return -1;
        }
        int start = 0;
        int end = arr.length - 1;
        int index = -1;
        while(start <= end){
            int mid = start + ((end - start) >> 1);
            if(arr[mid] >= num){
                index = mid;
                end = mid - 1;
            }else {
                start = mid + 1;
            }
        }
        return index;
    }

1.5 异或 两道面试题

1.5.1 找出数组中一个奇数次出现的数
    public static int sel(int[] arr){
        if(arr == null||arr.length == 0){
            return -1;
        }
        int num = 0;
        for(int i = 0;i < arr.length;i++){
            num ^= arr[i];
        }
        return num;
    }
1.5.2 找出数组中两个个奇数次出现的数
    public static void selLian(int[] arr){
        if(arr == null||arr.length == 0){
            return;
        }
        int num_0 = 0;
        for(int i = 0;i < arr.length;i++){
            num_0 ^= arr[i];
        }
        //a^b求最右边二进制为1的数
        int right = num_0 & (~num_0 + 1);
        int num_1 = 0;
        for(int i = 0;i < arr.length;i++){
            //求出与最右边二进制为1的数相等的一批数 在里面异或出a或b其中一个数
            if((right & arr[i]) == 0){
                num_1 ^= arr[i];
            }
        }
        //a^b^(a或者b) 求出另外一个数
        System.out.println((num_0 ^ num_1) + ":" + num_1);
    }

二、

2.1 递归求数组最大值

    public static int max(int[] arr){
        return max(arr,0,arr.length - 1);
    }
    public static int max(int[] arr,int l,int r){
        if(l == r){
            return arr[l];
        }
        //分而治之
        int mid = l + ((r - l) >> 1);
        int right = max(arr,l,mid);
        int left = max(arr,mid + 1,r);
        return Math.max(right,left);
    }

2.2 归并排序

  • 用分而治之递归 外排序
  • 时间O(NlogN)空间O(N)
    public static void sort(int[] arr){        if(arr == null|| arr.length < 2){            return;        }        sort(arr,0,arr.length - 1);    }    private static void sort(int[] arr, int l, int r) {        if(l == r){            return;        }        int mid = l + ((r - l) >> 1);        sort(arr,l,mid);        sort(arr,mid + 1,r);        merge(arr,l,mid,r);    }    private static void merge(int[] arr, int l, int mid, int r) {        int[] help = new int[r - l + 1];        int i = 0;        int p1 = l;        int p2 = mid + 1;        while(p1 <= mid&&p2 <= r){            help[i++] = arr[p1] <= arr[p2]?arr[p1++]: arr[p2++];        }        while(p1 <= mid){            help[i++] = arr[p1++];        }        while(p2 <= r){            help[i++] = arr[p2++];        }        for(int a:help){            arr[l++] = a;        }    }
2.2.1 小和问题
  • 求右边小于左边数的次数乘自身 总和
    public static int sort(int[] arr){        if(arr == null|| arr.length < 2){            return 0;        }        return sort(arr,0,arr.length - 1);    }    private static int sort(int[] arr, int l, int r) {        if(l == r){            return 0;        }        int mid = l + ((r - l) >> 1);        return sort(arr,l,mid) +        sort(arr,mid + 1,r) +        merge(arr,l,mid,r);    }    private static int merge(int[] arr, int l, int mid, int r) {        int[] help = new int[r - l + 1];        int i = 0;        int p1 = l;        int p2 = mid + 1;        int count = 0;        while(p1 <= mid&&p2 <= r){            if(arr[p1] < arr[p2]){                count += (r - p2 + 1) * arr[p1];                help[i++] = arr[p1++];            }else {                help[i++] = arr[p2++];            }        }        while(p1 <= mid){            help[i++] = arr[p1++];        }        while(p2 <= r){            help[i++] = arr[p2++];        }        for(int a:help){            arr[l++] = a;        }        return count;    }
2.2.2 逆序对
  • 右边比左边数小时 打印所有逆序对
    public static void sort(int[] arr){        if(arr == null|| arr.length < 2){            return;        }        sort(arr,0,arr.length - 1);    }    private static void sort(int[] arr, int l, int r) {        if(l == r){            return;        }        int mid = l + ((r - l) >> 1);        sort(arr,l,mid);        sort(arr,mid + 1,r);        merge(arr,l,mid,r);    }    private static void merge(int[] arr, int l, int mid, int r) {        int[] help = new int[r - l + 1];        int i = 0;        int p1 = l;        int p2 = mid + 1;        while(p1 <= mid&&p2 <= r){            if(arr[p1] < arr[p2]){                for(int j = p2;j <= r;j++){                    System.out.println(arr[p1] + ":" +arr[j]);                }                help[i++] = arr[p1++];            }else {                help[i++] = arr[p2++];            }        }        while(p1 <= mid){            help[i++] = arr[p1++];        }        while(p2 <= r){            help[i++] = arr[p2++];        }        for(int a:help){            arr[l++] = a;        }    }

2.3 荷兰国旗

  • 时间O(N)空间O(1)
2.3.1 比num >=的放左边 <的放右边
    public static void sort(int[] arr,int num){        if(arr == null||arr.length < 2){            return;        }        int index = -1;        for(int i = 0;i < arr.length;i++){            if(arr[i] <= num){                swap(arr,++index,i);            }        }    }    private static void swap(int[] arr, int i, int j) {        int temp = arr[i];        arr[i] = arr[j];        arr[j] = temp;    }
2.3.2 比num >的放左边 == 放中间<的放右边
    public static void sort(int[] arr,int num){
        if(arr == null||arr.length < 2){
            return;
        }
        int start = -1;
        int end = arr.length;
        for(int i = 0;i < end;i++){
            if(arr[i] < num){
                swap(arr,++start,i);
            }else if(arr[i] > num){
                swap(arr,--end,i--);
            }
        }
    }

    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

2.4 快速排序

  • 把最后一个数对比前面 分左中右 最后跟右边最后换
  • 随机一个数 放在最后
  • 时间O(N*logN)空间 O(logN)
    public static void sort(int[] arr){
        if(arr == null||arr.length < 2){
            return;
        }
        sort(arr,0,arr.length - 1);
    }

    private static void sort(int[] arr, int l, int r) {
        if(l < r){
            swap(arr,l + (int)(Math.random() * (r - l + 1)),r);
            int[] p = some(arr,l,r);
            sort(arr,l,p[0]);
            sort(arr,p[1],r);
        }
    }

    private static int[] some(int[] arr, int l, int r) {
        int start = l - 1;
        int end = r;
        while(l < end){
            if(arr[l] < arr[r]){
                swap(arr,++start,l++);
            }else if(arr[l] > arr[r]){
                swap(arr,--end,l);
            }else{
                l++;
            }
        }
        swap(arr,end++,r);
        return new int[]{start,end};
    }

    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值