随想录训练营Day1|704.二分查找、27.去除元素
标签: LeetCode闯关记
1. 704.二分查找 1.1 题目 相关链接 704 二分查找
参考labuladong: 双指针技巧秒杀七道数组题目 ###1.2 解题思路 二分查找 ###1.3 遇到问题 无 ###1.4 算法实现 算法分析
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while(left <= right){ //查找范围:[left,right] = [0, nums.length - 1](左闭右闭)
int mid = left + (right - left) / 2;
if (nums[mid] > target){
right = mid - 1;
}else if(nums[mid] == target){
return mid;
}else if( nums[mid] < target){
left = mid + 1;
}
}
return -1;
}
}
注意点:待更新
###1.5 题目总结 解题耗时:30min ###1.6 相关题目
- 35. 搜索插入位置: 左侧边界
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while(left <= right){//查找范围:[left,right] = [0, nums.length - 1](左闭右闭)
int mid = left + (right - left)/2; //注意
if(nums[mid] > target){
right = mid - 1;
}else if (nums[mid] < target){
left = mid + 1;
}else if (nums[mid] == target ){
right = mid - 1;//target已经找到后, 令right = mid - 1, 所以对于nums[mid]恒< target,left不断变为mid-1,即left不断右移,until left第一次>right, 此时, 即left - 1 = right,因不满足while循环条件而退出循环.这时的left指向的元素就是target,因为 left - 1 = right,且 right = mid - 1, mid 为target,则nums[left] = target;
}
}
return left;
}
}
- 34. 在排序数组中查找元素的第一个和最后一个位置: 左右侧边界
class Solution {
public int[] searchRange(int[] nums, int target) {
return new int []{left_bound(nums, target), right_bound(nums, target)};
}
//寻找左侧边界
int left_bound(int[]nums, int target){
int left = 0;
int right = nums.length - 1;
while(left <= right){
int mid = left + (right - left) / 2;
if(nums[mid] >= target){
right = mid - 1;
}else if(nums[mid] < target){
left = mid + 1;
}
}
//判断边界
if(left > nums.length - 1 || nums[left] != target){
return -1;
}else{ return left;}
}
//寻找右侧边界
int right_bound(int[]nums, int target){
int left = 0;
int right = nums.length - 1;
while(left <= right){
int mid = left + (right - left) / 2;
if(nums[mid] > target){
right = mid - 1;
}else if(nums[mid] <= target){
left = mid + 1;
}
}
//判断边界
if( right < 0 || nums[right] != target){
return -1;
}else{ return right;}
}
}
##2. 27.去除元素 ###2.1 题目 题目:原地移除=val的元素 ###2.2 解题思路 1.暴力求解 2.快慢指针 ###2.3 遇到问题 报错: 时间超过限制(法1) 原因:for循环的循环条件---- i < new_length 写成 i< nums.length
报错:越界异常(法2) 原因: slow++ 写在 nums[slow] = nums[fast]之前 ###2.4 实现代码 1.两次for循环 算法实现:
class Solution {
public int removeElement(int[] nums, int val) {
//遍历数组,遍历到删除元素后,将其删除
int new_length = nums.length;
for(int i = 0; i < new_length; i++){//错把i < new_length写成了i < nums.length,导致时间超出限制
if(nums[i] == val){
for( int j = i + 1; j < new_length; j++){//错把j < new_length写成了j < nums.length,导致时间超出限制
nums[j - 1] = nums[j];
}
nums[nums.length - 1] = 0;
i--;//因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
new_length--;//// 此时数组的大小-1
}
}
return new_length;
}
}
注意点: i--: 作用是为了避免遍历过程中漏掉重复的 val 元素。因为删除一个元素后,后面的元素会向前移动一位,而当前的 i 指向的是被删除的元素的下一个元素,因此需要将 i 向前移动一位,继续判断当前位置的元素是否为 val,直到找到下一个非 val 元素。
2.快慢指针
class Solution {
public int removeElement(int[] nums, int val) {
int slow = 0, fast = 0;
while(fast < nums.length){
if(nums[fast] != val){
nums[slow] = nums[fast];
slow++;//注意slow++ 和 nums[slow] = nums[fast] 的位置关系
}
fast++;
}
return slow;
}
}
注意点: 注意slow++ 和 nums[slow] = nums[fast] 的位置关系:例如,
假设在第一个元素上有要删除的值 val,那么如果在将 nums[slow] 赋值之前执行 slow++,则第一个元素将永远不会被覆盖,并且如果没有其他不等于 val 的元素,将返回错误的长度。
此外,如果 slow++ 放在 nums[slow] = nums[fast] 之后,将可能导致 slow 超过数组的长度并导致数组越界异常。因为当 fast 遍历数组时,slow 被赋值为所有非 val 元素的索引,这意味着 slow 可能超过最后一个非 val 元素的索引,而这个索引的最大值是 nums.length - 1。
###2.5 题目总结 解题耗时: 40min ###2.6 相关题目 1.26. 删除有序数组中的重复项 快慢指针:
class Solution {
public int removeDuplicates(int[] nums) {
if(nums.length == 0){
return 0;
}
int low = 0;
int fast = 0;
while (fast < nums.length){
if(nums[low] != nums[fast]){
low++;
nums[low] = nums[fast];
}
fast++;
}
return low + 1;//注意:需要+1,返回数组长度
}
}
2.283. 移动零
class Solution {
public void moveZeroes(int[] nums) {
int slow = 0;
int fast = 0;
while(fast < nums.length){
if(nums[fast] != 0){
nums[low] = nums[fast];
slow++;//注意
}
fast++;
}
return slow;
for(int p = slow; p < nums.length; p++){
nums[p] = 0;
}
}
}
##3. 今日心得 写博客好累,以及第一次转码人刷题确实漏洞百出,千疮百孔. 得下个编译器,markdown用得还不太顺畅. Thanks for ChatGPT's help!