代码随想录算法训练营第一天 | Leetcode 704、Leetcode35、Leetcode34、Leetcode27
打卡
Leetcode 704 二分查找
题目链接
简单的二分查找,一共两种写法:
左闭右闭=>更新左区间right=left-1;更新右区间left=right-1;
左闭右开=>更新左区间right=mid;更新右区间left=mid+1;
【mid已经被查询,后续区间不应该包含mid】
解答
//左闭右闭版本
class Solution {
public int search(int[] nums, int target) {
if(target < nums[0] || target > nums[nums.length -1]){
return -1;
}
int left = 0;
int right = nums.length - 1;
while (left <= right){
int mid = left + ((right - left)>>1);
if(nums[mid] == target){
return mid;
}
else if(nums[mid] < target)
left = mid + 1;
else if(nums[mid] > target)
right = mid - 1;
}
return -1;
}
}
//runtime:0 ms
//memory:44.7 MB
//左闭右开版本
class Solution {
public int search(int[] nums, int target) {
//左闭右开版本
int left = 0, right = nums.length;
while(left < right){
int mid = left + ((right-left)>>1);
if(nums[mid] == target)
return mid;
else if(nums[mid] < target)
left = mid + 1;
else if(nums[mid] > target)
right = mid;
}
return -1;
}
}
//runtime:0 ms
//memory:44.8 MB
Leetcode 35 搜索插入位置
题目链接
虽然题目中说插入但是实际只要求返回插入的位置,所以本质依然是搜索,可以采用和上题一样的二分查找求解
不过本题由于思维定势,反而忘了最简单的暴力法,实在不该
解答
//暴力法,也挺简单的
class Solution {
public int searchInsert(int[] nums, int target) {
for (int i = 0; i < nums.length; i++){
if (nums[i] >= target)
return i;
}
//目标值在数组所有元素之后的情况
return nums.length;
}
}
Leetcode 34 在排序数组中查找元素的第一个和最后一个位置
题目链接
本题一开始试图一次性得到左右边界,反复受挫后受代码随想录启发分开求左右边界并对可能出现的三种情况进行处理
不得不说,采用左闭右闭的二分真的很巧妙,在left == right时找到边界又因为还要进行一次循环导致左右边界各自又朝两边移了1位,使得rightBorder-leftBorder>=2,与情况三区分开来
解答
class Solution {
public int[] searchRange(int[] nums, int target) {
int leftBorder = getLeftRange(nums, target);
int rightBorder = getRightRange(nums, target);
// 在范围的两边
if (leftBorder == -2||rightBorder == -2)
return new int[]{-1,-1};
// 在范围内且在数组内,由于while条件的设置导致差值>=2
if (rightBorder - leftBorder > 1)
return new int[]{leftBorder+1,rightBorder-1};
// 在范围内但是不在数组内
return new int[]{-1,-1};
}
int getRightRange(int nums[], int target){
int left = 0;
int right = nums.length-1;
int rightBorder = -2;
while (left <= right){
int mid = left + ((right - left) >> 1);
if (nums[mid] > target)
right = mid -1;
else {
// 范围向右缩减时找到右边界,该过程是left向右边界靠近
left = mid + 1;
// nums[mid] == target更新left后还要进行一次循环导致rightBorder+1
rightBorder = left;
}
}
return rightBorder;
}
int getLeftRange(int nums[], int target){
int left = 0;
int right = nums.length-1;
int leftBorder = -2;
while (left <= right){
int mid = left + ((right - left)>>1);
if (nums[mid] < target)
left = mid + 1;
else {
// 范围向右缩减时找到左边界,该过程是right向左边界靠近
right = mid - 1;
// nums[mid] == target更新right后还要进行一次循环导致leftBorder-1
leftBorder = right;
}
}
return leftBorder;
}
}
LeetCode 27 移除元素
本题我采用双指针(相向指针),这种做法避免了开销很大的删除操作,性能上比起暴力法有不小提升。当出现==val的值后用数组最后面的元素替换原先元素且当当前位置元素非val后指针继续移动
解答
public class Solution {
public int removeElement(int[] nums, int val) {
//相向双指针法
int i = 0;
int j = nums.length-1;
while (i <= j){
if (nums[i] == val){
nums[i] = nums[j];
nums[j] = 0;
j--;
}
else i++;
}
return i;
}
}