二分查找
当我们听见这个名字第一想法 二分 第二想法 查找 再结合一下这个题的特别 这个在一个升序的数组中 我们来查找 一个元素
既然这个是一个升序数组那他就一定有什么特别之处 最左端的数最小 最右端的数最大那我们如果要想查找一个数我们可以先看看这个数组中间的哪个数的大小 近而我们可以进行比对 来查找
这个时候我们就可以利用到 二分查找
但是有一个我们需要注意就是这个区间 我们去要坚持循环不变量 这个请仔细代码
无论我们写哪一个代码我们都需要先理清自己的思路在动笔
对于这个二分查找 左闭右闭 第一步我们先要整好两个变量 分别是左和右得坐标 然后开始写循环条件 while(left<=right)
第二部 我们要来找middle 然后开始进行查找过程
接下来是左闭右闭的代码
#include<iostream>
using namespace std;
int fin_d(int arr[],int target)
{
//int n = sizeof(arr) / sizeof(arr[0]);
//这个地方这么写是错误的 因为arr实质是一个指针 所以如果要是想知道这个n具体是多少我们可以在主函数中进行sizeof计算然后给子函数
int left = 0;
int n = 7;
int right = n - 1;
while (left <= right)
{
int middle = left + ((right - left) / 2);
if (arr[middle] < target)
{
left = middle + 1;
}
else if (arr[middle] > target)
{
right = middle - 1;
}
else if (arr[middle] == target)
{
return middle;
}
}
return -1;
}
int main()
{
int arr[10] = { 0 };
for (int i = 0; i < 7; i++)
{
int num;
cin >> num;
arr[i] = num;
}
int target;
cin >> target;
cout << fin_d(arr, target);
}
接下来讲解的是左闭右开
这左闭右开不同的原因在于这个我们要保证这个左和右不会重合,所以我们更要坚持循环不变量
#include<iostream>
using namespace std;
int fin_d(int arr[],int n,int target)
{
int left = 0;
int right = n;
while (left < right)
{
int middle = left + ((right - left) / 2);
if (arr[middle] > target)
{
right = middle;
}
else if (arr[middle] < target)
{
left = middle + 1;
}
else if (arr[middle] == target)
{
return middle;
}
}
return -1;
}
int main()
{
int arr[10];
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
int num;
cin >> num;
arr[i] = num;
}
int target;
cin >> target;
cout<<fin_d(arr, n, target);
}
移除元素
这道移除元素:不仅需要把一个数组中的某个元素删除还需要来返回这个后来这个数组中元素的个数
数组是一个连续存储的空间,所以对于他的删除是覆盖。
面对这道题第一想法就是暴力算法来解决,代码如下
#include<iostream>
using namespace std;
//int dele_sha(int arr[], int target,int n)
//{
// int size = 0;
// for (int i = 0; i < n; i++)
// {
// if (arr[i] != target)
// {
// size++;
// }
// }
// return size;
//}
//以上这个是我单纯只是为了如果删除元素就返回数组的大小
int fanshu(int arr[], int target, int n)
{
for (int i = 0; i < n; i++)
{
if (arr[i] == target)
{
for (int j=i+1;j<n;j++)
{
arr[j - 1] = arr[j];
}
i--;//这一步一定要写
//关于这个一会会画图来解释
n--;
}
}
return n;
}
int main()
{
int arr[10];
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
int num;
cin >> num;
arr[i] = num;
}
int target;
cin >> target;
//dele_sha(arr, target, n);
cout<<fanshu(arr, target, n);
}
以上这个属于暴力算法相比之下 时间复杂度高 所以我们将利用双指针的方法!!!
这个所谓的快慢双指针其实跟那个我上面
int dele_sha(int arr[], int target,int n)
//{
// int size = 0;
// for (int i = 0; i < n; i++)
// {
// if (arr[i] != target)
// {
// size++;
// }
// }
// return size;
//}
这个函数的意义很像,这个函数就是说如果这个数不是这个我想删除的元素,那么就进行加加。
所以双指针的代码也是这个含义,只不过这个快慢双指针,对于快指针相当于是来找不等于删除的元素,对于慢的指针相当于是来记录这个新的元素的下标,其实这么间接来看真的很像上面那个函数中的size,感觉他们本质上起的作用是一样的。
快慢双指针的代码如下
#include<iostream>
using namespace std;
int fin_d(int arr[], int n, int target)
{
int slow = 0;
int fast = 0;
for (int fast = 0; fast < n; fast++)
{
if (arr[fast] != target)
{
arr[slow++] = arr[fast];
}
}
return slow;
}
int main()
{
int arr[10];
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
int num;
cin >> num;
arr[i] = num;
}
int target;
cin >> target;
cout << fin_d(arr, n, target);
}
还有一个是双向指针 所谓双向指针就是指一个是开头一个是末尾,这个双向指针我们要利用的就跟我们上面那个暴力算法中的有一个地方很像,在于覆盖,这个也就是利用了覆盖!!!(这个双向指针的代码我实在是不太想写,要是大家都很想看的话,就在评论区给我留个言吧!)