今天开始正式备战明年秋招,那算法必不可少,所以从今天开始每天力扣两三道题,有兴趣的可以一起探讨!
-第 一题:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
思路一:比较简单,首先想到的就是遍历数组和目标值进行比较,相等就返回下标值!代码如下:
class Solution {
public int search(int[] nums, int target) {
for(int i=0;i<nums.length;i++){
if(nums[i]==target){
return i;
}
}
return -1;
}
}
思路二:为了提高效率,采用二分法比较值,时间复杂度就低了许多!
public int search(int[] nums, int target) {
int left=0;//左下标
int mid;//中间值
int right=nums.length-1;//右下标
while(left<=right){//确定还有元素
mid=(left+right)/2;
if(nums[mid]==target){//二分出来的值相等就可以返回
return mid;
}else if (nums[mid]<target){
left=mid+1;
}else{
right=mid-1;
}
}
return -1;
}
}
- 第二题:有n个版本,找出第一个错误版本!例如【######】找出第一个#的位置!*
解题思路:将左右边界分别初始化为 1 和 n,其中 n 是给定的版本数量。设定左右边界之后,每次我们都依据左右边界找到其中间的版本,检查其是否为正确版本。如果该版本为正确版本,那么第一个错误的版本必然位于该版本的右侧,我们缩紧左边界;否则第一个错误的版本必然位于该版本及该版本的左侧,我们缩紧右边界。
这样我们每判断一次都可以缩紧一次边界,而每次缩紧时两边界距离将变为原来的一半,因此我们至多只需要缩紧 O(\log n)O(logn) 次。
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
int low=1;
int right=n;
while(low<right){
int mid=low + (right - low)/2;//防止计算溢出
if(isBadVersion(mid)){
right=mid;
}else{
low=mid+1;
}
}
return low;
}
}
这个容易理解,当low=right的时候就有结果了!!可以动手尝试一下就知道了,还有一个地方比较难理解的就是:mid=low+(right-low)/2为啥不是(low+right)/2:
比如(9+8)/2=8和8+(9-1)/2还是有很大区别的,第一个式子数值比较大,转换成第二种后就避免了这种情况!!!
- 第三题:给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法
解答:
class Solution {
public int searchInsert(int[] nums, int target) {
int lo=0;
int mi;
int hi=nums.length-1;
while(lo<=hi){//这里一定要有等号,用于判断最后一轮的目标值到底是在左边还是右边
mi=lo+(hi-lo)/2;//防止溢出
if(nums[mi]==target){
return mi;
}else if(nums[mi]<target){
lo=mi+1;
}else{
hi=mi-1;
}
}
return hi+1;
}
}
有新的解法朋友们可以探讨一下!!