Day1 二分查找+移除元素
代码随想录算法训练营第1天 | 704.二分查找、27.去除元素
704. 二分查找
思路:
数组元素为有序排列,我们需要确定搜索的左右边界。这道题中有边界可以包括也可以不包括,所有有两种[left, right]
左闭右闭区间,他的while的循环条件left <= right
,终止条件为 left == right + 1
。 还有一种[left, right)
左闭右开区间,他的while的循环条件left < right
,终止条件为 left == right
。
代码部分:
方法一: 采用左闭右闭区间
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
// target在[left, right]
while(left <= right){
//int mid = (left + right) / 2;
int mid = left + (right - left) / 2;
if(nums[mid] < target){
// 此时搜索区间为 [m + 1, r]
left = mid + 1;
}
if(nums[mid] > target){
// 此时搜索区间为 [l, m - 1]
right = mid - 1;
}
if(nums[mid] == target){
return mid;
}
}
return -1;
}
}
方法一: 采用左闭右开区间
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
// target在[left, right)
while(left < right){
//int mid = (left + right) / 2;
int mid = left + (right - left) / 2;
if(nums[mid] < target){
// 此时搜索区间为 [m + 1, r)
left = mid + 1;
}
if(nums[mid] > target){
// 此时搜索区间为 [l, m)
right = mid;
}
if(nums[mid] == target){
return mid;
}
}
return -1;
}
}
两个算法时间复杂度:
O(log2n)
空间复杂度:
O(1)
27. 移除元素
思路:
因为题目要求不要使用额外的数组空间,你必须仅使用 O(1)
额外空间并原地修改数组。所以有两种方法:
一:暴力法(两层循环,当找到要删除的值val时,把当前值val的后面所有元素往前移动一位)
二:快慢指针:
用慢指针保留去掉后的数组,慢指针从0开始;用快指针遍历数组。
---- 当数组元素不等于val时,把快指针对应值nums[fast]
赋给慢指针nums[slow]
。
---- 当数组元素等于val时,不赋值,找下一个元素比较。
代码部分:
方法一:暴力法
class Solution {
public int removeElement(int[] nums, int val) {
int len = nums.length;
for(int i = 0; i < len; i++){
if(nums[i] == val){
for(int j = i+1; j < len; j++){
// 用目标元素的后一位元素去覆盖目标元素
nums[j - 1] = nums[j];
}
i--;
len--;
}
}
return len;
}
}
时间复杂度:双层for循环,所以为O(n^2)
空间复杂度:O(1)
方法二:快慢指针
class Solution {
public int removeElement(int[] nums, int val) {
int slow=0;
for(int fast=0;fast<nums.length;fast++){
if(nums[fast] != val){
nums[slow++] = nums[fast];
}
}
return slow;
}
}
时间复杂度:O(n)
空间复杂度:O(1)
总结
一:数组为有序数组,同时题目还强调数组中无重复元素,可以考虑使用二分查找法。
二:mid = (left + right) / 2,如果 left 和 right 都很大,加法操作的结果可能会超过整型变量的最大值,从而导致溢出错误。可以使用 mid = left + (right - left) / 2;
三:引用传递。函数返回的是 slow
的值,也就是最终数组中非目标值元素的数量。由于 Java 中的数组是引用类型,因此对数组的修改会对原始数组产生影响,函数不需要显式返回修改后的数组,因为原始数组已经被修改了。这种方式被称为“引用传递”,即传递的是引用(指针),而不是对象本身的拷贝。