1.二分查找
题目链接:. - 力扣(LeetCode)
思路:二分查找
题解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-left)/2);
if(nums[middle]<target)
{
left=middle+1;
}
else if(nums[middle]>target)
{
right=middle-1;
}
else
{
return middle;
}
}
return -1;
}
};
解释:在定义右值的时候我们取了nums.size()-1,这将target的索引值限制在了闭区间[left,right],当left=right时,区间[left,right]仍然有效,所以在while循环中应该使用<=。当nums[middle]<target时,target在右半部分,即[middle+1,right];当nums[middle]>target时,target在左半部分,即[left,middle-1]。
题解2:
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)
{
left=middle+1;
}
else if(nums[middle]>target)
{
right=middle;
}
else
{
return middle;
}
}
return -1;
}
};
解释:在定义右值的时候我们取了nums.size(),这将target的索引值限制在了左闭右开区间[left,right),当left=right时,区间[left,right)无效,所以在while循环中应该使用<。当nums[middle]<target时,target在右半部分,即[middle+1,right);当nums[middle]>target时,target在左半部分,即[left,middle)。
复杂度分析:
时间复杂度:O(log n),因为影响循环次数的因素是int middle=left+((right-left)/2);这行代码
空间复杂度:O(1)
2.移除元素
题目链接:. - 力扣(LeetCode)
思路:快慢指针
题解:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
//定义快慢指针
int fastindex=0;
int slowindex=0;
while(fastindex<nums.size())
{
if(nums[fastindex]!=val)
{
nums[slowindex++]=nums[fastindex++];
}
else
{
fastindex++;
}
}
return slowindex;
}
};
解释:
定义快慢指针,快指针每次循环递增一次,慢指针当快指针为索引的条件下的值不等于val时才会递增,一快一慢。注意while(fastindex<nums.size())不能写成while(fastindex<=nums.size()-1),这时当输入的数组为空数组时会报错。
for循环实现:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
//定义快慢指针
int fastindex=0;
int slowindex=0;
for(;fastindex<nums.size();fastindex++)
{
if(nums[fastindex]!=val)
{
nums[slowindex++]=nums[fastindex];
}
}
return slowindex;
}
};
复杂度分析:
时间复杂度:O(n)
空间复杂度:O(1)
3.有序数组的平方
题目链接:. - 力扣(LeetCode)
思路:双指针
题解:
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int left=0;
int right=nums.size()-1;
int i=nums.size()-1;
vector<int> result(nums.size(), 0);
while(left<=right)
{
if(pow(nums[left],2)<=pow(nums[right],2))
{
result[i]=pow(nums[right],2);
right--;
}
else
{
result[i]=pow(nums[left],2);
left++;
}
i--;
}
return result;
}
};
解释:
利用双指针的思想,从两头的数字开始比,比出最大的放在新数组最后面,以此类推,注意while循环里面的条件,当left和right相等时,我们还需要对其进行比较,所以应该是left<=right。
复杂度分析:
时间复杂度:O(n)
空间复杂度:O(n)
暴力解法(时间复杂度是 O(n + nlogn)):
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for(int i=0;i<nums.size();i++)
{
nums[i]=pow(nums[i],2);
}
sort(nums.begin(),nums.end());
return nums;
}
};
4.搜索插入位置
题目链接:. - 力扣(LeetCode)
思路:二分法
题解:
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)
{
left=middle+1;
}
else if(nums[middle]>target)
{
right=middle-1;
}
else
{
return middle;
}
}
return left;
}
};
解释:
如果数组中存在value,则按照二分法查找方式去解决;如果不存在,为什么返回的是left?,因为在倒数第二次次循环的时候,假设left=a,则right=a+1,之后middle=a,left=a+1,即返回left。
复杂度分析:
时间复杂度:O(log n)
空间复杂度:O(1)
5.在排序数组中查找元素的第一个和最后一个位置
题目链接:. - 力扣(LeetCode)
思路:二分法
题解:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target)
{
int a=FindLeftBorder(nums,target);
int b=FindRightBorder(nums,target);
if(nums.size()==0)
{
return {-1,-1};
}
else
{
return {a,b};
}
}
private:
int FindLeftBorder(vector<int>& nums, int target)
{
int left=0,right=nums.size()-1;
while(left<=right)
{
int middle=left+(right-left)/2;
if(nums[middle]==target)
{
if(middle==0||nums[middle-1]!=target)
{
return middle;
}
else
{
right=middle-1;
}
}
else if(nums[middle]>target)
{
right=middle-1;
}
else
{
left=middle+1;
}
}
return -1;
}
int FindRightBorder(vector<int>& nums, int target)
{
int left=0,right=nums.size()-1;
while(left<=right)
{
int middle=left+(right-left)/2;
if(nums[middle]==target)
{
if(middle==nums.size()-1||nums[middle+1]!=target)
{
return middle;
}
else
{
left=middle+1;
}
}
else if(nums[middle]>target)
{
right=middle-1;
}
else
{
left=middle+1;
}
}
return -1;
}
};
解释:
首先需要查找左右两边界,比如说左边界,类似于没用重复值的二分法,在nums[middle]==target的条件下我们需要进一步分析,比如说数组为[5,7,7,8,8,10],如果nums[middle-1]!=target即middle前一个的值不是8,则找到的是左边界,否则找到的是第二个8,真正的8在middle的左区间,需要进行right=middle-1。
复杂度分析:
时间复杂度:O(log n)