代码随想录算法训练营第一天 | 704. Binary Search & 27. Remove Element
07/03/2024补充:第一轮打卡完全没跟上节奏,光荣加入新的一期打卡,重新开始
704. Binary Search
题目链接:704. Binary Search
题目描述:
Given an array of integers nums which is sorted in ascending order, and an integer target, write a function to search target in nums. If target exists, then return its index. Otherwise, return -1.
You must write an algorithm with O(log n) runtime complexity.
文章讲解:代码随想录:二分查找
视频讲解:手撕二分查找
读完题思路:
因为这道题真的已经刷过很多遍了,可以说是信手拈来了。真的只要记住卡尔学长说的循环不变量,就能轻松的写出来左闭右开[1,1)和左闭右闭[1,1]的两种代码。
左闭右闭写法:
class Solution:
def search(self, nums: List[int], target: int) -> int:
#左闭右闭
left, right = 0, len(nums)-1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return mid
if nums[mid] > target:
right = mid - 1
else:
left = mid + 1
return -1
左闭右开写法:
class Solution:
def search(self, nums: List[int], target: int) -> int:
#左闭右开
left, right = 0, len(nums)
while left < right:
mid = (left + right) // 2
if nums[mid] == target:
return mid
if nums[mid] > target:
right = mid
else:
left = mid + 1
return -1
最近也在练习C++,所以这次打卡正好加入C++的版本:
左闭右闭:
class Solution {
public:
// 左闭右闭
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = left + ((right - left) / 2); //防止溢出
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else {
return mid;
}
}
return -1;
}
};
左闭右开:
class Solution {
public:
// 左闭右开
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size();
while (left < right) {
int mid = left + ((right - left) / 2);
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid;
} else {
return mid;
}
}
return -1;
}
};
之前没注意到的是防止溢出的mid计算!太细了5555
35. Search Insert Position
第二次刷加入的补充题
题目链接:35. Search Insert Position
题目描述:
Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You must write an algorithm with O(log n) runtime complexity.
文章讲解:代码随想录:35.搜索插入位置
读完题思路:刚读完觉得好简单,直接二分查找只要改一下最后的return就好,但最终的return一下子突然又想不明白了。看了讲解后才意识到还是要继续从循环不变量去考虑。
这题就只用了C++写了一下。(下面copy的代码随想录的🐎)
暴力解法:
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
for (int i = 0; i < nums.size(); i++) {
// 分别处理如下三种情况
// 目标值在数组所有元素之前
// 目标值等于数组中某一个元素
// 目标值插入数组中的位置
if (nums[i] >= target) { // 一旦发现大于或者等于target的num[i],那么i就是我们要的结果
return i;
}
}
// 目标值在数组所有元素之后的情况
return nums.size(); // 如果target是最大的,或者 nums为空,则返回nums的长度
}
};
二分法(左闭右闭):
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
int left = 0;
int right = n - 1; // 定义target在左闭右闭的区间里,[left, right]
while (left <= right) { // 当left==right,区间[left, right]依然有效
int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
if (nums[middle] > target) {
right = middle - 1; // target 在左区间,所以[left, middle - 1]
} else if (nums[middle] < target) {
left = middle + 1; // target 在右区间,所以[middle + 1, right]
} else { // nums[middle] == target
return middle;
}
}
// 分别处理如下四种情况
// 目标值在数组所有元素之前 [0, -1]
// 目标值等于数组中某一个元素 return middle;
// 目标值插入数组中的位置 [left, right],return right + 1
// 目标值在数组所有元素之后的情况 [left, right], 因为是右闭区间,所以 return right + 1
return right + 1;
}
};
34. Find First and Last Position of Element in Sorted Array
题目链接:34. Find First and Last Position of Element in Sorted Array
文章讲解:代码随想录:34. 在排序数组中查找元素的第一个和最后一个位置
这题花了我好久,有点写不动讲解了。。。主要follow这个文章讲解
27. Remove Element
题目链接:27. Remove Element
题目描述:
Given an integer array nums and an integer val, remove all occurrences of val in nums in-place. The order of the elements may be changed. Then return the number of elements in nums which are not equal to val.
Consider the number of elements in nums which are not equal to val be k, to get accepted, you need to do the following things:
- Change the array nums such that the first k elements of nums contain the elements which are not equal to val. The remaining elements of nums are not important as well as the size of nums.
- Return k.
文章讲解:代码随想录:移除元素
视频讲解:数组中移除元素并不容易!
读完题思路:
这道题之前也是刷到过的,印象里是要用双指针。但令我惊讶的是一开始写暴力解法居然写不出来,知道大概思路但是implement有问题,还研究了半天。。。
暴力解法:
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
# 暴力解法
start, end = 0, len(nums)
while start < end:
if nums[start] == val:
for j in range(start+1, len(nums)):
nums[j-1] = nums[j]
start -= 1
end -= 1
start += 1
return end
快慢指针解法:
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
# 快慢指针
slow, fast = 0, 0
while fast < len(nums):
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
fast += 1
return slow
这题新用C++又写了一遍:
class Solution {
// Time Complexity: O(n)
// Space Complexity: O(1)
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0;
int fast = 0;
for (fast; fast < nums.size(); fast++) {
if (nums[fast] != val) {
nums[slow] = nums[fast];
slow ++;
}
}
return slow;
}
};
今日收获与总结
Day1 耗时大概1.5h,但是没有做补充衍生的题,只做了要求的两道,再加上都是Easy之前也刷过,所以今天耗时比较短。最近学校里事情比较多,希望之后也能跟上进度继续打卡下去。
今天算是第一次写博客,还是挺好玩的,希望也能养成这个习惯。
感觉二分查找已经完全没有问题了,双指针的运用可能还是需要加强,判断什么时候运用快慢指针,什么时候用左右指针。
Updated:
第二次刷这一课,做了补充题34&35。