二分查找
var binarySearch = function(nums,key){
let l=0,h=nums.length-1;
while(l<=h){
let m = l+(h-l)/2;
if(nums[m]==key){
return m;
}else if(nums[m]>key){
h=m-1;
}else{
l=m+1;
}
}
return -1;
}
计算并返回 x 的平方根,其中 x 是非负整数。 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
一个数 x 的开方 sqrt 一定在 0 ~ x 之间,并且满足 sqrt == x / sqrt。可以利用二分查找在 0 ~ x 之间查找 sqrt。
对于 x = 8,它的开方是 2.82842…,最后应该返回 2 而不是 3。在循环条件为 l <= h 并且循环退出时,h 总是比 l 小 1,也就是说 h = 2,l = 3,因此最后的返回值应该为 h 而不是 l。
var mySqrt = function(x) {
if(x<=1){
return x;
}
return parseInt(Math.sqrt(x));
};
大佬的解法
public int mySqrt(int x){
if(x<=1){
return x;
}
int l = 1,h=x;
while(l<=h){
int mid = l+(h-l)/2;
int sqrt = x/mid;
if(sqrt==mid){
return mid;
}else if(mid>sqrt){
h = mid-1;
}else{
l=mid+1;
}
}
return h;
}
给定一个只包含小写字母的有序数组letters?和一个目标字母?target,寻找有序数组里面比目标字母大的最小字母。
数组里字母的顺序是循环的。举个例子,如果目标字母target = ‘z’ 并且有序数组为?letters = [‘a’, ‘b’],则答案返回?‘a’。 分情况讨论:
- 如果letters[0]>target||letters[letters.length-1]<=target说明letters[0]就是我们需要查找的字符串
- 先取mid = left+(right+left)/2;
- 如果letters[mid]==target.由于有序数组,说明需要在右边查找,left = mid+1;
- 如果letters[mid]<target,由于是有序数组,说明需要在右边查找,left = mid+1;
- 当letters[mid]>target,需要分情况讨论,如果letters[mid-1]<=target,说明letters[mid]就是我们需要查找的字符,返回即可,否则,我们需要继续在左边查找,left = mid-1;
var nextGreatestLetter = function(letters, target) {
let n = letters.length;
let l = 0,h=n-1;
while(l<=h){
let mid = parseInt(l+(h-l)/2);
if(letters[mid]<=target){
l = mid+1;
}else{
h = mid-1;
}
}
return l<n?letters[l]:letters[0];
};
var nextGreatestLetter = function(letters, target) {
if(letters[0]>target||letters[letters.length-1]<=target){
return letters[0];
}
let left = 1,right = letters.length-1;
while(left<=right){
let mid = left+(right-left)/2;
if(letters[left]<=target){
left = mid+1;
}else{
if(letters[mid-1]<=target){
return letters[mid];
}else{
right = mid-1;
}
}
}
return ' ';
};
给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。 解题思路
var singleNonDuplicate = function(nums) {
let l = 0,r = nums.length-1;
while(l<r){
let h = parseInt((r+l)/2);
if(h%2==1){
if(nums[h]==nums[h+1]){
r = h-1;
}else{
l = h+1;
}
}else{
if(nums[h]==nums[h+1]){
l=h+2;
}else{
r = h;
}
}
}
return nums[l]
};
最简单的办法:
var singleNonDuplicate = function(nums) {
let result = 0;
for(let i=0;i<nums.length/2;i++){
if(nums[i*2]!==nums[i*2+1]){
result = nums[i*2];
break;
}
}
return result;
};
- 线性扫描 超时
var solution = function(isBadVersion) {
return function(n) {
for(let i=1;i<n;i++){
if(isBadVersion(i)){
return i;
}
}
};
};
- 二分查找
var solution = function(isBadVersion) {
return function(n) {
let left = 1,right = n;
while(left<right){
let mid = left+parseInt((right-left)/2);
if(isBadVersion(mid)){
right = mid;
}else{
left = mid+1;
}
}
return left;
};
};
public int firstBadVersion(int n) {
int left = 1;
int right = n;
while (left < right) {
int mid = left + (right - left) / 2;
if (isBadVersion(mid)) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
假设按照升序排序的数组在预先未知的某个点上进行了旋转。 ( 例如,数组?[0,1,2,4,5,6,7] 可能变为?[4,5,6,7,0,1,2]?)。 请找出其中最小的元素。 你可以假设数组中不存在重复元素。
- Leetcode官方解法,寻找变化点
变化点特点:
- 所有变化点左侧元素>数组的第一个元素
- 所有变化点右侧元素<数组的第一个元素
算法:
- 寻找数组的中间元素 mid;
- 如果中间元素>数组第一个元素,需要在mid右边搜索变化点
- 如果中间元素<数组第一个元素,需要在mid左边搜索变化点
- 当我们找到变化点时停止搜索,当以下条件满足任意一个即可:
- nums[mid] > nums[mid + 1],因此 mid+1 是最小值。
- nums[mid - 1] > nums[mid],因此 mid 是最小值。
public int findMin(int[] nums){
if(nums.length==1){
return nums[0];
}
int left = 0,right = nums.length-1;
if(nums[right]>nums[0]){
return nums[0];
}
while(left<=right){
int mid = left + (right-left)/2;
if(nums[mid]>nums[mid+1]){
return nums[mid+1];
}
if(nums[mid-1]>nums[mid]){
return nums[mid];
}
if(nums[mid]>nums[0]){
left = mid+1;
}else{
right = mid-1;
}
}
return -1;
}
var findMin = function(nums) {
nums.sort((a,b)=>(a-b));
return nums[0];
};
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是?O(log n) 级别。
如果数组中不存在目标值,返回?[-1, -1]。
var searchRange = function(nums, target) {
let first = binarySearch(nums,target);
let last = binarySearch(nums,target+1)-1;
if(first==nums.length||nums[first]!=target){
return [-1,-1];
}else{
return [].concat(first,Math.max(first,last));
}
};
var binarySearch = function(nums,target){
let left = 0,right = nums.length;
while(left<right){
let mid = left + parseInt((right-left)/2);
if(nums[mid]>=target){
right = mid;
}else{
left = mid+1;
}
}
return left;
};
|