LeetCode 704.二分查找
解题思路
根据题目描述,整型数组中的元素是升序的,因此可以使用二分查找对目标值进行搜索。
左闭右开------while(left < right)
思路
左边界为数组第一个元素的下标,即0;右边界为数组最后一个元素的下标加1,即数组的大小。middle = left + (right - left)/2,通过比较nums[middle]与target的大小,更新左右边界并查找目标值。在查找的过程中,有以下3种情况出现:
- nums[middle] > target:需要更新右边界,由前面的分析及while循环条件可知,右边界对应的元素不属于数组,所以right = middle;
- nums[middle] < target:需要更新左边界,由前面的分析及while循环条件可知,左边界对应的元素属于数组并且需要参与下一次二分查找,所以left = middle + 1;
- nums[middle] = target:不需要更新边界,直接返回middle。
代码
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size();
while(left < right) {
int middle = left + (right - left)/ 2;
if(nums[middle] > target) {
right = middle;
} else if(nums[middle] < target) {
left = middle + 1;
}
else {
return middle;
}
}
return -1;
}
};
左闭右闭------while(left <= right)
思路
左边界为数组第一个元素的下标,即0;右边界为数组最后一个元素的下标,即数组的大小减1。middle = left + (right - left)/2,通过比较nums[middle]与target的大小,更新左右边界并查找目标值。在查找的过程中,有以下3种情况出现:
- nums[middle] > target:需要更新右边界,由前面的分析及while循环条件可知,右边界对应的元素属于数组并且需要参与下一次二分查找,所以right = middle - 1;
- nums[middle] < target:需要更新左边界,由前面的分析及while循环条件可知,左边界对应的元素属于数组并且需要参与下一次二分查找,所以left = middle + 1;
- nums[middle] = target:不需要更新边界,直接返回middle。
代码
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 - left)/ 2;
if(nums[middle] > target) {
right = middle - 1;
} else if(nums[middle] < target) {
left = middle + 1;
}
else {
return middle;
}
}
return -1;
}
};
LeetCode 27.移除元素
解题思路
暴力解法
思路
使用两个for循环进行移除,一个for循环用于遍历数组,当nums中的元素与val相同时,另一个for循环用于更新数组内容以及数组有效长度。
代码
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int num = nums.size();
for(int i = 0; i < num; i ++) {
if(val == nums[i]) {
for(int j = i; j < num - 1; j ++) {
nums[j] = nums[j + 1];
}
num --;
i --; // 更新后的数组,原来下标i处的元素需要重新与val比较;每次循环i自动加1
}
}
return num;
}
};
双指针解法
思路
定义两个指针,使用一个for循环完成移除。
两个指针的作用分别为:
- slow:用于标记数组需要更新的位置;
- fast:用于索引数组中符合要求的元素。
代码
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int num = 0;
for(int fast = 0, slow = 0; fast < nums.size(); fast ++) {
if(val != nums[fast]) {
nums[slow ++] = nums[fast];
}
num = slow;
}
return num;
}
};
总结
二分查找的使用条件是数组需要是有序数组,有两种写法,分别为:
- 左闭右开:循环条件是while(left < right),左边界为left = middle + 1,右边界为right = middle;
- 左闭右闭:循环条件是while(left <= right),左边界为left = middle + 1,右边界为right = middle - 1;
两种方法的区别是右边界需不要参与下次二分查找,中心思想是循环不变量。
双指针法实际是使用了两个变量代替了两个for循环,从而降低时间复杂度。