算法基础入门——选择、冒泡、插入、二分、异或运算

public class code01 {
    /**
     * 选择排序
     * 遍历一轮选择最小的,每轮确定一个数的位置
     * 时间复杂度O(N^2),额外空间复杂度O(1)
     */
    public static void selectionSort(int[] arr) {
        if (arr == null || arr.length < 2){
            return;
        }
        for (int i = 0; i < arr.length - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j <arr.length; j++) {
                minIndex = arr[j] < arr[minIndex] ? j : minIndex;
            }
            // 如果minIndex等于i,就是其本身就不用交换,如果使用异或交换就会变为0
            if (minIndex != i) {
                swap(arr, i, minIndex);
            }
        }
    }

    /**
     * 冒泡排序
     * 遍历一轮,确定一个数的位置,相邻比较
     * 时间复杂度O(N^2),额外空间复杂度O(1)
     */
    public static void bubbleSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        for (int k = arr.length - 1; k > 0; k--) {
            for (int i = 0; i < k; i++) {
                if (arr[i] > arr[i+1]) {
                    swap(arr, i, i + 1);
                }
            }
        }
    }

    /**
     * 插入排序
     * 左边有序,右边无序
     * 时间复杂度O(N^2),额外空间复杂度O(1)
     */
    public static void insertionSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        for (int i = 1; i < arr.length; i++) {
            for (int j = i - 1; j >= 0 && arr[j] > arr[j+1]; j--) {
                swap(arr, j, j+1);
            }
        }
    }

    /**
     * 数组交换
     */
    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];
    }

    /**
     * 在有序数组中,使用二分法查找某数是否存在
     * @return
     */
    public static boolean BSExist(int[] arr, int num) {
        if (arr == null && arr.length == 0) {
            return false;
        }
        int left = 0;
        int right = arr.length -1;
        int mid = 0;
        while (left < right) {
            // mid = left + ((right - left) >> 1);
            mid = (left + right) / 2;
            if (arr[mid] == num) {
                return true;
            } else if (arr[mid] > num) {
                right = mid -1;
            } else {
                left = mid + 1;
            }
        }
        // return sortedArr[left] == num;
        return false;
    }

    /**
     * 在有序数组中,使用二分查找>=某个数的最左侧位置
     * @return
     */
    public static int BSNearLeft(int[] arr, int num) {
        if (arr == null && arr.length == 0) {
            return 0;
        }
        int index = -1;
        int left = 0;
        int right = arr.length -1;
        int mid;
        while (left < right) {
            mid = left + ((right - left) >> 1);
            if (arr[mid] >= num) {
                index = mid;
                right = mid -1;
            } else {
                left = mid + 1;
            }
        }
        return index;
    }

    /**
     * 一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到这一个数?
     * 运用异或运算,出现偶数次的数异或后等于0,最后异或的结果就是出现奇数次的数
     * 0^N == N
     * N^N == 0
     * @param arr
     */
    public static void printOddTimesNum1(int[] arr) {
        int a = 0;
        for (int b :arr) {
            a = a ^ b;
        }
        System.out.println(a);
    }

    /**
     * 一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到这两个数
     * @param arr
     */
    public static void printOddTimesNum2(int[] arr) {
        int a = 0;
        int one = 0;
        // 获取到2个数异或的值
        for (int b :arr) {
            a = a ^ b;
        }
        // 获取2个数异或的值的最右边的1,与上(取反+1)
        int rightOne = a & (~a + 1);
        // 将数组分为2类,独自异或,可以得到一个出现奇数次的数
        for (int b :arr) {
            if ((b & rightOne) != 0) {
                one ^= b;
            }
        }
        System.out.println(one +" "+ (one ^ a));
    }

    /**
     * 用递归方法找一个数组中的最大值
     * @param arr
     * @param left
     * @param right
     * @return
     */
    public static int getMax(int[] arr, int left, int right) {
        if (left == right) {
            return arr[left];
        }
        int mid = left + ((right - left) >> 1);
        int leftMax = getMax(arr, left, mid);
        int rightMax = getMax(arr, mid + 1, right);
        return Math.max(leftMax,rightMax);
    }

    /**
     * 局部最小值问题
     * 局部最小值的概念。arr长度为1时,arr[0]是局部最小。arr的长度为N(N > 1)时,如果arr[0]<arr[1],那么arr[0]是局部最小;
     * 如果arr[N-1]<arr[N-2],那么arr[N-1]是局部最小;如果0<i<N-1,既有arr[i]<arr[i-1],又有arr[i]<arr[i+1],那么arr[i]是局部最小。
     * 给定无序数组arr,已知arr中任意两个相邻的数都不相等。写一个函数,只需返回arr中任意一个局部最小出现的位置即可。
     * @param arr
     * @return
     */
    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 - left) >> 1);
            // 注意这里判断条件
            // 上升趋势,抛弃右边,保持先降后升的趋势
            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[] arr1 = {212,1561,451,15415,451,12,4511,45315,5616,4565};
        // 选择排序
        selectionSort(arr1);
        for (int i = 0; i < arr1.length; i++) {
            System.out.println(arr1[i]);
        }

        int[] arr2 = {212,1561,451,15415,451,12,4511,45315,5616,4565};
        // 冒泡排序
        bubbleSort(arr2);
        for (int i = 0; i < arr2.length; i++) {
            System.out.println(arr2[i]);
        }

        int[] arr3 = {212,1561,451,15415,451,12,4511,45315,5616,4565};
        // 插入排序
        insertionSort(arr3);
        for (int i = 0; i < arr2.length; i++) {
            System.out.println(arr3[i]);
        }

        // 二分查找某数
        boolean b = BSExist(arr3, 451);
        System.out.println(b);

        // 二分查找>=某数最左侧位置
        int i = BSNearLeft(arr3, 452);
        System.out.println(i);

        // 一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到这一个数
        int[] arr4 = { 3, 3, 2, 3, 1, 1, 1, 3, 1, 1, 1 };
        printOddTimesNum1(arr4);

        // 一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到这两个数
        int[] arr5 = { 4, 3, 4, 2, 2, 2, 4, 1, 1, 1, 3, 3, 1, 1, 1, 4, 2, 2 };
        printOddTimesNum2(arr5);

        // 递归获取数组最大值
        int max = getMax(arr3, 0, arr3.length - 1);
        System.out.println(max);

        // 局部最小值问题
        int[] arr6 = {6, 5, 7, 3, 4, 6, 7, 8};
        for (int j = 0; j != arr6.length; j++) {
            System.out.print(arr6[j] + " ");
        }
        System.out.println();
        int index = getLessIndex(arr6);
        System.out.println("index: " + index + ", value: " + arr6[index]);
    }
}

 

posted @ 2022-03-05 20:36  北漂的尘埃  阅读(55)  评论(0编辑  收藏  举报