leetcode刷题-- 3.二分查找
二分查找
正常实现
题解
public int binarySearch(int[] nums, int key) {
int l = 0, h = nums.length - 1;
while (l <= h) {
int m = l + (h - l) / 2;
if (nums[m] == key) {
return m;
} else if (nums[m] > key) {
h = m - 1;
} else {
l = m + 1;
}
}
return -1;
}
二分查找也称为折半查找,每次都能将查找区间减半,这种折半特性的算法时间复杂度为 O(logN)。
有两种计算中值 m 的方式:
- m = (l + h) / 2
- m = l + (h - l) / 2
l + h 可能出现加法溢出,也就是说加法的结果大于整型能够表示的范围。但是 l 和 h 都为正数,因此 h - l 不会出现加法溢出问题。所以,最好使用第二种计算法方法。
我感觉这里l,h最终都会扫到一个点上,即某一时刻l=h=m,只有L=h时,m才会=l=h,所以循环终止条件为l<=h
744 寻找比目标字母大的最小字母
题目描述
给定一个只包含小写字母的有序数组letters和一个目标字母target,寻找有序数组里面比目标字母大的最小字母。
数组里字母的顺序是循环的。举个例子,如果目标字母target = 'z' 并且有序数组为letters = ['a', 'b'],则答案返回'a'。
示例
输入:
letters = ["c", "f", "j"]
target = "a"
输出: "c"
输入:
letters = ["c", "f", "j"]
target = "c"
输出: "f"
输入:
letters = ["c", "f", "j"]
target = "d"
输出: "f"
输入:
letters = ["c", "f", "j"]
target = "g"
输出: "j"
输入:
letters = ["c", "f", "j"]
target = "j"
输出: "c"
输入:
letters = ["c", "f", "j"]
target = "k"
输出: "c"
题解
class Solution:
def nextGreatestLetter(self, letters: List[str], target: str) -> str:
l,r = 0,len(letters)-1
if target<letters[l] or target>=letters[r]:
return letters[l]
while l<=r:
m = l + (r-l)//2
if target>=letters[m]:
l = m + 1
else:
r = m - 1
return letters[l]
这里l<=r,不能l<r,例如
输入:
["c","f","j"]
"c"
输出:
"c"
预期:
"f"
因为target < letters[m]时,r=m-1会出现r指到l的情况,这时还需一次循环。
我的思路时将所有情况分为三种:
- target<letters[l]
- target>=letters[r]
- letters[l]<=target<letters[r]
因为1,2种结果一样就归为一类,上面代码主要讨论第三种。
最终l是要比m前一位,所以输出l
278第一个错误的版本
题目描述
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
示例
给定 n = 5,并且 version = 4 是第一个错误的版本。
调用 isBadVersion(3) -> false
调用 isBadVersion(5) -> true
调用 isBadVersion(4) -> true
所以,4 是第一个错误的版本。
题解(python)
# The isBadVersion API is already defined for you.
# @param version, an integer
# @return a bool
# def isBadVersion(version):
class Solution:
def firstBadVersion(self, n):
"""
:type n: int
:rtype: int
"""
l,r = 1,n
while l<=r:
m = l+(r-l)//2
if isBadVersion(m):
r = m-1
else:
l = m+1
return l
总结
做了这么几道题,有点感觉。例如上面这道,或者之前的最终情况我们可以想象成三个元素的区间,[a(0),a(1),a(2)],l=0,r=2。讨论一下第一轮m=1时,a(1)是否符合条件,就容易判断边界条件了。
我感觉当l<=r时,也就是考虑l=r时,也就是最后肯定会出现l=r,这时候上面这个例子中,m=l=r, 此时若m处是满足条件的,那么r=m-1,r就是最后错误版本之前正确的版本,l=m最后错误版本。若m处不满足条件,那么l=m+1,l就是最后错误版本,此时m=r是最后正确版本。
也就是说,当l<=r时,这种情况下l如果等于m-1,那么l最后会指向最后满足,我们设定条件的位置,这道题的条件即是否是错误版本,r则会指向其之前一位。
leetcode刷题-- 3.二分查找的更多相关文章
- LeetCode刷题总结-二分查找和贪心法篇
本文介绍LeetCode上有关二分查找和贪心法的算法题,推荐刷题总数为16道.具体考点归纳如下: 一.二分查找 1.数学问题 题号:29. 两数相除,难度中等 题号:668. 乘法表中第k小的数,难度 ...
- C#LeetCode刷题-二分查找
二分查找篇 # 题名 刷题 通过率 难度 4 两个排序数组的中位数 C#LeetCode刷题之#4-两个排序数组的中位数(Median of Two Sorted Arrays)-该题未达最优解 30 ...
- LeetCode刷题专栏第一篇--思维导图&时间安排
昨天是元宵节,过完元宵节相当于这个年正式过完了.不知道大家有没有投入继续投入紧张的学习工作中.年前我想开一个Leetcode刷题专栏,于是发了一个投票想了解大家的需求征集意见.投票于2019年2月1日 ...
- LeetCode刷题总结之双指针法
Leetcode刷题总结 目前已经刷了50道题,从零开始刷题学到了很多精妙的解法和深刻的思想,因此想按方法对写过的题做一个总结 双指针法 双指针法有时也叫快慢指针,在数组里是用两个整型值代表下标,在链 ...
- LeetCode刷题总结-数组篇(上)
数组是算法中最常用的一种数据结构,也是面试中最常考的考点.在LeetCode题库中,标记为数组类型的习题到目前为止,已累计到了202题.然而,这202道习题并不是每道题只标记为数组一个考点,大部分习题 ...
- LeetCode刷题总结-数组篇(中)
本文接着上一篇文章<LeetCode刷题总结-数组篇(上)>,继续讲第二个常考问题:矩阵问题. 矩阵也可以称为二维数组.在LeetCode相关习题中,作者总结发现主要考点有:矩阵元素的遍历 ...
- LeetCode刷题总结-树篇(上)
引子:刷题的过程可能是枯燥的,但程序员们的日常确不乏趣味.分享一则LeetCode上名为<打家劫舍 |||>题目的评论: 如有兴趣可以从此题为起点,去LeetCode开启刷题之 ...
- LeetCode刷题笔记和想法(C++)
主要用于记录在LeetCode刷题的过程中学习到的一些思想和自己的想法,希望通过leetcode提升自己的编程素养 :p 高效leetcode刷题小诀窍(这只是目前对我自己而言的小方法,之后会根据自己 ...
- LeetCode刷题的一点个人建议和心得
目录 1. 为什么我们要刷LeetCode? 2. LeetCode的现状和问题 3. 本文的初衷 4. LeetCode刷题建议 4.1入门数据结构,打基础阶段 4.2 建立 ...
随机推荐
- 洛谷 P1464 Function(简单记忆化)
嗯... 让一切从水开始吧... 水过初赛,但愿复赛能够接着水过... 这道题不记忆化会tle,所以用空间换时间,将每次的答案(只有20*20*20个)存下来,如果之前已经求过,就不需要重复求了... ...
- echart 重新加载
myechart2.clear(); myechart2.setOption(options[1]);
- Java入门笔记 03-面向对象(中)
介绍:这部分内容主要是介绍和总结封装.继承和多态. 一. 封装:把该隐藏的隐藏起来,把该暴露的暴露出来 封装是指将信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现 ...
- html 标签 frame
html 标签 frame 对于html标签,一般都是在<html>标签对里包着<head>标签对和<body>标签对,body元素定义文档的主体,包含文档的所有内 ...
- 九、Appium-python-UI自动化之通过text定位
1.通过xpath定位text xpath路径为://android.widget.EditText[@text='请输入包含街道的完整地址'] 2.通过AndroidUIAutomator # 这个 ...
- 快速创建vue 项目
随着VUE 技术的不断更新,越来越多的开发者开始使用vue编写前端界面,今天我就和大家分享一下 ,如何快速创建一个vue项目. 前提: 安装了node.js 首先: 全局安装vue-cli 使用命令: ...
- Educational Codeforces Round 73 (Rated for Div. 2)F(线段树,扫描线)
这道题里线段树用来区间更新(每次给更大的区间加上当前区间的权重),用log的复杂度加快了更新速度,也用了区间查询(查询当前区间向右直至最右中以当前区间端点向右一段区间的和中最大的那一段的和),也用lo ...
- [读书]The Man Who Solved the Market
出乎个人意料的是,西蒙斯是从FICC类品种起步的,包括量化投资方法获得第一次重大突破也是在FICC品种上. FICC市场的深度不够,所以文艺复兴科技实现规模扩张是股票策略成功之后的事情,很靠后. 虽然 ...
- java8新特性1:lambda表达式和函数式接口
1.lambda的介绍: 1.1.为什么java语言需要引入lambda表达式? java语言诞生于1995年,历史时间已经相对较长了.在其后的各种新型编程语言中,都有着lambda表达式的内容,并且 ...
- 并发队列之ArrayBlockingQueue
上一篇我们说了并发队列中的LinkedBlockingQueue队列,这次我们看看ArrayBlockingQueue,看看名字,我们想象一下LinkedList和ArrayList的区别,我们可以知 ...