二分查找
- 给定一个n个元素有序的(升序)整型数组 nums 和一个目标值 target,写一个函数检索 nums中的 target, 如果目标值存在返回下标, 否则返回-1。
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function(nums, target) {
var len = nums.length;
var left = 0, right = len - 1;
if(len === 1){
return target === nums[0]?0 : -1;
}
while(left <= right){
var mid = Math.floor((left + right) / 2); //向下求整
if(target < nums[mid]){ // 目标值在左侧
right = mid - 1
}else if(target > nums[mid]){ // 目标值在右侧
left = mid + 1
}else{ // 目标值在中间
return mid;
}
}
return -1;
};
-如 : 在[10,11,22,33,44,55,66]中找目标值10;
10的数组下标是0; 66的数组下标是6;
| 最小值 | 中间值 | 最大值 | 说明 |
|---|---|---|---|
| 0 | 3 | 6 | 数组下标0和6的中间值为(0+6)/2=3,下标3对应的值是33,目标值10<33;则新的最大值下标为3-1=2 |
| 0 | 1 | 2 | 数组下标0和2的中间值为(0+2)/2=1,下标1对应得值是11,目标值10<11;则新的最大值下标为1-1=0 |
| 0 | 0 | 0 | 数组下标0和0的中间值为(0+0)/2=0,下标0对应得值是10,目标值10==10;顾结果为10对应得下标0 |
寻找旋转排序数组中的最小值
/**
* @param {number[]} nums
* @return {number}
*/
var findMin = function(nums) {
var len = nums.length
if(len === 1){
return nums[0]
}
var left = 0, right = len - 1;
while(left <= right){
var mid = Math.floor((left + right)/2);
if(nums[mid] <= nums[right]){ //中间值 小于 最右侧值,则最小值等于中间值或者在左侧
if(nums[mid] > nums[mid-1]){
right = mid - 1;
}else{ //最小值等于中间值的情况
return nums[mid]
}
}else{ //中间值 大于最右侧值,则最小值在右侧
left = mid + 1
}
}
return nums[left]
};
搜索旋转排序数组
- 整数数组nums按升序排序,数组中的值互不相等。
- 在传递给函数之前,nums在预先未知的某个小标k(0<=k<=nums.length)上进行了旋转,使数组变为[nums[k], nums[k+1],..., nums[n-1], nums[0],nums[1],...,nums[k-1]]。例如,[0,1,2,4,5,6,7]在下标3处经旋转后可能变成[4,5,6,7,0,1,2]。
- 给你旋转后的数组nums和一个整数target,如果nums中存在这个目标值target,则返回它的下标,否则返回-1。
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function(nums, target) {
var len = nums.length
if(len === 1){
return nums[0] === target?0: -1;
}
var left = 0, right = len -1;
while(left <= right){
var mid = Math.floor((left + right) / 2)
if(target === nums[mid]){
return mid;
}
//通过画曲线,分三段对比
// 中间数小于最右数
if(nums[mid] <= nums[right]){
if(target > nums[right]){
right = mid - 1
}else if(target < nums[mid]){
right = mid - 1
}else{
left = mid + 1
}
}else{
if(target > nums[mid]){
left = mid + 1
}else if(target < nums[left]){
left = mid + 1
}else{
right = mid - 1
}
}
}
return -1;
};
搜索旋转排序数组 II
- 整数数组nums按升序排序,数组中的值不必互不相同
/**
* @param {number[]} nums
* @param {number} target
* @return {boolean}
*/
var search = function(nums, target) {
var len = nums.length
if(len == 1 && target == nums[0]){
return true
}
var left = 0, right = len - 1
while(left <= right){
var mid = Math.floor((left + right) / 2)
if(target === nums[mid]){
return true
}
if(nums[left] === nums[mid] && nums[mid] === nums[right] ){ //相等情况的特殊处理
left ++
right --
}else if(nums[mid] <= nums[right]){ //右边是升序
if (target > nums[mid] && target <= nums[right]){
left = mid + 1
}else{
right = mid - 1
}
}else { //左边是升序
if(target >= nums[left] && target < nums[mid]){
right = mid - 1
}else{
left = mid + 1
}
}
}
return false
}
有序数组中的单一元素
leetcode-cn.com/problems/si… 给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。
/**
* @param {number[]} nums
* @return {number}
*/
var singleNonDuplicate = function(nums) {
var len = nums.length
var left = 0, right = len - 1
while(left <= right){
var mid = Math.floor((left + right) / 2)
//判断中间位置是奇数还是偶数
//中间位置是偶数,前面就有偶数个整数
//中间位置是奇数,前面就有奇数个整数
var double = false
if(mid%2 === 0){
double = true
}
if(nums[mid] === nums[mid + 1]){
if(double){//中间位置为偶数,左边有偶数个整数,顾单数在右侧
left = mid + 2
}else{//中间位置为奇数,左边有奇数个整数,顾单数在左侧
right = mid - 1
}
}else if (nums[mid] === nums[mid - 1]){
if(double){ //中间位置为偶数,左边有偶数个整数,mid-1占了一个,剩余奇数个整数,则单数在左侧
right = mid - 2
}else{ //中间位置为奇数,左边有奇数个整数,mid-1占了一个,剩余偶数个整数,则单数在右侧
left = mid + 1
}
}else{
return nums[mid]
}
}
};
寻找峰值
- 峰值元素是指其值大于左右相邻值的元素
- 给你一个输入数组nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。
/**
* @param {number[]} nums
* @return {number}
*/
var findPeakElement = function(nums) {
var len = nums.length
var left = 0, right = len - 1
while(left < right){
var mid = Math.floor((left + right)/2)
if(nums[mid] > nums[mid + 1]){ //
right = mid
}else{
left = mid + 1
}
}
return left
};
var nums = [1,2,1,3,5,6,4]
- left=0 right=6 mid=3 nums[3]=3 nums[4]=5 nums[3]<nums[4] 则left=4
- left=4 right=6 mid=5 nums[5]=6 nums[6]=4 nums[5]>nums[6] 则right=5
- left=4 right=5 mid=4 nums[4]=5 nums[5]=6 nums[4]<nums[5] 则left=5
- left=5 right=5 则while循环终端