赞
踩
题目链接: 704. 二分查找
思路:
解题方法
第一种写法:定义target目标值是在一个左闭右闭[left, right]的区间中
因为定义target在[left, right]区间,所以有如下两点:
例如在数组:1,2,3,4,7,9,10中查找元素2,如图所示:
代码如下:
// 版本一 class Solution { public: int search(vector<int>& nums, int target) { int left = 0; int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right] while (left <= right) { // 当left==right,区间[left, right]依然有效,所以用 <= int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2 if (nums[middle] > target) { right = middle - 1; // target 在左区间,所以[left, middle - 1] } else if (nums[middle] < target) { left = middle + 1; // target 在右区间,所以[middle + 1, right] } else { // nums[middle] == target return middle; // 数组中找到目标值,直接返回下标 } } // 未找到目标值 return -1; } };
第二种写法:定义 target 是在一个在左闭右开的区间里,也就是[left, right)
有如下两点:
在数组:1,2,3,4,7,9,10中查找元素2,如图所示:(注意和方法一的区别)
代码如下:(详细注释)
// 版本二 class Solution { public: int search(vector<int>& nums, int target) { int left = 0; int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right) while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 < int middle = left + ((right - left) >> 1); if (nums[middle] > target) { right = middle; // target 在左区间,在[left, middle)中 } else if (nums[middle] < target) { left = middle + 1; // target 在右区间,在[middle + 1, right)中 } else { // nums[middle] == target return middle; // 数组中找到目标值,直接返回下标 } } // 未找到目标值 return -1; } };
总结
需要注意的地方
对于middle的获取存在疑惑:
正常人理解应是:middle = (left + right)/2
可是这样写会有溢出风险, 那么解决办法是应这样写:
middle = left + (right - left)/2
middle = left + ((right - left) >> 1)
其中">>"代表移位操作,二进制数向右遗一位相当于十进制数除以2,但移位操作不存在小数点问题
题目链接: 27. 移除元素
思路:
暴力解法代码如下:
// 时间复杂度:O(n^2) // 空间复杂度:O(1) class Solution { public: int removeElement(vector<int>& nums, int val) { int size = nums.size(); 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--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位 size--; // 此时数组的大小-1 } } return size; } };
双指针法代码如下:
// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
if (val != nums[fastIndex]) {
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
};
注意这些实现方法并没有改变元素的相对位置!
/** * 相向双指针方法,基于元素顺序可以改变的题目描述改变了元素相对位置,确保了移动最少元素 * 时间复杂度:O(n) * 空间复杂度:O(1) */ class Solution { public: int removeElement(vector<int>& nums, int val) { int leftIndex = 0; int rightIndex = nums.size() - 1; while (leftIndex <= rightIndex) { // 找左边等于val的元素 while (leftIndex <= rightIndex && nums[leftIndex] != val){ ++leftIndex; } // 找右边不等于val的元素 while (leftIndex <= rightIndex && nums[rightIndex] == val) { -- rightIndex; } // 将右边不等于val的元素覆盖左边等于val的元素 if (leftIndex < rightIndex) { nums[leftIndex++] = nums[rightIndex--]; } } return leftIndex; // leftIndex一定指向了最终数组末尾的下一个元素 } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。