LeeCode 704 二分查找
二分查找适合顺序数组,且无重复元素
class Solution {
public:
int search(vector<int>& nums, int target) {
int i = 0,j = nums.size()-1;
int mid = 0;
while(i <= j)
{
mid = i + ((j - i) >> 1);//注意运算符的优先级,所以右移要加括号
if (nums[mid] < target)
{
i = mid + 1;
}
else if (nums[mid] > target)
{
j = mid - 1;
}
else
{
return mid;
}
}
return -1;
}
};
插入位置一个头(第一个元素位置)一个尾(最后一个元素的下一个位置)
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int low = 0,high = nums.size() - 1;
while(low <= high)
{
int mid = low + ((high - low) >> 1);
if (nums[mid] < target)
{
low = mid + 1;
}
else if (nums[mid] > target)
{
high = mid - 1;
}
else
{
return mid;
}
}
return low;
}
};
时刻记得,二分查找就是查找某个元素在数组中的下标位置
第一版:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> temp;
int start = -1,end = -1;
//寻找左边界
int low = 0,high = nums.size() - 1;
while(low <= high)
{
int mid = low + ((high - low) >> 1);
if(nums[mid] < target)
{
low = mid + 1;
}
else if(nums[mid] > target)
{
high = mid - 1;
}
else
{
start = mid;
high = mid - 1;
}
}
//寻找右边界
low = 0,high = nums.size() - 1;
while(low <= high)
{
//注意右边界是得向上取整
int mid = low + ((high - low + 1) >> 1);
if(nums[mid] < target)
{
low = mid + 1;
}
else if(nums[mid] > target)
{
high = mid - 1;
}
else
{
end = mid;
low = mid + 1;
}
}
temp.push_back(start);
temp.push_back(end);
return temp;
}
};
第二版:针对第一版作稍许优化
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int start = -1,end = -1;
//寻找左边界
int low = 0,high = nums.size() - 1;
int mid = 0;
while(low <= high)
{
mid = low + ((high - low) >> 1);
if(nums[mid] < target)
{
low = mid + 1;
}
else if(nums[mid] > target)
{
high = mid - 1;
}
else
{
start = mid;
high = mid - 1;
}
}
if (start == -1) return {-1,-1};
//寻找右边界
low = start,high = nums.size() - 1;
while(low <= high)
{
//注意右边界是得向上取整
mid = low + ((high - low + 1) >> 1);
if(nums[mid] < target)
{
low = mid + 1;
}
else if(nums[mid] > target)
{
high = mid - 1;
}
else
{
end = mid;
low = mid + 1;
}
}
return {start,end};
}
};
class Solution {
public:
int mySqrt(int x) {
int low = 0,high = x;
int mid = 0;
if (x==1) return x;
while(low <= high)
{
mid = low + ((high - low)>>1);
if (!mid) return mid;//要考虑mid=0的情况
if (x/mid == mid)
{
return mid;
}
else if (mid > x/mid)
{
high = mid-1;
}
else
{
low = mid+1;
}
}
return high;
}
};
还有一种理解:思路差不多,也更好理解,区间内找,相等就跳出循环,最后一定是m值往min值去逼近,直到相等跳出
int mySqrt(int x)
{
if(x == 1)
return 1;
int min = 0;
int max = x;
while(max-min>1)
{
int m = (max+min)/2;
if(x/m<m)
max = m;
else
min = m;
}
return min;
}
一定要注意while判断条件相等的时候,和不相等的时候的含义
class Solution {
public:
bool isPerfectSquare(int num) {
int num1 = 1;
while(num > 0)
{
num -= num1;
num1 += 2;
}
return num == 0;
}
};
原理:1+3+5+7+9+…+(2n-1)=n^2,即完全平方数肯定是前n个连续奇数的和
二分法:
class Solution {
public:
bool isPerfectSquare(int num) {
if (num == 1) return true;
int low = 1,high = num;
while(high - low > 1)//防止死循环,即low=mid,high=mid+1的情况会死循环,因为int是向下取整
{
int mid = low + ((high-low)>>1);
if(num/mid == mid){
if(num % mid == 0) return true;//eg:num=5的时候不加判断,会返回true
low = mid;//同理防止死循环
}else if(num/mid > mid)
{
low = mid;
}else
{
high = mid;
}
}
return false;
}
};
class Solution {
public:
bool isPerfectSquare(int num) {
int low = 1,high = num;
while(low <= high)
{
int mid = low + ((high-low)>>1);
if(num/mid == mid){
if(num % mid == 0) return true;
low = mid + 1;
}else if(num/mid > mid)
{
low = mid + 1;
}else
{
high = mid -1;
}
}
return false;
}
};
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int i=0,j=0;
while(j<nums.size())
{
if(nums[j] != val)//等于val全部往后丢,题目没有要求顺序
{
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
++i;
}
++j;
}
return i;//i前面的全是!=val的
}
};
//精简版
int removeElement(int* nums, int numsSize, int val){
int k = 0;
for(int i=0;i<numsSize;i++)
{
if(nums[i] != val)
nums[k++] = nums[i];
}
return k;
}
双向奔赴:
/**
* 相向双指针方法,基于元素顺序可以改变的题目描述改变了元素相对位置,确保了移动最少元素
* 时间复杂度: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一定指向了最终数组末尾的下一个元素
}
};
int removeDuplicates(vector<int>& nums) {
int i=0,j=0;
while(j<nums.size())
{
if(i<j&&nums[j]!=nums[i])//加个i<j保险一点防止越界,但实际上肯定不会越界,初始j就先跳出了加1了
{
nums[++i]=nums[j];
}
++j;
}
return i+1;
}
//两者本质上都是交换,理解角度不同
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int k=0;
for(int i=0;i<nums.size();++i)
{
if(nums[i])
{
swap(nums[i],nums[k++]);
}
}
}
};
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int k=0;
for(int i=0;i<nums.size();++i)
{
if(nums[i])
{
nums[k++] = nums[i];
if (k-1<i) nums[i] = 0;//k-1<i的含义是当nums[k-1],即前面无重复的有序数组中的最后一个元素,与遍历的元素不相同时,才赋0,相同不必赋值
}
}
}
};
class Solution {
public:
bool backspaceCompare(string s, string t) {
return deal(s)==deal(t);
}
private:
string deal(string& a)
{
int i=0,j=0;
while(j<a.size())
{
if(a[j] != '#')
{
a[i++] = a[j];
}else
{
if(i>0) --i;
}
++j;
}
return a.substr(0,i);
}
};