题一(278. 第一个错误的版本)
第一天写力扣给了这个题,T-T有被自己菜瞎《第一个错误版本》
思路1
第一次思路错误,想的是与快速排序相似的
//首先测试二分的那个
//如果运行错误的话,向前运行二分的那个
//递归该函数
//如果运行正确的话,向后运行二分的那个
//跳出条件想不出来了呜呜
这个思路错误的原因是:找不到出口
错误1
这个思路错误的原因是:当输入n= 0、1 时,while循环进不去怎么办?只能输出mid。
事实上这时候输出left就可以了。但是我又进入了错误二:
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
//用mid来记录跳出条件
int left=1;
int right=n;
int mid=0;
while(left<right){
mid =(left+right)/2;
//如果中间正确的话,向后运行
if(!isBadVersion(mid)){
left=mid+1;
}
else{//如果中间错误的话,向前运行
right=mid;
}
}
return mid;
}
}
错误2
我以为,只要输出让mid等于边界就行了。那这样就真的对了吗??
错误一是左边界的问题还是右边界的问题?
这里可以结合一下盒子模型理解一下边界的问题。
数量为n的内部有一个错误。
- 可以想象成这样的二维情况下的盒子模型
边界是否被完全规避?!
如果像错误二中这样更改是处理了右间隔,并没有处理左间隔。
(什么时候处理了左右边界?left和right的时候就处理了)
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
//用mid来记录跳出条件
int left=1;
int right=n;
int mid=(left+right)/2;
while(left<right){
mid =(left+right)/2;
//如果中间正确的话,向后运行
if(!isBadVersion(mid)){
left=mid+1;
}
else{//如果中间错误的话,向前运行
right=mid;
}
}
return mid;
}
}
错误3
在错误3中的更改中处理了左间隔,正常来说这是完全正确的版本。
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
//用mid来记录跳出条件
int left=1;
int right=n;
int mid=0;
while(left<right){
mid =(left+right)/2;
//如果中间正确的话,向后运行
if(!isBadVersion(mid)){
left=mid+1;
}
else{//如果中间错误的话,向前运行
right=mid;
}
}
return left;
}
}
错误4
错误:mid = left + (right - left) / 2 ;
而不是mid =(left+right)/ 2
第三种写法会出现数组溢出的问题。left + right过大的情况下数字会超大,(2倍增大了)
- 尽量先做减法后做加法
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
//用mid来记录跳出条件
int left=1;
int right=n;
// int mid=(left+right)/2;
int mid = 0; // 防止计算时溢出
while(left<right){
mid = left + (right - left) / 2;
//如果中间正确的话,向后运行
if(!isBadVersion(mid)){
left=mid+1;
}
else{//如果中间错误的话,向前运行
right=mid;
}
}
return left;
}
}
边界值模板
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0, right = nums.length - 1; // 注意
while(left <= right) { // 注意
int mid = (left + right) / 2; // 注意
if(nums[mid] == target) { // 注意
// 相关逻辑
} else if(nums[mid] < target) {
left = mid + 1; // 注意
} else {
right = mid - 1; // 注意
}
}
// 相关返回值
return 0;
}
}
题二(35. 搜索插入位置)
35. 搜索插入位置
二分查找的另一道题,直接写出思路,困在边界值的处理上。
错误一
第一个版本太多边界值处理不清楚,感觉陷进去了,自己的逻辑一点也理不清。想通过if语句规避掉所有错误。
public static int searchInsert1(int[] nums, int target) {
int left=0;
int right=nums.length-1;
int mid=0;
while(left<right){
mid=left+(right-left)/2;
if(nums[mid]==target){
return mid;
}
if(nums[mid]<target){
left=mid+1;
}else{
right=mid;
}
}
if(nums.length==1&&nums[left]<target){
return 1;
}
if (left==nums.length-1){
return nums.length;
}
return left;
}
错误二
参照边界值模板直接写出第一个版本
public static int searchInsert(int[] nums, int target) {
int left = 0, right = nums.length - 1; // 注意
while(left <= right) { // 注意
int mid = (left + right) / 2; // 注意
if(nums[mid] == target) { // 注意
// 相关逻辑
return left;
} else if(nums[mid] < target) {
left = mid + 1; // 注意
} else {
right = mid - 1; // 注意
}
}
// 相关返回值
return left;
}
错误三
当nums[mid] == target时应直接返回mid
public static int searchInsert(int[] nums, int target) {
int left = 0, right = nums.length - 1; // 注意
while(left <= right) { // 注意
int mid = (left + right) / 2; // 注意
if(nums[mid] == target) { // 注意
// 相关逻辑
return mid;
} else if(nums[mid] < target) {
left = mid + 1; // 注意
} else {
right = mid - 1; // 注意
}
}
// 相关返回值
return left;
}
学会自己编写测试数据
要学会自己编写测试数据
- [1] 0
- [1] 2
- [1234] 1、3、4
- [123] 1、2、3