我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第4篇文章,点击查看活动详情
一、前言
每天都有刷算法但是确实缺少一个陪跑,借着这次卡哥的训练营来整体的完成一次算法学习和一刷,说起来也挺惭愧的,进卡哥的知识星球也半年多了,还没说过话。。
闲话少说, 今天是算法训练营的第一天,目标是【数组】模块 LeetCode的 704,二分查找和 27. 移除元素
二、LeetCode 704. 二分查找
题目描述
解题思路
- 首先题中有说这是一个有序且升序的数组,那么肯定是二分法了
- 直接设置一个左右下标 left和 right,把控好有左右边界来遍历获取中间值就可以了
- 这里需要注意的是左右边界的判定
- 同时,因为是有序的,所以当数组最小值 nums[0]都小于 target或者数组最大值 nums[nums.length - 1] 大于 target那么证明这个数组中不可能存在 target
代码展示
public int search(int[] nums, int target) {
// 因为 nums是有序的, 那最小的如果大于 target或者最大的小于 target,则代表数组中不可能存在大小 target的元素
if (nums[0] > target || nums[nums.length - 1] < target){
return -1;
}
int left = 0, right = nums.length - 1;
// 因为是二分法,所以当左右双指针相等的时候代表数组遍历完成
while(left <= right){
// 获取当前左右边界的中间下标
int temp = left + (right - left) / 2;
if (nums[temp] > target){
// 如果中间的树都大于 target,那么右边界向左移动
right = temp - 1;
}else if (nums[temp] < target){
// 如果中甲的树小于 target, 那么左边界移动
left = temp + 1;
}else{
return temp;
}
}
return -1;
}
提交结果
总结
不得不说,很多东西不去练习真的会忘记,万万没想到这道题在之前我刷过四遍,虽然这次重做本题有些游刃有余,但是在细节处理上还是有一些小瑕疵,后续代码通过看代码随想录进行了相应的改进
LeetCode 27. 移除元素
题目描述
思路分析
- 首先这道题需要注意的是既要修改数组,还要记录数组中元素值非 val的个数
这道题我们还是可以使用双指针来做, 一个指针去遍历数组, 另外一个指针去修改数组的同时记录长度,具体可看代码展示
代码展示
public int removeElement(int[] nums, int val) {
// left一直向前走, right记录长度
int left = 0, right = 0;
for (; left < nums.length; left++) {
// 如果当前元素为 val则 left继续向前走
if (nums[left] != val){
// 如果当前元素不为 val则修改,right++
nums[right++] = nums[left];
}
}
return right;
}
提交结果
补充
在【代码随想录】网站中,本题还给了另外一种解法,相向双指针法,但是相对来讲更繁琐且不易理解, 具体如下
LeetCode 34. 在排序数组中查找元素的第一个和最后一个位置
题目描述
思路分析
- 老规矩,认真审题
- 这道题题目写的是非递减数组
- 目标值的开始结束位置
- 时间复杂度为 0(log n)
三种情况:
- 不存在
- 存在两个 val
- 只有一个 val
依旧是双指针来做,不过这次是用两个双指针
代码展示
class Solution {
public int[] searchRange(int[] nums, int target) {
int left = 0, right = nums.length - 1;
// 因为是二分法,所以当左右双指针相等的时候代表数组遍历完成
while(left <= right){
// 获取当前左右边界的中间下标
int temp = left + (right - left) / 2;
if (nums[temp] > target){
// 如果中间的树都大于 target,那么右边界向左移动
right = temp - 1;
}else if (nums[temp] < target){
// 如果中甲的树小于 target, 那么左边界移动
left = temp + 1;
}else{
left = temp;
right = temp;
while(left > 0 && nums[left - 1 ] == target){
left--;
}
while(right <= nums.length - 2 && nums[right + 1] == target){
right++;
}
return new int[]{left, right};
}
}
return new int[]{-1,-1};
}
}
结果提交
总结
笑死了,因为偷懒直接 copy的 704的代码,然后缝缝补补,出了好几个 bug,是我自信了,一个小扒菜的自不量力, 但是好在结果是好的
在评论区 Carl哥给出了另外一种解法,使用两次二分法查找,分别去查找左边界和右边界,感兴趣的可以试一下
LeetCode 35. 搜索插入位置
题目描述
思路分析
- 依旧是二分法的思路
- 需要注意的是返回值要是left, 因为当前left > right了证明若存在 target元素就应该在当前的 left下标位置
代码展示
class Solution {
public int searchInsert(int[] nums, int target) {
if (nums[0] > target ){
return 0;
}
if (nums[nums.length - 1] < target){
return nums.length;
}
int left = 0, right = nums.length - 1, temp = 0;
// 因为是二分法,所以当左右双指针相等的时候代表数组遍历完成
while(left <= right){
// 获取当前左右边界的中间下标
temp = left + (right - left) / 2;
if (nums[temp] > target){
// 如果中间的树都大于 target,那么右边界向左移动
right = temp - 1;
}else if (nums[temp] < target){
// 如果中甲的树小于 target, 那么左边界移动
left = temp + 1;
}else{
return temp;
}
}
return left ;
}
}
提交结果
总结
万万没想到,这道题我竟然错了这么多次,我真的有这么菜的吗。。。
本文内容到此结束了
如有收获欢迎点赞👍收藏💖关注✔️,您的鼓励是我最大的动力。
如有错误❌疑问💬欢迎各位大佬指出。
我是 宁轩 , 我们下次再见