代码随想录算法训练营第一天 | 704.二分查找、35.搜索插入位置、34.在排序数组中查找元素的第一个和最后一个位置

文章讲述了作者在解决LeetCode中的二分查找相关题目时,逐步改进代码以解决数组查找、插入位置、搜索范围等问题,包括优化时间复杂度和处理边界情况的过程。
摘要由CSDN通过智能技术生成

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

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值