Leetcode-704 二分查找
一开始的思路是在数组的最左边和最右边做一个标记然后进行一个while循环,循环的终止条件是左指针等于右指针,循环体内部是先取中间元素与目标元素作比较若mid>=k则将右指针移动到mid处反之则将左指针移动到mid处。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,k;
cout << "请输入元素个数: " << endl;
cin >> n;
vector<int> a(n, 0);
for(int i = 0; i < n; i++){
cout << "请输入第" << i + 1 << "项元素: " << endl;
cin >> a[i];
}
cout << "请输入要搜索的值: " << endl;
cin >> k;
int l = 0,r = n - 1;
while(l != r){
int mid = (l + r) / 2;
if(a[mid] >= k){
r = mid;
}else{
l = mid;
}
}
cout << "位置为:" << l;
return 0;
}
但写完后发现代码进入了死循环,然后发现是循环终止条件的问题,思考了一下原来的代码在大于等于的判定条件下如果mid == k不能立即做出反应,所以可以在循环体内部加入一个判定条件,并更改循环的终止条件,这时候想起了刚学数据结构时就是因为大意也是出现这个错误哈哈,将循环的终止条件改为l <= r,只要左指针一直在有指针的左边循环就可以一直进行一旦越过右指针便停止循环。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,k;
cout << "请输入元素个数: " << endl;
cin >> n;
vector<int> a(n, 0);
for(int i = 0; i < n; i++){
cout << "请输入第" << i + 1 << "项元素: " << endl;
cin >> a[i];
}
cout << "请输入要搜索的值: " << endl;
cin >> k;
int l = 0,r = n - 1;
while(l <= r){
int mid = (l + r) / 2;
if(a[mid] == k){
cout << "位置为: " << mid <<endl;
return 0;
}else if(a[mid] > k){
r = mid - 1;
}else if(a[mid] < k){
l = mid + 1;
}
}
cout << "未找到目标元素: " << endl;;
return 0;
}
但做到这里我发现该程序只能找到数组内的一个目标元素并不能找到所有的,接着我的思路是从找到的第一个元素处开始向左向右进行搜索,然后到这里有一个错误导致搜索的循环进入了死循环就是忘记在搜索结束后未即使退出循环:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,k;
cout << "请输入元素个数: " << endl;
cin >> n;
vector<int> a(n, 0);
for(int i = 0; i < n; i++){
cout << "请输入第" << i + 1 << "项元素: " << endl;
cin >> a[i];
}
cout << "请输入要搜索的值: " << endl;
cin >> k;
int l = 0,r = n - 1;
while(l <= r){
int mid = (l + r) / 2;
if(a[mid] == k){
cout << "位置为: " << mid <<endl;
int left = mid - 1;
while(left >= 0 && a[left] == k){
cout << "位置为: " << left << endl;
left--;
}
int right = mid + 1;
while(right < n && a[right] == k){
cout << "位置为: " << right << endl;
right++;
}
return 0;
}else if(a[mid] > k){
r = mid - 1;
}else if(a[mid] < k){
l = mid + 1;
}
}
cout << "未找到目标元素: " << endl;;
return 0;
}
这里考虑时间复杂度的优化的话可以在找到第一个元素后继续使用二分查找去寻找其他的目标元素而不是用线性查找,此处的时间复杂度为o(logn * n)。leetcod原题代码:
class Solution {
public:
int search(vector<int>& nums, int target) {
int l = 0, r = nums.size() - 1;
while(l <= r){
int mid = (l + r) / 2;
if(nums[mid] == target){
return mid;
}else if(nums[mid] > target){
r = mid - 1;
}else if(nums[mid] < target){
l = mid + 1;
}
}
return -1;
}
};
Leetcode - 35 搜索插入位置
对于这道题的思路与上题大差不差,但多了一个要求就是求插入位置,这里困扰我的一点是最后返回插入位置是选左指针还是右指针,由于左指针一直是mid+1而右指针一直是mid-1所以第一次到达目标位置的应该是左指针而不是右指针。
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int l = 0, r = nums.size() - 1;
while(l <= r){
int mid = (l + r) / 2;
if(nums[mid] == target){
return mid;
}else if(nums[mid] > target){
r = mid - 1;
}else{
l = mid + 1;
}
}
return l;
}
};
Leetcode-34 在排序数组中查找元素的第一个和最后一个位置
这道题就是在第一个基础的去寻找数组中所有目标元素的基础上再将位置输出,这道题迷惑住我的一个地方是将位置输出时l和r的值,因为是在找到第一个不等于target的值的时候仅需递减或递增了一次所一需要对指针进行加一或减一。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int l = 0,r = nums.size() - 1;
vector<int> a(2,-1);
while(l <= r){
int mid = (l + r) / 2;
if(nums[mid] == target){
int right = mid, left = mid;
while(right < nums.size() && nums[right] == target){
right++;
}
while(left >= 0 && nums[left] == target){
left--;
}
a[0] = left + 1;
a[1] = right - 1;
return a;
}else if(nums[mid] > target){
r = mid - 1;
}else{
l = mid + 1;
}
}
return a;
}
};
Leetcode - 27 移除元素
这道题一开始看以为是用二分找到目标元素然后将其与元素全都删除掉后来发现所给数组并不是有序的所以卡壳了,然后看到可以用双指针法进行解题就从这个方向进行思考但是由于是否输出的数组再取出目标元素后剩下的元素的顺序是否和原数组一致这块又不会了,但是把我原先写了一半思路的代码扔给gpt补全完善思路提交竟然通过了,这里的思路就是主循环与二分法一致都是保持左指针的位置小于等于右指针,左指针向右移动,遇到目标元素时,右指针开始移动寻找到第一个不为目标元素的数值将两者替换,这样目标元素就全部被抛到了数组的末尾,只不过前面的数组元素就不再是遵循原数组的顺序了,下面是第一次完成的代码:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
if (nums[left] == val) {
while (right >= 0 && nums[right] == val) {
right--;
}
if (right >= 0) {
swap(nums[left], nums[right]);
right--;
}
}
left++;
}
return left;
}
};
但并未成功通过,报错样例是[ val ]类型,上面的代码在运行此样例时返回的是【val】并未返回空列表,对左右指针相遇时的情况并未做处理,左右指针相遇就直接返回右指针,因为此时右指针的右侧全为目标元素。
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int l = 0,r = nums.size() - 1;
while(l <= r){
if(nums[l] == val){
while(nums[r] == val && r > l){
r--;
}
if(l < r){
swap(nums[l], nums[r]);
r--;
}else{
return r;
}
}
l++;
}
return l;
}
};
这块代码写起来还是有点吃力思路还是不太清晰需要再多次的琢磨琢磨。今天的算法训练营就到这里结束了,期待明天的新章节!
------- 2-21 21.25 magixx