【算法題】二分查找及升級版

一、二分查找法(無重複數)
1、算法思想
針對一個有序數據集合a(無重複數),查找元素x的下標位置。我們可以將n個元素分成大致相等的兩部分,取a[n/2]與x做比較,如果x=a[n/2],則找到了x,算法中止;如果x<a[n/2],則只要在數組a的左半部分繼續搜索x;如果x>a[n/2],則只要在數組a的右半部搜索x。
2、時間複雜度:O(logn)
3、代碼實現(Java)
(1)通過while循環實現:

	public static void main(String[] args) {
        int[] a = {1, 3, 5, 6, 10, 12};
        System.out.println(binarySearch(a, 10));
    }

    public static int binarySearch(int[] a, int x) {
        if (a == null || a.length == 0) {
            return -1;
        }
        int low = 0;
        int high = a.length - 1;
        int mid;
        while (low <= high) {
            mid = low + (high - low) / 2;
            if (x == a[mid]) {
                return mid;
            }
            else if (x < a[mid]) {
                high = mid - 1;
            }
            else {
                low = mid + 1;
            }
        }
        return -1;
    }

(2)通過for循環實現

	public static void main(String[] args) {
        int[] a = {1, 3, 5, 6, 10, 12};
        System.out.println(binarySearch(a, 10));
    }

    public static int binarySearch(int[] a, int x) {
        if (a == null || a.length == 0) {
            return -1;
        }
        int low = 0;
        int high = a.length - 1;
        int mid = low + (high - low) / 2;
        for (int i = mid; low <= high; mid = low + (high - low) / 2) {
            if (x == a[mid]) {
                return mid;
            }
            else if (x < a[mid]) {
                high = mid - 1;
            }
            else {
                low = mid + 1;
            }
        }
        return -1;
    }

二、二分查找(有重複數)
如果一個n個數的有重複數的有序數據集合a,如果查找的x有連續多個,返回一個列表,保存x的起始位置;如果查找的x只有一個,則直接返回該數下標;如果沒找到,則返回列表-1。

	public static void main(String[] args) {
        int[] a = {1, 3, 3, 3, 5, 6, 10, 12, 12};
        System.out.println(binarySearch(a, 12));
    }
    
    // 有序數組,有重複數,返回查找數的起始位置
    public static ArrayList<Integer> binarySearch(int[] a, int x) {
        ArrayList<Integer> result = new ArrayList<>();
        if (a == null || a.length == 0) {
            result.add(-1);
            return result;
        }
        int low = 0;
        int high = a.length - 1;
        int mid = low + (high - low) / 2;
        int start, end;
        boolean isExist = false; // 記錄是否找到x
        while(low <= high) {
            mid = low + (high - low) / 2;
            if (x < a[mid]) {
                high = mid - 1;
            }
            else if (x > a[mid]) {
                low = mid + 1;
            }
            else {
                isExist = true; // 查找到至少一個x
                break;
            }
        }
        // 如果沒有找到x,則直接返回-1
        if (!isExist) {
            result.add(-1);
            return result;
        }
        // 如果已經找到了元素,則先從左邊繼續找
        start = mid;
        end = mid;
        // 如果起始位置大於等於0且a[start] == x,則繼續
        while(start >= 0 && a[start] == x) {
            start--;
        }
        start = start + 1;
        // 如果終點位置小於等於數組長度且a[end] == x,則繼續
        while(end <= high && a[end] == x) {
            end++;
        }
        end = end - 1;
        // 如果起始位置相等,說明只找到一個數
        if (start == end) {
            result.add(start);
        }
        else {
            result.add(start);
            result.add(end);
        }
        return result;
    }

三、二分查找第一個等於給定的數的下標

	public static void main(String[] args) {
        int[] a = {1, 3, 3, 3, 3, 6, 10, 12, 12};
        System.out.println(binarySearch(a, 3));
    }

    public static int binarySearch(int[] a, int x) {
        if (a == null || a.length == 0) {
            return -1;
        }
        int low = 0;
        int high = a.length - 1;
        int mid;
        while(low <= high) {
        	mid = low + (high - low) / 2;
            if (x < a[mid]) {
                high = mid - 1;
            }
            else if(x > a[mid]){
                low = mid + 1;
            }
            // 否則,x == a[mid],至少找到一個值等於x
            else {
                // 如果中間位置等於最左邊,或者a[mid - 1] != x,說明再往左沒有找到等於x的值,則此時第一個等於x的值位置就是mid
                if (mid == low || a[mid - 1] != x) {
                    return mid;
                }
                high = mid - 1;
            }
        }
        return -1;
    }

四、二分查找最後一個等於給定的數的下標

	public static void main(String[] args) {
        int[] a = {1, 3, 3, 3, 3, 6, 10, 12, 12};
        System.out.println(binarySearch(a, 3));
    }

    public static int binarySearch(int[] a, int x) {
        if (a == null || a.length == 0) {
            return -1;
        }
        int low = 0;
        int high = a.length - 1;
        int mid;
        while (low <= high) {
            mid = low + (high - low) / 2;
            if (x < a[mid]) {
                high = mid - 1;
            }
            else if(x > a[mid]){
                low = mid + 1;
            }
            else {
                if (mid == high || a[mid + 1] != x) {
                    return mid;
                }
                low = mid + 1;
            }
        }
        return -1;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章