跟着左神刷爆算法——简单排序算法

选择排序:

 public static void selectionSort(int[] arr){
        if(arr == null || arr.length < 2){
            return;
        }
        for(int i = 0; i < arr.length; i++){
            int minIndex = i;
            for(int j = i+1; j < arr.length; j++){
                minIndex = arr[i] < arr[j]?j:minIndex;
            }
            swap(arr, i, minIndex);
        }
    }
    public static void swap(int[] arr, int i, int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    } 

冒泡排序:

    public static void bubbleSort(int[] arr){
        if(arr == null || arr.length <2){
            return;
        }
        for(int e = arr.length - 1; e > 0; e--) { // 0~e
            for(int i = 0; i< e; i++) {
                if(arr[i] > arr[i+1]){
                    swap(arr,i,i+1);
                }
            }
        }
    }
    //交换arr的i和j位置上的值
    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];
    }

异或运算:相同为0,不同为1(可以理解为无进位相加)

异或运算不是对内存里的元素值进行运算,而是对元素的内存地址进行运算

异或相关面试题:

一个整型数组中,已知只有一种数出现奇数次,其余所有数出现偶数次

问题1:找到该奇数次的数

int eor = 0  ; eor ^ 数组中所有的数,得到eor该数

    public static void printOddTimesNum1(int[] arr){
        int eor = 0;
        for(int i = 0; i < arr.length; i++){
            eor ^= arr[i];
        }
        System.out.println(eor);
    }

问题2:如果有两种数出现奇数次,其余所有数出现偶数次,找出出现奇数次的两个数

提取一个数最右边的1的方式是  int rightOne =  eor & (~eor +1);

    public static void printOddTimesNum2(int[] arr){
        int eor = 0;
        for(int i = 0; i < arr.length; i++){
            eor ^= arr[i];
        }
        // eor = a^b;
        // eor != 0
        // eor必然有一个位置上是1
        int rightOne = eor ^ (~eor + 1); // 提取出一个数最右边的1
        int onlyOne = 0;
        for(int cur : arr){
            if((cur & rightOne) == 0){
                onlyOne ^= cur;
            }
        }
        System.out.println(onlyOne + " " + (eor^onlyOne));
    }

插入排序:

    public static void insertSort(int[] arr){
        if(arr == null || arr.length < 2){
            return;
        }
        // 0~0上有序
        // 0~i上有序
        for(int i = 1; i < arr.length; i++){ // 0~i上做到有序
            for(int j = i-1; j >= 0 && arr[j] > arr[j-1]; j--){
                swap(arr,j,j+1);
            }
        }
    }
    // i和j是一个位置的话,会出错
    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];
    }

二分法:

问题1:在一个有序数组中,找某个数是否存在

问题2:在有序数组中,找 >=某个数最左侧的位置

问题3:局部最小值问题 : arr中,无序,相邻数一定不相等

    public int binarySearch(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1; // 注意

        while(left <= right) {
            int mid = left + (right - left) / 2;
            if(nums[mid] == target)
                return mid;
            else if (nums[mid] < target)
                left = mid + 1; // 注意
            else if (nums[mid] > target)
                right = mid - 1; // 注意
        }
        return -1;
    }

递归排序:

问题:用递归方法找一个数组中的最大值

    public static int getMax(int[] arr) {
        return process(arr,0,arr.length-1);
    }
    // arr[L...R]范围上求最大值   N
    public static int process(int[] arr,int L, int R) {
        if (L == R) { // arr[L...R]范围伤只有一个数,直接返回
            return arr[L];
        }
        int mid = L + ((R-L) >> 1); // L+(R-L)/2
        int leftMax = process(arr,L,mid);
        int rightMax = process(arr,mid-1,R);
        return Math.max(leftMax,rightMax);
    }

归并排序:额外空间复杂度n级别

    public static void mergeSort(int[] arr) {
        if(arr == null || arr.length < 2){
            return ;
        }
        process(arr,0,arr.length-1);
    }

    public static void process(int[] arr, int L, int R){
        if(L == R){
            return;
        }
        int mid = L +((R-L) >> 1);
        process(arr,L,mid);
        process(arr,(mid+1),R);
        merge(arr,L,mid,R);
    }
    public static void merge(int[] arr, int L, int M, int R){
        int[] help = new int[R-L+1];
        int i = 0;
        int p1 = L;
        int p2 = M+1;
        while(p1 <= M && p2 <= R){
            help[i++] = arr[p1] <= arr[p2]?arr[p1++]:arr[p2++];
        }
        while(p1 <= M){
            help[i++] = arr[p1++];
        }
        while(p2 <= R){
            help[i++] = arr[p2++];
        }
        for(i = 0; i < help.length;i++){
            arr[L + i] = help[i];
        }
    }

问题1:小和问题

在一个数组中,每一个数的左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。例子:[1,3,4,2,5] 1左边比1小的数,没有;3左边比3小的数,1;4左边比4小的数。1,3;2左边比2小的数,1;5左边比5小的数,1、2、3、4;所以小和就是:1+1+3+1+1+3+4+2 = 16

划等为---------》求右边有多少个数比他大,1右边有4个数比他大1*4;3右边有2个比他大3*2;4右边有1个比他大4*1;2右边有1个比他大2*1;小和:4+6+4+2 = 16

相等时先拷贝右组

    public static int smallSum(int[] arr){
        if(arr == null || arr.length < 2){
            return -1;
        }
        return 0;
    }

    // arr[L...R]既要排好序,也要产生小和
    public int process(int[] arr, int L, int R){
        if(L == R) {
            return 0;
        }
        int mid = L + ((R-L) >> 1);
        return process(arr,L,mid)
            + process(arr,mid+1,R)
            +merge(arr,L,mid,R);
    }
    public 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 ret = 0;
        // 相等时先拷贝右组
        while(p1<=mid && p2 <= R){
            ret += arr[p1] < arr[p2]?(R-p2+1)*arr[p1]:0;
            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 (i = 0; i<help.length;i++){
            arr[L+i] = help[i];
        }
        return ret;
    }

问题2:逆序对问题

在一个数组中,左边的数如果比右边的数大,则这两个数构成逆序对,请打印所有逆序对。

Leetcode 剑指 Offer 51. 数组中的逆序对 求逆序对个数

        while (p1 <= mid && p2 <= r) {
            res += nums[p1] > nums[p2] ?(r - p2 + 1): 0 ;
            help[i++] = nums[p1]>nums[p2]?nums[p1++]:nums[p2++];
        }

快速排序:0(N*logN) 额外空间复杂度logN级别

荷兰国旗问题:

问题1:给定一个数组arr,和一个数num,请把小于等于num的数放在数组的左边,大于num的数放在数组的右边。要求额外空间复杂度0(1),时间复杂度0(N)

思路:1,arr[i] <= num,arr [i] 和<=区的下一个数交换,<=区右扩 i++;

           2,arr[i] > num, i++

问题2:

在给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。要求额外空间复杂度0(1),时间复杂度0(N)

思路:1,arr[i] < num, arr[i] 和<区的下一个数交换,<区右扩 i++;

           2,arr[i] == num, i++

          3,arr[i] > num, arr[i] 和>区的下一个数交换,>区左扩 ,i原地不动;

另附代码(Leetcode 75):

    public void sortColors(int[] nums) {
        if(nums == null || nums.length < 2){
            return;
        }
        quickSort(nums,0,nums.length-1);
    }

    // arr[l...r]排好序
    private static void quickSort(int[] arr, int l, int r) {
        if(l < r) {
            // 划分值等于区域的左右边界
            int[] p = partition(arr,l,r);
            quickSort(arr,l,p[0]-1); // <区
            quickSort(arr,p[1]+1,r); // > 区
        }
    }
    // 以区域内的最后一个数划分 > = < 最后与<区域的第一个交换
    private static int[] partition(int[] arr, int l, int r) {
        int less = l-1; // <区右边界
        int more = r; // >区左边界
        while (l < more){ // l表示当前数的位置arr[r] -> 划分值
            if(arr[l] < arr[r]){ // 当前数 < 划分值
                swap(arr,++less,l++);
            } else if(arr[l] > arr[r]){ // 当前数 > 划分值
                swap(arr,--more,l);
            } else {
                l++;
            }
        }
        swap(arr,more,r);
        return new int[]{less+1, more};
    }
    public static void swap(int[] arr, int i, int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值