704. 二分查找
题目描述:
题目链接:
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
解题思路:看见数组是升序排列且需要寻找到目标值,即可确定使用二分查找
问题1:循环条件是left<right,还是left<=right
问题2:假设确定target在左区间之后,左区间left应该如何赋值,right=middle还是right=middle-1
有关这两个问题实际上就是确定区间问题,有关二分查找的主流解决方案基本上是基于左闭右闭或者左闭右开区间。
解法1:针对左闭右闭区间(举例[2,4],该区间取值是2,3,4)
首先是right的取值,因为右边为闭合区间,即能够取到最右侧的值且区间左值能够等于区间右值(如[1,1]是合法区间),所以right=nums.size()-1。
此时的循环条件就是while(left <= right)。
情况1:当目标值(T)位于区间中点(M)的左侧,此时左区间(L)不变,更新右区间(R)。此时R应该等于M-1,即right = middle-1。因为此时为闭区间,而M不等于T,即nums[middle]!=target,此时右区间即可取值为middle-1。
情况2:当目标值(T)位于区间中点(M)的右侧,此时右区间(R)不变,更新右区间(L)。按照刚刚的理论,此时左区间的取值应该为middle+1。
代码实现如下:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size()-1; //左闭右闭区间
while(left <= right){
int middle = (left + right)/2;
if (target > nums[middle]){ //target此时处于右区间[middle+,right]
left = middle + 1;
}
else if (target < nums[middle]){ //target此时处于左区间 [left , middle-1]
right = middle -1 ;
}
else { // nums[middle] = target
return middle;
}
}
return -1;
}
};
解法2:针对左闭右开区间(举例[2,4),该区间取值是2,3)
同样首先是right的取值,因为右边为开区间,即不能够取到最右侧的值且区间左值不能够等于区间右值(如[1,1)是不法区间),所以right=nums.size()。
此时的循环条件就是while(left < right)。
情况1:当目标值(T)位于区间中点(M)的左侧,此时左区间(L)不变,更新右区间(R)。此时R应该等于M,即right = middle。因为此时为开区间,取不到最右侧的值,即取不到nums[middle]的值,所以,此时右区间即可取值为middle。
情况2:情况2:当目标值(T)位于区间中点(M)的右侧,此时右区间(R)不变,更新右区间(L)。因为左区间为闭合区间,所以同情况1,此时左区间的取值应该为middle+1。
代码实现如下:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size(); //左闭右开区间
while(left < right){
int middle = (left + right)/2;
if(target > nums[middle]){ //target此时处于右区间 [middle+1,right)
left = middle+1;
}
else if (target < nums[middle]){//target此时处于左区间[left,middle)
right = middle;
}
else{// target = nums[middle]
return middle;
}
}
return -1;
}
};
27.移除元素
题目描述:
解题思路:1、暴力解法,2、快慢指针
数组特性:连续的储存空间,所以在数组里面删除指定的值,是使用新的值将旧的值进行覆盖,而数组的实际存储空间并为改变。
1、暴力解法思路:
使用双循环,第一层循环进行遍历,第二层循环将所需要删除的值用数组之后的值进行覆盖,即数组迁移一位。
代码实现:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int size = nums.size(); //记录数组大小
for(int i =0;i<size;i++){ //进入第一层循环,遍历数组
if(val == nums[i]){ //判断数组的值是否等于需要删除的值
for(int j = i+1;j<size;j++){ //若相等,进入第二层循环
nums[j-1] = nums[j]; //数组整体前移覆盖
}
i--; //用i+1的值覆盖i
size--; //数组长度减1
}
}
return size ;
}
};
2、快慢指针:
使用快指针进行遍历,如果不是需要删除的值则,使用慢指针进行存储为新的数组。
代码实现:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0; //设置慢指针
for(int fast = 0;fast<nums.size();fast++){
if(val != nums[fast]){ //快指针遍历数组,不等于删除的值
//则复制给慢指针所指向的值
nums[slow] = nums[fast];
slow++;
}
}
return slow;
}
};
总结:学习时长3小时,目前没有遇到难以解决的问题