代码随想录算法训练营第一天 | LeetCode704. 二分查找,27. 移除元素
1. LeetCode704 二分查找
1) 使用二分法的前提条件:
- 数组为有序数组
- 数组中无重复元素
2) 二分查找法:
- 写二分法经常写乱,主要是对区间的定义不确定
- 区间的定义就是不变量。
- 在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。
- 写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。
- 二分法的两种写法详见下面代码随想录的超链接
- 文章里提到的区间中 left == right 有没有意义的意思是,如果是左闭右开那么右指针right = nums.length。数组里没有nums[right]这个元素,所以说是右边开的区间,且left==right是无意义的。
以上二分查找法的使用是学习了代码随想录的讲解
class Solution {
public int search(int[] nums, int target) {
// 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
if (target < nums[0] || target > nums[nums.length - 1]) {
return -1;
}
int left = 0;
int right = nums.length-1;
while(left<=right){
int mid = (right-left)/2+left;
if(nums[mid] == target){
return mid;
}else if(nums[mid]>target){
right = mid-1;
}else if(nums[mid]<target){
left = mid+1;
}
}
return -1;
}
}
2. LeetCode27移除元素
学习资料
解法一:暴力解法(时间复杂度是O(n2))
思路:
- 声明一个size变量储存数组的大小。
- 遍历数组,当发现数组中的值与目标值相等时,让该元素的下一个元素依次覆盖前一个元素。
- 将i–,这是因为后一个元素覆盖了前一个元素,所以i这个位置的值是新的,还没有被遍历过
- 将size-- 因为减少了一个元素,所以需要将数组大小减一
- 这里要注意size这个变量是有必要声明出来并使用的,不然在LeetCode中这种暴力解法会超时。
- 使用size变量不超时的原因是因为每有一个元素被删除,i的上限大小会变小,数组长度同时变小,那里层循环的次数也会变少,但是时间复杂度依旧是O(n2)
class Solution {
public int removeElement(int[] nums, int val) {
int size = nums.length;
for(int i=0;i<size;i++){
if(nums[i] == val){
for(int j=i+1;j<size;j++){
nums[j-1]=nums[j];
}
i--;
size--;
}
}
return size;
}
}
解法二:双指针(快慢指针法)(时间复杂度是O(n))
这个方法在解决链表题的时候也常用
思路:
- 当快指针指向的数组元素与目标元素的值相等时,让快指针移动到下一个元素
- 当快指针指向的数组元素与目标元素的值不相等时,让nums[slowIndex] = nums[fastIndex]
- 第2步的本质就是实现了下一个元素对上一个元素的覆盖。
class Solution {
public int removeElement(int[] nums, int val) {
int slowIndex = 0;
for(int fastIndex = 0;fastIndex<nums.length;fastIndex++){
if(nums[fastIndex] != val){
nums[slowIndex] = nums[fastIndex];
slowIndex++;
}
}
return slowIndex;
}
}