Day01| 27. 移除元素、704. 二分查找
27. 移除元素
解法1: 暴力解法(两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组。)
// 暴力解法
// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
class Solution {
public int removeElement(int[] nums, int val) {
int n = nums.length;
int count=0;
for(int i=0;i<n;i++){
if(nums[i]==val){ // 发现需要移除的元素,就将数组集体向前移动一位
for(int j=i;j<n-1;j++){
nums[j]=nums[j+1];
}
i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
n--; // 此时数组的大小-1
}
}
return n;
}
}
解法2:双指针法
双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
定义快慢指针:
快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
慢指针:指向更新 新数组下标的位置
看代码,相当于就是只有在nums[fast]!=val时,才会给nums[slow]赋值;只有slow处得到了赋值,才能前进(i.e. slow++)。
// 双指针法
// 时间复杂度:O(n)
// 空间复杂度: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];
slow++;
}
}
return slow;
}
}
补充:还有一个相向双指针法:
//相向双指针法
class Solution {
public int removeElement(int[] nums, int val) {
int left = 0;
int right = nums.length - 1;
while(right >= 0 && nums[right] == val) right--; //将right移到从右数第一个值不为val的位置
while(left <= right) {
if(nums[left] == val) { //left位置的元素需要移除
//将right位置的元素移到left(覆盖),right位置移除
nums[left] = nums[right];
right--;
}
left++;
while(right >= 0 && nums[right] == val) right--;
}
return left;
}
}
704. 二分查找
704题考察的就是标准的二分查找。用三个模板中的第一个即可。
如下,是按照左闭右闭的方式总结的3个二分查找模板。第1个就是标准的二分查找,第2个是查找左边界(即待查找元素第1次出现的索引),第3个是查找右边界(即待查找元素最后1次出现的索引)。
必须背下来!
int binary_search(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while(left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if(nums[mid] == target) {
// 直接返回
return mid;
}
}
// 直接返回
return -1;
}
int left_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 别返回,锁定左侧边界
right = mid - 1;
}
}
// 判断 target 是否存在于 nums 中
// 此时 target 比所有数都大,返回 -1
if (left == nums.length) return -1;
// 判断一下 nums[left] 是不是 target
return nums[left] == target ? left : -1;
}
int right_bound(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] == target) {
// 别返回,锁定右侧边界
left = mid + 1;
}
}
// 此时 left - 1 索引越界 right=left-1
if (right < 0) return -1;
// 判断一下 nums[left] 是不是 target
return nums[right] == target ? (left - 1) : -1;
}