目录
前言
仅做学习使用,侵删
什么是ARTS?
算法(Algorithm): 每周至少一道LeetCode算法题,加强编程训练和算法学习
阅读(Review): 阅读并点评至少一篇英文技术文章,提高英文水平
技巧 (Tip):学习至少一个技术技巧,总结、归纳日常工作中遇到的知识点
分享(Share):分析一篇有关点和思考的技术文章,建立影响力,输出价值观
算法
力扣704题
一道经典的二分查找题目
二分查找
基本思想:
二分查找算法(递归的方式):
- 创建一个查找算法,参数列表有left,right,findValue,array
- 创建一个变量mid,通过left和right获取mid
- 通过对mid的比较,决定递归方向
- 最后判断是否能找到
📌
请注意,所有的二分查找算法都是建立在数组有序的基础上的,如果带查找序列是无序序列,不能用二分查找算法,只能使用其他查找算法,谨记!
经典写法(找单值):
public static int binarySearchSingle(int[] array,int left,int right,int findValue) {
if(left > right || findValue > array[length-1]) {
return -1;
}
var mid = left + 1/2*(right - left);
var midValue = array[mid];
if(findValue > midValue) {
return binarySearchSingle(array,mid+1,right,findValue);
}else if(findValue < midValue) {
return binarySearchSingle(array,left,mid-1,findValue);
}else {
return mid;
}
}
代码分析:
- left是左索引,right是右索引,应该一开始就被赋值为0与array.length-1(因为带查找的值在他们两个索引之间,即
[left,right]
区间内有带查找元素) - findValue是待查找的值,array是带查找的数组
- 二分查找法顾名思义是折半,所以
mid = 1/2(left + right) = left + 1/2*(right - left)
注意:后面的表达式非常的重要,是折半查找发的关键
- 将mid下标对应的值放入midValue
情况:
- 如果midValue大于findValue,由于有序,说明待查找的元素在mid右边且不为mid,所以得出了[mid+1,right]的范围内有带查找元素,故left = mid+1
- 如果midVvalue小于findValue,由于有序,说明带查找的元素在mid左边且不为mid,所以得出了[left,mid-1]的范围内有带查找元素,故right = mid-1
- 如果midValue = findValue,说明找到了该元素,直接返回mid即可,mid是下标
- 如果left > right,由于没有这样的区间(即区间左边必须小于右边的值),说明找不到,直接返回-1
- 如果findValue大于列表的最后一个值,由于有序,最后一个值为最大值,说明列表里面不可能有与findValue相同的值,直接返回-1
经典写法(找数组即多个返回值)
public static List<Integer> binarySearchMore(int[] array,int left,int right,int findValue) {
if(left > right || findValue > array[length-1]) {
return new ArrayList<Integer>();
}
var mid = (left + right)/2;
var midValue = array[mid];
if(findValue > midValue) {
return binarySearchMore(array,mid+1,right,findValue);
}else if(findValue < midValue) {
return binarySearchMore(array,left,mid-1,findValue);
}else {
var list = new ArrayList<Integer>();
list.add(mid);
var temp = mid - 1;
while(temp > 0 && array[temp] == findValue) {
list.add(temp--);
}
temp = mid + 1;
while (temp < array.length && array[temp] == findValue) {
list.add(temp++);
}
return list;
}
代码分析
- 注意:由于其他代码都一样,我们重点分析一下else里面的代码
- 当程序进入else时,说明找到了该元素,由于我们要实现多元素返回,我们可以借助集合,故我们要new一个ArrayLsit<Integer>
- 先将该元素add进去集合中
- 创建一个辅助索引temp,赋值为mid-1(目的:向左遍历)
- 通过while循环,如果temp>0(防止数组下标越界异常),且array[temp] = findValue,说明此元素也是我们要找的元素,添加入集合中
- 如果while布尔表达式为false,说明temp遍历到了最左边或是不相等,由于列表的有序性,如果不相等,则前面的元素一定比midValue小,不可能再有带查找的元素,直接结束向左遍历
- temp赋值为mid+1(目的:向右遍历)
- 同理5~6
- 最后返回list即可
- 特别注意的是,如果找不到,我们返回一个空的集合,所以在最前面new了一个空集合
经典题目
题目描述:
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
提示:
你可以假设 nums 中的所有元素是不重复的。
n 将在 [1, 10000]之间。
nums 的每个元素都将在 [-9999, 9999]之间。
官方题解
class Solution {
public int search(int[] nums, int target) {
int left = 0,right = nums.length - 1;
while (left <= right){
int mid = (right - left) / 2 +left;
int num = nums[mid];
if (num == target) {
return mid;
} else if (num > target) {
right = mid - 1;