训练营的第一天, 上个月开始决定转码,马虎的学习了java的一些基础知识,看了几集韩顺平,赶感觉有本质上的提升,于是开始正式刷题. 第一天感觉还行, 虽然直接做题做不出来,但是看解法还是看得懂的,一定要坚持接下来两个月
今天的第一题是关于二分查找,binary search,前提是有序且不重复的
左闭右闭 和 左闭右开
两种解法,在一开始的index, while循环条件,和边界上皆有不同
首先介绍我写的左闭右闭:
看完carl哥的视频后还是比较理解的,但是上手写的时候有很多bug:
1.分清楚写的是数字还是index,这里的target, left和right是不同含义的
2.分清楚条件,一开始就要判断target的合理性
3.右闭的话,判断条件就是小于等于
4. 在while循环判断是已经包括了middle(right),所以此时的middle已经不在新的区间里了,应该用middle-1/+1
5.>>是向右位移, 直接用left + (right - left)/2 一样(是为了防止数字过大超过边界)
6.这里有四种情况,大于,小于,等于(相当于直接找到了),遍历完都没有
class Solution {
public int search(int[] nums, int target) {
//左闭右闭
if(target < nums[0] || target > nums[nums.length - 1]) {
return -1;
}
int left = 0;
int right = nums.length - 1; //这里由于右边闭合了
while(left <= right) {
int middle = left + ((right - left)>>1); //这里可以进一步了解
if(nums[middle] > target) {
right = middle -1;
} else if(nums[middle] < target){
left = middle +1;
} else if(nums[middle] == target){
return middle;
}
}
return -1;
}
}
接下来是左闭右开:
在这里犯了几个低级错误
1.忘记给写 int middle = xxx了,记住java永远是面对对象的
2.记住对middle的赋值要放在循环里,不然是不会改变的
3.这里区别就是,right的定义就是num.size; left一样,但是right 直接=middle
class Solution {
public int search(int[] nums, int target) {
//左闭右开
if(target < nums[0] || target > nums[nums.length - 1]){
return -1;
}
int left = 0;
int right = nums.length; //这里右边是开的,所以直接num.length
while (left < right) {
int middle = left + (right - left)/2;
if(nums[middle] < target) {
left = middle + 1;
} else if (nums[middle] > target) {
right = middle;
} else if (nums[middle] == target) {
return middle;
}
}
return -1;
}
}
下一个是移除元素,有暴力解法和双指针解法
暴力解法:
这个对我来说反而不好理解,反正就是有两个for,第一个是来遍历每一个元素来匹配val;第二个是找到val后,将后面的元素覆盖到前面;
注意条件:
1. 判断如果找到val,进入遍历循环,新的数j, j=i+1,意思是val后面那个元素是j
2. 通过nums[j-1]=nums[j]来覆盖值,然后i--(后面的元素集体往前挪了,所以要减一复原),size--;
class Solution {
public int removeElement(int[] nums, int val) {
int size = nums.length;
for(int i =0; i < size; i++){
if(nums[i] == val){
for(int j = i+1; j < size; j++){
nums[j-1] = nums[j];
}
i--;
size--;
}
}
return size;
}
}
双指针解法:
一个快指针:寻找新数组里所需要的元素(不含target的),也是index
一个慢指针:新数组的下标值就是slow
有以下注意事项:
1. 快指针无论什么情况都+1,慢指针符合条件才+1
2. 当快指针不等于target时,才是我们要的新数组元素
3.if里面要给slow代表的新数组赋值,也要给slow指针右移
4.这里如果不是if,slow就不会移动,也不会给新数组赋值,所以相当于删除了
class Solution {
public int removeElement(int[] nums, int val) {
int slow = 0;
for(int fast = 0; fast < nums.length; fast++){
if(nums[fast] != val){
nums[slow] = nums[fast]; //这里要理解好,是给slow代表的新数组赋值
slow++; //同时慢指针要向右移动
}
}
return slow;
}
}
注意:这里总是会有sb小错误,比如nums总是写成num,甚至分号都忘记打。