LeetCode 704 二分查找
题目链接:704. 二分查找
个人做题感想:拿到题目之后,自己独立写完并且ac了,自己写的具体代码
class Solution {
public:
int search(vector<int>& nums, int target) {
int left=0, right=nums.size()-1;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==target){
return mid;
}else if(nums[mid]>target){
right=mid-1;
}else{
left=mid+1;
}
}
return -1;
}
};
看完卡哥视频和代码随想录书相应部分后,才知道原来二分查找还有那么多细节,突然感觉自己ac的代码很多细节都没有注意,有可能这次写对下次就写不对,或者自己没有遵循一定规则去写错误了然后调试浪费大量时间。
具体细节部分:① while(left<right)还是while(left<=right) ② right=middle还是right=middle-1
进行上述细节的书写时候,就要知道循环不变量的规则,这里的循环不变量就是区间的定义,在while循环中,每一次边界的处理都要根据区间的定义来操作,区间大小和个数不能多也不能少。
二分法中区间的定义有两种,一种是左闭右闭即[left, right],另一种是左闭右开[left, right),才发现原来自己单独ac的代码是第一种写法,自己也比较倾向于第一种写法
下面是两种写法具体代码
//左闭右闭区间写法,始终保持这个循环不变量,不能多,也不能少
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;
}
};
LeetCode 27 移除元素
题目链接:27. 移除元素
个人做题感想1:拿到题目之后,由于自己以前接触过双指针的题目和看过这道题目,所以第一想法就想到了双指针做法,且自己独立写完并且ac了,不过相对卡哥给的代码,自己写的代码很low,而且感觉思路也不是很清晰,自己写的具体代码如下:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int n=nums.size();
int slow=0,fast=0;
while(fast<n){
if(nums[fast]==val){
fast++;
continue;
}else{
nums[slow++]=nums[fast++];
}
}
return slow;
}
};
看完卡哥视频和代码随想录书相应部分后,自己的思路突然更加清晰了,一定要注意快慢指针的定义。特别注意:双指针法(快慢指针)在这个题目中的定义如下:快指针:寻找新数组的元素,也就是不含目标元素的数组的元素 慢指针:指向和更新数组下标的位置,注意上述指针都是在原数组上操作的
具体代码如下:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowIndex=0;
for(int fastIndex=0;fastIndex<nums.size();fastIndex++){
if(nums[fastIndex]!=val){
nums[slowIndex++]=nums[fastIndex];
}
}
return slowIndex;
}
};
个人做题感想2:由于自己一下子想到了快慢指针写法,就没有想暴力解法了,这不是一个好习惯,很多题目做不出的时候用暴力至少能够做出来,然后再在暴力法的基础上进行优化,看完卡哥暴力解法思路以及代码实现后,代码实现很值得学习,自己没写出来暴力解法代码:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int size=nums.size();
for(int i=0;i<size;i++){
if(nums[i]==val){
for(int j=i;j<size-1;j++){
nums[j]=nums[j+1];
}
i--;
size--;
}
}
return size;
}
};
个人做题感想3:由于本题目基于元素顺序可以改变的这一前提条件,最后卡哥给出了相向双指针法,代码写法特别是那几个while的判断以及if的判断写法很值得推敲和学习,有可能也会用在其它题目中:
/**
* 相向双指针方法,基于元素顺序可以改变的题目描述改变了元素相对位置,确保了移动最少元素
* 时间复杂度:O(n)
* 空间复杂度:O(1)
*/
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int leftIndex = 0;
int rightIndex = nums.size() - 1;
while (leftIndex <= rightIndex) {
// 找左边等于val的元素
while (leftIndex <= rightIndex && nums[leftIndex] != val){
++leftIndex;
}
// 找右边不等于val的元素
while (leftIndex <= rightIndex && nums[rightIndex] == val) {
-- rightIndex;
}
// 将右边不等于val的元素覆盖左边等于val的元素
if (leftIndex < rightIndex) {
nums[leftIndex++] = nums[rightIndex--];
}
}
return leftIndex; // leftIndex一定指向了最终数组末尾的下一个元素
}
};
今天按照步骤做下来包括写博客一共花了三个小时左右(题目比较简单且熟悉所以很快就解决了),由于第一次在csdn种用markdown写博客,所以这篇博客写了比较长时间,不过是自己空闲时候写的。
贵在坚持,加油,共勉