声明:小白总结,本意是记录自己的思路,不过希望能帮助别人,那就更好啦,若发现问题,欢迎指正,感谢!!
来源:力扣(LeetCode)
链接:704.二分查找
题目:二分查找
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target
写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
题目解析
这个题目呢,可以说可以深刻理解二分的含义了,我认为就是每次分两半,一直一直……直到找到目标值
首先要知道数组的长度吧,然后呢,要有两个位置指针,循环终止条件是两指针相遇,当然啦,写法有很多,理解之后可以自己试试新的写法,我只是个小白……太弱了
代码
// java
class Solution {
public int search(int[] nums, int target) {
int m = nums.length;//数组长度
int left = 0, right = m - 1;//两个位置指针
while(left < right){//终止条件:两指针相遇
//找到中间位置,这样写是比较不容易出错的
int mid = left + (right - left) / 2;
if(nums[mid] < target){//如果中间值比目标值小
left = mid + 1;//往右移
}else{
right = mid;//否则,往左移
}
}
//最后left == right
如果此时的值(也可以用nums[right])与目标值相同,找到啦~否则,没找到……
return nums[left] == target ? left : -1;
}
}
——————————————
要再来个二分小宝贝吗?
Yes
——————————————
来源:力扣(LeetCode)
链接:374.猜数字大小
题目:猜数字大小
我们正在玩一个猜数字游戏。 游戏规则如下:
我从 1 到 n 选择一个数字。 你需要猜我选择了哪个数字。
每次你猜错了,我会告诉你这个数字是大了还是小了。
你调用一个预先定义好的接口 guess(int num),它会返回 3 个可能的结果(-1,1 或 0):
-1 : 我的数字比较小
1 : 我的数字比较大
0 : 恭喜!你猜对了!
输入: n = 10, pick = 6
输出: 6
题目解析
这个题目跟上面一题可以说是基本一样啦,只不过这里直接给了一个接口值让我们来比较大小,想一下之后来看吧
代码
// java
/**
* Forward declaration of guess API.
* @param num your guess
* @return -1 if num is lower than the guess number
* 1 if num is higher than the guess number
* otherwise return 0
* int guess(int num);
*/
public class Solution extends GuessGame {
public int guessNumber(int n) {
int left = 1, right = n;//两个指针
while(left <= right){//while(left < right)//循环条件
int mid = left + (right - left) / 2;//中间值
if(guess(mid) == 0){//找到目标值
return mid;//返回
}else if(guess(mid) == -1)//目标值较小
right = mid;//往左移
}else{//否则
left = mid + 1;//往右移
}
}
return -1;//return left//返回
}
}
——————————————
要再来个二分小宝贝吗?
Yes
——————————————
来源:力扣(LeetCode)
链接:面试题11.旋转数组的最小数字
题目:旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转
输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素
例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
输入:[3,4,5,1,2]
输出:1
输入:[2,2,2,0,1]
输出:0
题目解析
这个问题是想要找到那个旋转的值,可以想一下,这个旋转的最小值有什么特点呢,可以看到,它前面的值比最后一个值大,而它后面的值小于等于最后一个值,查找时就可以利用这个特性,这是如何确定的呢,我也是有迷惑,来记录一下,一个值如果比最后的大,那么它一定在前面的递增部分,目标值当然在它的后面啦,如果比最后的要小,那么它在后面的递增部分,那么目标值一定在他前面啦,这样一直缩小搜查范围,只要有,就一定会抓到哒~
因为有重复值的原因,我们要考虑,也就是说我们可能会遇到一个值跟最后一个值相同,由于这个数组是有序的,所以可以考虑把它砍掉,让这个二分再分一会儿
总结一下:先找到目标值的特点,来做排查,再将重复值砍掉
——————————应该就是这样啦~
代码
// java
class Solution {
public int minArray(int[] numbers){
int m = numbers.length;//数组长度
int left = 0, right = m - 1;//两个指针
while(left < right){//循环条件
int mid = left + (right - left) / 2;//中间值
if(numbers[mid] > numbers[right]){
//比最后值大,往右分
left = mid + 1;
}else if(numbers[mid] < numbers[right]){
//比最后值小,往左分
right = mid;
}else{
right--;//重复,砍掉
}
}
return numbers[left];//返回目标值
}
}
——————————————
要再来个二分小宝贝吗?
Yes
——————————————
来源:力扣(LeetCode)
链接:面试题53 - I. 在排序数组中查找数字 I
题目: 在排序数组中查找数字 I
统计一个数字在排序数组中出现的次数。
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
输入: nums = [5,7,7,8,8,10], target = 6
输出: 0
限制:
0 <= 数组长度 <= 50000
题目解析
题目要求我们找目标值出现的次数,如果我们能找到第一个出现的目标值,然后向后遍历并计数,就可得到,怎么找到第一个目标值就是我们的首要问题了。利用这个方法也可以解决找目标值首位置以及尾位置的问题。
现在来解决找到首个目标值的问题,二分法就是一直二分,直到找到目标值,首先,我们在解决二分查找时,可以说num[mid]的值很可能就目标值,如果我们把与目标值相同的mid趋向于往左边分,那么我们找到的是不是就是第一个了呢
比如:
while(left < right){
if(num[left] > target){
left = mid + 1;
}else{
right = mid;//把相同值往左分
}
}
再比如:
while(left < right){
if(num[left] < target){
right = mid;
}else{
left = mid + 1;//把相同值往右分
}
}
代码
// java
class Solution {
public int search(int[] nums, int target) {
int n = nums.length;
if(nums == null || n == 0) return 0;
int left = 0;
int right = n - 1;
while(left < right){
int mid = left + (right - left)/2;
if(nums[mid] < target){
left = mid + 1;
}else{
right = mid;//将相同值往左分,得到第一个目标值
}
}
int res = 0;
//将前提条件写在前面,防止数组越界
while((left <= n - 1) && (left >= 0) && (nums[left] == target)){
res++;//记录目标值个数
left++;//右移
}
return res;
}
}
——————————————
要再来个二分小宝贝吗?
Yes
——————————————
来源:力扣(LeetCode)
链接:349. 两个数组的交集
题目:两个数组的交集
给定两个数组,编写一个函数来计算它们的交集。
输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2]
输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [9,4]
说明:
输出结果中的每个元素一定是唯一的。
我们可以不考虑输出结果的顺序。
题目解析
这一题要找他们的交集,也就是说两个数组都有的元素,不考虑顺序,但不能重复
我们可以先固定一个数组,然后在另一个数组中查找,查到时要考虑,这个数是否已经存在了
思路不是很难,来实现吧
代码
// java
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
//定义一个Set数组来排查是否重复
Set<Integer> set = new HashSet<>();
Arrays.sort(nums2);//给小2排序
for(int target : nums1){//遍历小1的每个数
//看看在小2中能不能找到它,然后Set中有它了嘛~
if(binarySearch(nums2, target) && !set.contains(target)){
set.add(target);//满足条件,加入大家庭吧
}
}
int index = 0;//小朋友,排队拿票啦
int[] res = new int[set.size()];//定义一个数组房子
for(int num : set){//看看都有哪些小朋友
res[index++] = num;//按顺序进来玩吧
}
return res;//返回结果
}
//就用它来看看小1中的数在不在小2中
private boolean binarySearch(int[] nums, int target){
int left = 0, right = nums.length - 1;//两个指针
while(left <= right){//循环条件
int mid = left + (right - left) / 2;//中间值
if(nums[mid] == target){//找到啦
return true;//有它
}else if(nums[mid] < target){//比中间值大?
left = mid + 1;//右移
}else{//比中间值小?
right = mid - 1;//左移
}
}
//不可以在外面判断nums[left] == target
//万一小2是空心怎么办~越界啦~ 所以把它放里面判断吧
return false;//没找到那就是没有啦~
}
}
感谢各位巨巨们的帮助,希望在记录分析题目的条件下算法能有所提升……