1.二分查找
二分查找所遇到的数组主要分为三种情况,左闭右闭,左闭右开以及左开右闭(最后一种与第二种原理相同 可以忽略)。
①左闭右闭:对于二分查找,细节处在于While循环条件的设置以及每次查找不成功后指针位置的更新,对于左闭右闭区间,可以设置两个指针low和high分别在开始指向下表为0的元素和下标为numsSize-1的元素,对于特殊情况当low==high的时候即两个指针指向同一个元素,在左闭右闭的区间中是合理的,简单说如果给定一个只有两个相同元素的集合,取出其中的元素,是合理的。在每次进行匹配时用匹配过后数组的中间值与目标值进行匹配,nums[middle]与target进行大小比较,如果target>nums[middle],high=middle-1;如果target<nums[middle],low=middle+1;如果匹配直接返回下标。(对于更新的加一减一需要做如下说明:由于在这个两边都能取到的区间中我们已经将目标值和nums[middle]进行大小比较,那么接下来的比较就不需要再包括这个数,所以要将更新后的指针移动一个位置)
int search(int* nums, int numsSize, int target){
if(numsSize==1&&nums[0]==target)
{
return 0;
}
else if(numsSize==1&&nums[0]!=target)
{
return -1;
}
int low=0,high=numsSize-1;
int middle=(low+high)/2;
while(low<=high) //易错点:在区间中一定要有low<=high而不是单纯的小于 判断是小于等于还是小于的依据是带入看其究竟是否为一个非法区间来满足自己的需要
{
if(nums[middle]<target)
{
low=middle+1;
middle=(low+high)/2;
}
else if(nums[middle]==target)
{
return middle;
}
else
{
high=middle-1;
middle=(low+high)/2;
}
}
return -1;
}
②左闭右开:此情况与上面的原理相同,但是细节需要稍微修改,首先由于右边取不到,所有可以直接将high=numsSize,并且While循环的条件必须删去等号(举例方法与第一种相同,若为两个相同元素的集合指向同一个时会发生矛盾所以不能让其相等)。还有每次更新位置的时候nums[middle]与target进行大小比较,如果target>nums[middle],high=middle;如果target<nums[middle],low=middle+1;如果匹配直接返回下标。(此时由于右边是无法取到的,所以只需要将更新后的high=middle,不需要加一,与high初始值的取法原理相同)
2.移除元素
①最简单的想法:两层循环+统计目标值
②快慢指针:利用快慢指针的思想,每次只需要判断当前快指针所指向的元素值是否为目标值,如果不是则两个指针共同前进,并且把快指针指向的值赋给慢指针,如果是,则仅有快指针前进。在未遇到目标值的时候仅在原地交换,但在开始遇到之后直接将最近的非目标值的数对目标值进行覆盖,并且最后的返回值只需要返回慢指针所指向的位置即可。(话不多说,直接上代码)
int removeElement(int* nums, int numsSize, int val){
int slow=0;
for(int fast=0;fast<numsSize;fast++)
{
if(nums[fast]!=val)
{
nums[slow]=nums[fast];
slow++;
}
}
return slow;
}