前端面试算法,经典题目练习,JS版,二分(持续更新)

123 阅读1分钟

二分搜索

在排序数组中查找元素的第一个和最后一个位置

先二分找到其中一个,再循环左右相等元素并取最左最右索引

var searchRange = function (nums, target) {
    if(nums.length < 2 && nums[0]=== target) return [0,0]
    if(nums.length < 2 && nums[0]!== target) return [-1,-1]
    let left = 0, right = nums.length - 1, mid, ans = [-1, -1]
    while (left <= right) {
        mid = Math.floor((left + right) / 2)
        if (target < nums[mid]) {
            right = mid - 1
        } else if (target > nums[mid]) {
            left = mid + 1
        } else {
            ans = [mid, mid]
            let temp = mid
            while (nums[temp-1] === target) {
                temp -= 1
            }
            
            while (nums[mid+1] === target) {
                mid += 1
            }
            ans = [temp, mid]
            return ans
        }
    }
    return ans
};

搜索旋转排序数组

二分思想,每次if找顺序没乱的那边先进行位移

var search = function (nums, target) {
    let n = nums.length
    if (n === 0) return -1
    if (n === 1) return target === nums[0] ? 0 : -1
    let left = 0, right = n - 1, mid;
    while (left <= right) {
        mid = Math.floor((left + right) / 2)
        if (target === nums[mid]) {
            return mid
        } else {
            if (nums[0] <= nums[mid]) {
                if (nums[0] <= target && target < nums[mid]) {
                    right = mid - 1
                } else {
                    left = mid + 1
                }
            } else {
                if (target <= nums[n - 1] && target > nums[mid]) {
                    left = mid + 1
                } else {
                    right = mid - 1
                }
            }
        }
    }
    return -1
};

搜索二维矩阵

var searchMatrix = function (matrix, target) {
    let m = matrix.length, n = matrix[0].length;
    let left = 0, right = n - 1, row = 0
    while (!(target >= matrix[row][left] && target <= matrix[row][right])){
        row++
        if(row > m-1) return false
    }
    if(n === 1) return matrix[row][0] === target
    let mid
    while(left <= right){
        mid = Math.floor((left+right)/2)
        if(target === matrix[row][mid]){
            return true
        }else if(target < matrix[row][mid]){
            right = mid - 1
        }else{
            left = mid + 1
        }
    }
    return false
};

寻找旋转排序数组中的最小值

var findMin = function(nums) {
    let left = 0, right = nums.length, mid, ans = nums[0]
    while(left < right){
        mid = Math.floor((left+right)/2)
        if(nums[mid]<ans){
            ans = nums[mid]
        }
        if(nums[0] < nums[mid]){
            left = mid + 1
        }else{
            right = mid
        }
    }
    return ans
};

寻找峰值

var findPeakElement = function(nums) {
    const n = nums.length;
    let left = 0, right = n - 1, ans = -1;
    while (left <= right) {
        const mid = Math.floor((left + right) / 2);
        if (compare(nums, mid - 1, mid) < 0 && compare(nums, mid, mid + 1) > 0) {
            ans = mid;
            break;
        }
        if (compare(nums, mid, mid + 1) < 0) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return ans;
}

// 辅助函数,输入下标 i,返回一个二元组 (0/1, nums[i])
// 方便处理 nums[-1] 以及 nums[n] 的边界情况
const get = (nums, idx) => {
    if (idx === -1 || idx === nums.length) {
        return [0, 0];
    }
    return [1, nums[idx]];
}
// idx1取值大放回1,idx2大返回-1,并且处理好边界问题
const compare = (nums, idx1, idx2) => {
    const num1 = get(nums, idx1);
    const num2 = get(nums, idx2);
    if (num1[0] !== num2[0]) {
        return num1[0] > num2[0] ? 1 : -1;
    }
    if (num1[1] === num2[1]) {
        return 0;
    }
    return num1[1] > num2[1] ? 1 : -1;
}