LeetCode 704. 二分查找
思路:
最基础的二分查找,看到升序数组可以马上想到用二分,用left和right两个指针表示可能存在的区间,middle为两个指针的中点,如果比middle小,那就将右区间缩小到middle-1,比middle大则将左区间缩小到middle+1,最后注意left==right的情况
代码:
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 (nums[middle] < target)
left = middle + 1;
else if (nums[middle] > target)
right = middle - 1;
else
return middle;
}
return -1;
}
};
时间复杂度:O(logn)
空间复杂度:O(1)
附:LeetCode 35. 搜索插入位置
思路:
和LC704一样也是用二分法,而且题目要求了必须用logn的复杂度,代码基本一致,唯一不同的是没找到的时候返回的是位置,当left==right的时候,就是没找到的情况,返回left或者right都可以
代码:
class Solution {
public:
int searchInsert(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 left;
}
};
时间复杂度:O(logn)
空间复杂度:O(1)
附:LeetCode 34. 在排序数组中查找元素的第一个和最后一个位置
思路:
和二分法不同的是,查找的数可能会出现很多次,因此在数组中找到元素后,还需要用递归的方法查找该元素之前或是之后是否有相同的元素,因为要求复杂度logn,所以不能在第一次二分法查找到元素后遍历该元素之前或之后的元素寻找该元素的第一个位置和最后一个位置,因为在最差的情况下,整个数组都是该元素的话,查找第一个位置和最后一个位置耗费的时间退化到了n(遍历整个数组),所以必须要递归调用二分查找来寻找一头一尾的位置
代码:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
vector<int> ans(2, -1);
while (left <= right)
{
int middle = (left + right) / 2;
if (nums[middle] < target)
left = middle + 1;
else if (nums[middle] > target)
right = middle - 1;
else
{
// 开始位置
int temp = search(left, middle - 1, nums, target, 1);
if (temp != -1)
ans[0] = temp;
else
ans[0] = middle;
// 结束位置
temp = search(middle+1, right, nums, target, 0);
if (temp != -1)
ans[1] = temp;
else
ans[1] = middle;
return ans;
}
}
return ans;
}
int search(int left, int right, vector<int>& nums, int target, bool position)
{
int ans = -1;
while (left <= right)
{
int middle = (left + right) / 2;
if (nums[middle] < target)
left = middle + 1;
else if (nums[middle] > target)
right = middle - 1;
else
{
ans = middle;
break;
}
}
if (ans != -1)
{
if (position)
{
int temp = search(left, ans - 1, nums, target, 1);
if (temp != -1)
ans = temp;
}
else
{
int temp = search(ans + 1, right, nums, target, 0);
if (temp != -1)
ans = temp;
}
}
return ans;
}
};
时间复杂度:O(logn)
空间复杂度:O(1)
LeetCode 27. 移除元素
思路:
因为数组没办法直接删除,只能用之后的一个元素覆盖覆盖当前的,所以一开始的思路是遍历整个数组,每当发现需要移除的元素后,用后一个元素覆盖需要移除的元素,并将数组的长度减去1,但是这样无法解决连续几个数都是需要删除的数的问题,因为用后一个元素覆盖当前元素时,后一个元素也是需要被删掉的,改进办法是用快慢指针,慢指针指向下一个需要被覆盖的元素,快指针指向下一个不需要被移除的元素,每次循环中,如果当前元素不需要被移除,快慢指针都+1,如果当前元素需要被移除,慢指针不动,记录需要被移除的元素的位置,快指针继续往下寻找下一个不需要被移除的元素
代码:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int size = nums.size(); int slow = 0;
for (int i = 0; i < nums.size(); i++)
{
if (nums[i] == val)
{
size--;
}
else
{
nums[slow] = nums[i];
slow++;
}
}
return size;
}
};
注:在代码中,fast和i一样每次循环都+1,可以将fast删去用i代替节省4个字节的空间
时间复杂度:O(n)
空间复杂度:O(1)