力扣题目链接(opens new window)
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
二分时的条件到底是 while(left < right)
还是 while(left <= right)
二分完后根据target的位置不同,指针到底应该指向哪,是right = middle
,还是要right = middle - 1
此时left == right是有意义的,if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
public class BinarySearch {
public int search1 (int[] nums, int target){
// whlie循环中为左闭右闭区间
// 定义左右指针及中间位置
int left = 0;
int right = nums.length - 1;
while (left <= right){
int mid = left + ((right - left) >> 1);
if (target < nums[mid]){
right = mid - 1;
}else if (target > nums[mid]){
left = mid + 1;
}else if (target == nums[mid]){
return mid;
}
}
return -1;
}
}
因为left == right在区间[left, right)是没有意义的,if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,right即使更新为middle也是在开区间上,不会参与比较
public int search2 (int[] nums, int target){
// whlie循环中为左闭右开区间
// 定义左右指针及中间位置
int left = 0;
int right = nums.length; // 左闭右开时右指针要指出数组右边界后一位,开区间取不到
while (left < right){
int mid = left + ((right - left) >> 1);
if (target < nums[mid]){
right = mid;
}else if (target > nums[mid]){
left = mid + 1;
}else if (target == nums[mid]){
return mid;
}
}
return -1;
}
时间复杂度:O(logn)
力扣题目链接
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
定义快慢指针
当快指针指向的值不等于目标值,那么快指针此时指向的值便可以赋值给慢指针所指向的新数组
public class RemoveElement {
public int removeElement(int[] nums, int val){
int slowIndex = 0; // 寻找新数组的元素 ,新数组就是不含有目标元素的数组
int fastIndex = 0; // 新新数组下标
for (fastIndex = 0; fastIndex < nums.length; fastIndex++){
if (nums[fastIndex] != val){
nums[slowIndex] = nums[fastIndex];
slowIndex++;
}
}
return slowIndex;
}
}
O(n)
核心就是把不等于val的全部放在数组左边,等于val的全部放在数组右边
难点是关于while中<
与<=
的使用
while (leftIndex <= rightIndex && nums[leftIndex] != val){
leftIndex++;
}
当leftIndex=rightIndex两个指针重合,说明左边已经没有val要移动到右边,左指针指向两指针重合的下一位,当leftIndex>rightIndex循环停止
while (leftIndex <= rightIndex && nums[rightIndex] == val) {
rightIndex--;
}
此时leftIndex已经大于rightIndex,循环停止。
if (leftIndex < rightIndex)
leftIndex=rightIndex时当二指针重合时不需要交换
完整代码:
public int removeElement(int[] nums, int val){
// 双向指针的方法
int leftIndex = 0; // 左指针
int rightIndex = nums.length - 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;
}