-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
第 150 题:二分查找如何定位左边界和右边界 #320
Comments
二分查找基础代码//递归查找
function erfen_digui(arr, val, left = 0, right = arr.length - 1) {
if (left > right) {
return -1;
}
let cent = Math.floor((right + left) / 2);
if (arr[cent] === val) {
return `最终查找结果下标为${cent}`;
} else if (arr[cent] > val) {
right = cent - 1;
} else {
left = cent + 1;
}
return erfen_digui(arr, val, left, right);
}
//非递归查找
function erfen_feidigui(arr, val) {
let left = 0,
right = arr.length - 1;
while (left <= right) {
let cent = left + Math.floor((right - left) / 2);
if (arr[cent] === val) {
return `最终查找结果下标为${cent}`;
} else if (arr[cent] > val) {
right = cent - 1;
} else {
left = cent + 1;
}
}
return -1;
}
//左边界查找(查找第一个元素)
function erfen_digui(arr, val, left = 0, right = arr.length - 1) {
if (left > right) {
return -1;
}
let cent = Math.floor((right + left) / 2);
if (arr[cent] === val) {
/****************改动点********************/
if (arr[cent - 1] === val) {
right = cent - 1;
} else {
return `最终查找结果下标为${cent}`;
}
/*****************************************/
} else if (arr[cent] > val) {
right = cent - 1;
} else {
left = cent + 1;
}
return erfen_digui(arr, val, left, right);
}
// 二分查找右边界(查找最后一个元素)
function erfen_digui(arr, val, left = 0, right = arr.length - 1) {
if (left > right) {
return -1;
}
let cent = Math.floor((right + left) / 2);
if (arr[cent] === val) {
/****************改动点********************/
if (arr[cent + 1] === val) {
left = cent + 1;
} else {
return `最终查找结果下标为${cent}`;
}
/*****************************************/
} else if (arr[cent] > val) {
right = cent - 1;
} else {
left = cent + 1;
}
return erfen_digui(arr, val, left, right);
} |
function search(arr, target) {
let begin = 0;
let end = arr.length - 1;
const result = [];
while (begin <= end) {
const mid = (begin + end) >>> 1;
if (target === arr[mid]) {
let left = mid;
let right = mid;
result.push(mid)
while (--left && left > 0) {
if (arr[mid] === arr[left]) {
result.unshift(left)
}
}
while (++right && right < arr.length) {
if (arr[mid] === arr[right]) {
result.push(right)
}
}
break;
} else if (target > arr[mid]) {
begin = mid + 1;
} else {
end = mid - 1;
}
}
return result
}
// 返回出现目标数据的索引位置数组 第一次出现位置为result[0] 最后一次为 result[result.length -1]
//const list1 = [1, 4, 4, 4, 5, 6, 7];
//console.log(search(list1, 4)); [1, 2, 3] 第一次出现索引位置为1 最后一次出现的索引位置为3 |
function twoY(arr,str){ |
题目介绍二分查找定位左边界和右边界 knuth 说过,二分查找虽然思路很简单,但是细节是魔鬼。 通常,我会根据$[left, right]$ 和
function binarySearch(arr, target) {
let left = 0;
let right = arr.length;
while (left < right) {
let mid = first + Math.floor((right-left)/2);
if(arr[mid] < target) left = mid + 1
else right = mid
}
return left;
}
function binarySearch(arr, target) {
let left = 0;
let right = arr.length;
while (left < right) {
let mid = first + Math.floor((right-left)/2);
if(arr[mid] < target) left = mid + 1
else right = mid
}
return left < arr.length && arr[left] === target;
}
function binarySearch(arr, target) {
let left = 0;
let right = arr.length;
while (left < right) {
let mid = first + Math.floor((right-left)/2);
if(arr[mid] < target) left = mid + 1
else right = mid
}
return left-1;
} |
/**
* 寻找目标值左侧边界
* @param {*} nums
* @param {*} target
*/
function findLeft(nums, target) {
let left = 0;
let right = nums.length;
while (left < right) {
let mid = Math.floor((left + right) / 2);
if (nums[mid] === target) {
right = mid; //关键地方
} else if (nums[mid] > target) {
right = mid; //关键地方
} else {
left = mid + 1;
}
}
return left;
}
/**
* 寻找目标值右侧边界
* @param {*} nums
* @param {*} target
*/
function findRight(nums, target) {
let left = 0;
let right = nums.length;
while (left < right) {
let mid = Math.floor((left + right) / 2);
if (nums[mid] === target) {
left = mid + 1 //关键地方
} else if (nums[mid] > target) {
right = mid;
} else {
left = mid + 1;//关键地方
}
}
return left;
}
let arr = [1, 3, 4, 4, 6, 8, 10];
console.log('left bound:', findLeft(arr, 4))
console.log('right bound:', findRight(arr, 4)) |
|
递归实现 /**
* @param {Array} arr 数组
* @param {Number} item 待查找项
* @param {Number} min 第一个索引
* @param {Number} max 最后一个索引
*/
function _binarySearch(arr, item, min = 0, max = arr.length - 1) {
const half = Math.floor(min + (max - min) / 2)
if (item < arr[half]) return _binarySearch(arr, item, min, half - 1)
if (item > arr[half]) return _binarySearch(arr, item, half + 1, max)
return half
}
/**
* @param {Array} arr 数组
* @param {Number} item 待查找项
*/
const binarySearch = (arr, item) => _binarySearch(arr, item) // 隐藏多余参数 循环实现: /**
* @param {Array} arr 数组
* @param {Number} item 待查找项
*/
function binarySearch(arr, item) {
let min = 0
let max = arr.length - 1
let half
while (min <= max) {
half = Math.floor(min + (max - min) / 2)
if (item > arr[half]) {
min = half + 1
} else if (item < arr[half]) {
max = half - 1
} else {
break
}
}
return half
} 测试: /**
* test
*/
const res = binarySearch([1, 3, 66, 88, 233, 666], 666)
console.log('res: ', res) // 5 |
// 非递归解法, 查lastIndex原理一样
function searchFirstIndex(arr, target) {
let firstIndex = -1
let leftIndex = 0
let rightIndex = arr.length // 初始区间为[0, arr.length)
// leftIndex == rightIndex时终止循环
while(leftIndex < rightIndex) {
let midIndex = Math.floor((leftIndex + rightIndex) / 2)
let mid = arr[midIndex]
if(mid == target) {
if(firstIndex == -1 || firstIndex > midIndex) {
firstIndex = midIndex
rightIndex = midIndex // 继续向左查找
}
} else if(mid < target) {
leftIndex = midIndex + 1
} else if(mid > target) {
rightIndex = midIndex
}
}
return firstIndex
} |
findRight 应当返回left - 1 |
function findLeft(nums: number[], target: number): number {
let left = 0
let right = nums.length
while (left < right) {
const mid = left + Math.floor((right - left) / 2)
if (nums[mid] === target) {
right = mid
} else if (nums[mid] < target) {
left = mid + 1
} else {
right = mid
}
}
if (nums[left] !== target) {
return -1
}
return left
}
function findRight(nums: number[], target: number): number {
let left = 0
let right = nums.length
while (left < right) {
const mid = left + Math.floor((right - left) / 2)
if (nums[mid] === target) {
left = mid + 1
} else if (nums[mid] < target) {
left = mid + 1
} else {
right = mid
}
}
if (nums[left - 1] !== target) {
return -1
}
return left - 1
} |
稍微对二分查找改造一下就可以,找到目标值之后左右滑动确定值 function findBoundary(source, target, start = 0, end = source.length - 1) {
if (end - start === 1) {
if (source[start] !== target) return -1;
return leftAndRight(source, target, start);
}
const mid = start + Math.floor((end - start) / 2);
if (source[mid] < target) {
return findBoundary(source, target, mid, end);
} else if (source[mid] > target) {
return findBoundary(source, target, start, mid);
} else {
return leftAndRight(source, target, mid);
}
}
function leftAndRight(source, target, mid) {
let i = mid;
let j = mid;
while (source[i - 1] === target) {
i--;
}
while (source[j + 1] === target) {
j++;
}
return [i, j];
} |
var search = function (nums, target, isBorder) {
let min = 0;
let max = nums.length - 1;
let isRightBorder = false;
let isLeftBorder = false;
if (isBorder === "left") {
isLeftBorder = true;
} else if (isBorder === "right") {
isRightBorder = true;
}
while (min <= max) {
let mid = Math.ceil((max + min) / 2);
let cur = nums[mid];
if (cur === target) {
if (isLeftBorder) {
mid = mid - 1;
if (nums[mid] !== target) {
return mid + 1;
}
max = mid;
} else if (isRightBorder) {
mid = mid + 1;
if (nums[mid] !== target) {
return mid - 1;
}
min = mid;
} else {
return mid;
}
} else if (target > cur) {
min = mid + 1;
} else {
max = mid - 1;
}
}
return -1;
}; |
不使用JS数组API,查找有序数列最先出现的位置和最后出现的位置
The text was updated successfully, but these errors were encountered: