代码随想录算法训练营第一天| 704.二分查找、35.搜索插入位置、27.移除元素

代码随想录算法训练营第一天| 704.二分查找、35.搜索插入位置、27.移除元素

二分查找

题目链接:

https://leetcode.cn/problems/binary-search/

问题

在这里插入图片描述

解题思路

主要问题就是索引的区间的开闭问题,具化一点唯一的难度也就是while (left < right)是否带等号以及每次对left或right部分索引的修改

方案一:

搜索区间均闭合,即[left,right],这样也就意味着每次拿来比较的mid不应该再出现在新的区间内,因为mid所在位置的元素已经进行了判断,不需要再出现在新的区间内,只需要取[left, mid - 1]或[mid + 1, right]。同时由于左右区间均为闭合区间,所以允许left=right,该条件允许成立。

class Solution {
    public int search(int[] nums, int target) {
		int left = 0;
		int right = nums.length - 1;
		while (left <= right){
			int mid = (left + right) / 2;
			if (nums[mid] == target)
				return mid;
			else if (nums[mid] > target)
				right = mid - 1;
			else
				left = mid + 1;
		}
		return -1;
    }
}
方案二:

搜索区间左开右闭或者左闭合开,即[left, right)或(left, right],下面以左闭又开举例,也就意味着每次right并不在比较的范围内,经过mid判断后只需要取[mid + 1,right) 或 [left, mid),因为对于开区间来说mid本身就不在考虑的范围内,而也就不允许left=right。

class Solution {
    public int search(int[] nums, int target) {
		int left = 0;
		int right = nums.length;
		while (left < right){
			int mid = (left + right) / 2;
			if (nums[mid] == target)
				return mid;
			else if (nums[mid] > target)
				right = mid;
			else
				left = mid + 1;
		}
		return -1;
    }
}

搜索插入位置

题目链接:

https://leetcode.cn/problems/search-insert-position/

问题

在这里插入图片描述

解题思路

对于该问题也是使用二分法,区别仅仅在于当找不到元素时需要查找插入位置,而当使用左开右闭的方式进行二分查找时,当找不到时候的终止条件是left >= right,而其真正的结束循环的位置在left = right。如果在达到结束条件前的最后一次结果是[mid + 1,right) ,那么也就意味着target要比mid+1位置上的元素要大,而right位置上的元素并不在区间内,因为在初始条件下的right就是数组长度,已经是越界的索引,所以最终的位置也就应该是right对应的索引,因为right部分并不是闭合的区间。而如果是[left, mid)则表示最终位置要比left还要小,所以可以使用left位置的索引来表示,而终止条件是left=right,所以使用right统一表示即可

class Solution {
    public int searchInsert(int[] nums, int target) {
		int left = 0;
		int right = nums.length;
		while (left < right){
			int mid = (left + right) / 2;
			if (nums[mid] == target)
				return mid;
			else if (nums[mid] > target){
				right = mid;
			}
			else if (nums[mid] < target){
				left = mid + 1;
			}
		}
		return right;//使用left也可以
    }
}

移除元素

题目链接:

https://leetcode.cn/problems/remove-element/

问题

在这里插入图片描述

解法
暴力解法:

直接两层for,难点仅仅在于第二层for来覆盖数据后记得将第一次计数的i索引进行回退,防止覆盖后的还是target

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; j < size - 1; j++) {
					nums[j] = nums[j + 1];
				}
				size--;
				i--;
				//i--是防止覆盖当前i会在下一次循环+1,但是为了防止当前位置的i覆盖后的值仍为val,所以要-1
			}
		}
		return size;
    }
}
使用双指针(两个都从起始位置出发)

slowIndex与fastIndex最开始一起出发,而slowIndex当遇到val相同时会停下来等待,而fastIndex会继续走来寻找下一个不是val的值,找到后覆盖slowIndex位置处的数据,然后再让slowIndex走,这样也就导致最后slowIndex的位置或者是val值的位置或者是最后一个元素的位置,即导致索引越界的位置,整体复杂度相比于暴力解法减小了,该方法为O(n)

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];
			}
		}
		return slowIndex;
	}
}
使用双指针(一前一后)

左面的找的是等于val的,右面找的是不等于val的,然后用右边覆盖左边,因为左右都是闭区间,所以使用>=

对于这种情况有一个问题是出现rightIndex的值也为val,但是即使如此也可以成功运行,因为覆盖后leftIndex并没有发生变化,会继续进行检查,而rightIndex已经向左移动

class Solution {
    public int removeElement(int[] nums, int val) {
		int leftIndex = 0;
		int rightIndex = nums.length - 1;
		while (leftIndex <= rightIndex){
			if (nums[leftIndex] == val){
				nums[leftIndex] = nums[rightIndex];
				rightIndex--;
			}else
				leftIndex++;
		}
		return leftIndex;
	}
}
  • 11
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值