题目链接:704.二分查找
给定一个n元素升序的整形数组nums和一个目标值target,写一个函数搜索nums中的target,如果目标值存在返回下标,否则返回-1。
二分查找共有两种实现方式,即“左闭右闭”和“左闭右开”,区间不同,函数实现的逻辑不同,下面给出在两种区间上基于C和C++的实现:
左闭右闭(C):
int search(int* nums, int numsSize, int target){
int left = 0; //左边界
int right = numsSize - 1; //右边界
int middle;
while(left <= right){ //定义[left,right],左闭右闭区间
middle = left + ((right - left) / 2); //防止right+left泄露
if(nums[middle] > target){ //target在[left, middle-1]区间
right = middle - 1;
}else if(nums[middle] < target){ //target在[middle+1,right]区间
left = middle + 1;
}else{ // nums[middle] == target
return middle; //找到目标值,返回下标
}
}
return -1; // 未找到目标值
}
左闭右开(C):
int search(int* nums, int numsSize, int target){
int left = 0; //左边界
int right = numsSize; //右边界
int middle;
while(left < right){ //定义[left,right),左闭右开区间
middle = left + ((right - left) / 2);
if(nums[middle] > target){ //target在[left, middle)区间
right = middle;
}else if(nums[middle] < target){ //target在[middle+1,right)区间
left = middle + 1;
}else{ // nums[middle] == target
return middle; //找到目标值,返回下标
}
}
return -1; // 未找到目标值
}
在某些情况下,“左闭右开”会多跑一轮循环,在时间成本上高于“左闭右闭”,个人感觉“左闭右闭”也更符合严谨的编程思维,下面是基于C++的实现。
左闭右闭(C++):
class Solution {
public:
int search(vector& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while(left <= right){
int middle = left + ((right - left) >> 1);
if(nums[middle] > target){
right = middle - 1;
}else if(nums[middle] < target){
left = middle + 1;
}else{
return middle;
}
}
return -1;
}
};
左闭右开(C++):
class Solution {
public:
int search(vector& nums, int target) {
int left = 0;
int right = nums.size();
while(left < right){
int middle = left + ((right - left) >> 1);
if(nums[middle] > target){
right = middle;
}else if(nums[middle] < target){
left = middle + 1;
}else{
return middle;
}
}
return -1;
}
};
本人初学C++,如有问题,恳请指正,不胜感激。
题目链接:27.移除元素
给你一个数组nums和一个值val,你需要原地移除所有数值等于val的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用O(1)额外空间并原地修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
要求原地执行修改,不允许定义额外的数组,有两种解法,“暴力解法”和“双指针方法”:前者通过循环嵌套,将等于val元素后的所有元素前移一位,覆盖掉该元素;后者通过“慢指针”和“快指针”的组合,“慢指针”代表新数组中元素的个数,新数组中最后一个元素的下一个位置,将“快指针”指向的非val元素赋给“慢指针”,下面给出两种解法基于C和C++的实现:
暴力解法(C):
int removeElement(int* nums, int numsSize, int val){
for(int i = 0; i < numsSize; i++){
if(nums[i] == val){
for(int j = i + 1; j < numsSize; j++){
nums[j - 1] = nums[j];
}
numsSize--; //长度自减
i--; //i也要自减
}
}
return numsSize;
}
双指针(C):
int removeElement(int* nums, int numsSize, int val){ //双指针
int slowIndex = 0;
for(int fastIndex = 0; fastIndex < numsSize; fastIndex++){
if(nums[fastIndex] != val){
nums[slowIndex++] = nums[fastIndex]; //把所有不为val的元素都移到前面
}
}
return slowIndex;
}
“双指针”的思想可以应用在很多算法中,请熟练掌握。
暴力解法(C++):
public:
int removeElement(vector& nums, int val) {
int length = nums.size();
for(int i = 0; i < length; i++){
if(nums[i] == val){
for(int j = i + 1; j < length; j++){
nums[j - 1] = nums[j];
}
length--;
i--;
}
}
return length;
}
};
双指针(C++):
class Solution {
public:
int removeElement(vector& nums, int val) {
int length = nums.size();
int slowIndex = 0;
for(int fastIndex = 0; fastIndex < length; fastIndex++){
if(nums[fastIndex] != val){
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
};
第一天算法训练营,打卡完毕!