LeetCode刷题模板(1):《我要打10个》之二分法
Author : 叨陪鲤 Email : vip_13031075266@163.com Date : 2021.01.23 Copyright : 未经同意不得转载!!! Version : 第一章 二分法 Reference:《LeetCode刷题笔记之模板整理》 |
目录
1.3.11 LC-34:在排序数组中查找元素的第一个和最后一个
1. 二分法
1.1 什么是二分查找
二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法,前提是数据结构必须先排好序,可以在数据规模的对数时间复杂度内完成查找。但是,二分查找要求线性表具有有随机访问的特点(例如数组),也要求线性表能够根据中间元素的特点推测它两侧元素的性质,以达到缩减问题规模的效果
二分查找是计算机科学中最基本、最有用的算法之一。 它描述了在有序集合中搜索特定值的过程。
二分查找中的经常使用的术语:
- 目标 Target:你要查找的值
- 索引 Index:你要查找的当前位置
- 左右指示符 Left,Right:用来确定查询空间范围的指标
- 中间指示符 Mid:用来确定接下来在左侧查找还是在右侧查找
1.2 如何识别二分法
二分查找是一种在每次查询比较之后,将查找空间一分为二的算法,查询时间复杂度通常为O(log2n)。相对于一般遍历算法性能高出很多,因此每次需要查找集合中的索引或者元素时,都应该考虑二分查找。如果集合原本是无序的,我们需要先进行排序然后再二分查找。
二分查找一般有三个主要部分组成:
- 预处理
如果待查找集合是未排序的,首先需要对其进行排序
- 二分查找
用循环或者递归在每一次比较之后,将查询空间一分为二
- 后处理
在剩余空间中确定可行的候选者
1.3 二分法模板
当我们第一次学会二分查找时,我们可能会挣扎。我们可能会在网上研究数百个二分查找问题,每次我们查看开发人员的代码时,它的实现似乎都略有不同。尽管每个实现在每个步骤中都会将问题空间划分为原来的 1/2,但其中有许多问题:
- 为什么执行方式略有不同?
- 开发人员在想什么?
- 哪种方法更容易?
- 哪种方法更好?
经过许多次失败的尝试并拉扯掉大量的头发后,我们找到了三个主要的二分查找模板。为了防止脱发,并使新的开发人员更容易学习和理解,我们在接下来一一介绍他们。
1.3.1 模板一
func binarySearch(nums []int, target int) int {
if nums == nil {
return -1
}
left, right := 0, len(nums)-1
for left <= right {
mid := left + (right-left)>>1
if nums[mid] == target {
return mid
} else if nums[mid] < target {
left = mid + 1
} else if nums[mid] > target {
right = mid - 1
}
}
//End Condition: left > right
return -1
}
此模板是二分查找最基础和最基本的形式,是一个标准的二分查找模板,要求背诵全文。
这里说明下mid的计算:
通常情况下mid = (left + right)/2。但是这存在溢出的可能性:
比如说left,right,mid都是uint8(一个字节),
left=100,
right=250,
left + right= 350
我们想要的是(left+ right)/2 = 175,但由于350这已经超过uint8的范围了,最后算出来的结果为47,溢出的情况下算出来的值是不准确。而使用下面的方法则不存在此问题,始终可以保证left <= mid <= right。
除此之外由于移位运算的性能高于乘除运算,因此这里我采用了右移来代替除以2的操作。
mid := left + (right-left)>>1
- 二分查找最基础和最基本的形式
- 查找添加可以在不与元素两侧进行比较的情况下确定
- 无需后处理过程,因为在每一步中都在检查是否找到元素。因此如果程序到达末尾,则说明未找到该元素。
- 初始条件: ```left=0, right=length-1```
- 终止 : ```left > right```
- 向左查找: ```right = mid – 1```
- 向右查找: ```left = mid + 1````
1.3.2 Lc69:x的平方根
- 题目描述
实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
- 示例
示例 1:
输入: 4
输出: 2
示例2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。
- 实现
Leetcode题的解法有很多中,比如该题Leetcode官方便给出了三种解决方法,二分法求解只是其中的一种,当然可能不是最优的解法(该题比较牛逼的解法是袖珍计算器法,将开方运算转换为指数+对数运算,数学上很强),但由于我们是为了学习二分法,因此这里使用二分法来求解。
func mySqrt(x int) int {
if x < 0 {
return -1
}
if x == 0 {
return 0
}
left, right := 1, x
for left <= right {
mid := left + (right-left)>>1
val := mid * mid
if val < x {
left = mid + 1
} else if val > x {
right = mid - 1
} else {
return mid
}
}
return right
}
关于为什么最后返回right,这里使用一张图进行说明:
- 复杂度分析
时间复杂度:O(log x),即为二分查找需要的次数。
空间复杂度:O(1)。
1.3.3Lc374:猜数大小
- 题目描述
规则如下:
- 每轮游戏,我都会从1到n随机选择一个数字。 请你猜选出的是哪个数字。
- 如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。
你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有 3 种可能的情况(-1,1 或 0):
- -1:我选出的数字比你猜的数字小 pick < num
- 1 :我选出的数字比你猜的数字大 pick > num
- 0 :我选出的数字和你猜的数字一样。恭喜!你猜对了!pick == num
返回我选出的数字。
- 示例
示例 1:
输入:n = 10, pick = 6
输出:6
示例 2:
输入:n = 1, pick = 1
输出:1
示例 3:
输入:n = 2, pick = 1
输出:1
示例 4:
输入:n = 2, pick = 2
输出:2
- 实现
func guessNumber(n int) int {
left, right := 1, n
for left <= right {
mid := left + (right-left)>>1
ret := guess(mid)
if ret == 1 {
left = mid + 1
} else if ret == -1 {
right = mid - 1
} else {
return mid
}
}
}
- 复杂度分析
时间复杂度:O(log n),即为二分查找需要的次数。
空间复杂度:O(1)。
1.3.4 Lc33:搜索旋转数组
- 题目描述
整数数组nums按升序排列,数组中的值互不相同。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标从0开始计数)。例如, [0,1,2,4,5,6,7] 在下标3处经旋转后可能变为[4,5,6,7,0,1,2] 。
给你旋转后的数组nums和一个整数target,如果nums中存在这个目标值 target ,则返回它的索引,否则返回 -1 。
- 示例
示例 1:
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
示例 2:
输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1
示例 3:
输入:nums = [1], target = 0
输出:-1
- 实现
要点:如果首先找到mid所在的左侧有序区间还是在右侧有序区间,在确定区间之后,根据target和mid的关系(直接判断有序序列,如果不在有序序列范围内,那只能在另一半空间)。
判断mid所在序列比较简单:
如果nums[mid] > nums[0], 则在左侧序列中
如果nums[mid] < nums[0], 则在右侧序列中
func search(nums []int, target int) int {
if nums == nil {
return -1
}
left, right := 0, len(nums)-1
for left <= right {
mid := left + (right-left)/2
if nums[mid] == target {
return mid
}
if nums[mid] >= nums[left] { //mid在左侧序列中
if nums[mid] > target && target >= nums[left] {
right = mid - 1
} else {
left = mid + 1
}
} else{ //mid在右侧序列中
if nums[mid] < target && target <= nums[right] {
left = mid + 1
} else {
right = mid - 1
}
}
}
return -1
}
- 复杂度分析
时间复杂度:O(logn),其中 n为nums 数组的大小。整个算法时间复杂度即为二分查找的时间复杂度O(logn)。
空间复杂度:O(1)。我们只需要常数级别的空间存放变量。
1.3.5 模板二
func binarySearch2(nums []int, target int) int {
if nums == nil {
return -1
}
left, right := 0, len(nums)
for left < right {
mid := left + (right-left)>>1
if nums[mid] < target {
left = mid + 1
} else {
right = mid
}
}
//End Condition: left == right
if left != len(nums)-1 && nums[left] == target {
return left
}
return left
}
该模板是二分查找的高级模板,它用于查找需要需要访问当前索引以及直接右邻居索引的情况。
举一个例子:在一个排序数字中,查找第一次出现n的索引(也可以极值、最值)。代码中判断条件根据不同情形有不同的形式。
- 二分查找的高级方法
- 查找条件需要访问元素的直接右邻居
- 使用元素的右邻居来确定是否满足条件,并决定是向左还是向右查找
- 保证查询空间的每一步至少有两个元素(left<right)
- 需要后续处理过程。因为循环体中每一步至少需要两个元素,因此最终只剩下一个元素时需要单独处理,确定是否满足条件。
- 初始条件: ```left=0, right=length```
- 终止 : ```left == right```
- 向左查找: ```right = mid```
- 向右查找: ```left = mid + 1````
1.3.6 Lc278:第一个错误版本
- 题目描述
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用bool isBadVersion(version)接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
简单的概括下:在数组中,第一次出现x的下标
- 示例
给定 n = 5,并且 version = 4 是第一个错误的版本。
调用 isBadVersion(3)-> false
调用 isBadVersion(5)-> true
调用 isBadVersion(4)-> true
所以,4 是第一个错误的版本。
- 解法
func firstBadVersion(n int) int {
if n < 1 {
return 0
}
left, right := 1, n
for left < right {
mid := left + (right-left)>>1
if isBadVersion(mid) {
right = mid
} else {
left = mid + 1
}
}
return right
}
- 复杂度分析
时间复杂度:O(logn),整个算法时间复杂度即为二分查找的时间复杂度O(logn)。
空间复杂度:O(1)。
1.3.7Lc162:寻找峰值
- 题目描述
峰值元素是指其值大于左右相邻值的元素。给你一个输入数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞ 。
- 示例
示例 1:
输入:nums = [1,2,3,1]
输出:2
解释:3 是峰值元素,你的函数应该返回其索引 2。
示例 2:
输入:nums = [1,2,1,3,5,6,4]
输出:1 或 5
解释:你的函数可以返回索引 1,其峰值元素为 2;或者返回索引 5, 其峰值元素为 6。
- 代码实现
这道题如果说使用二分法可能没有什么思路,后来看了官方题解,才明白过来。这里做一个说明:
这道题可以分为3中情况分别进行分析:单调递增、单调递减、两个组合。如下图所示
而使用二分法的核心便是确定mid所处的区间:递增区间或者递减区间。如果为递增区间,即mid右面一定有一个峰值;如果在递减区间,则在mid左面一定有一个峰值。(题外话:::忽然想到了高数中罗尔中值定理:闭区间连续,开区间可导,端点值相等,导数为零。而导数为零的点就是其中一个极值点)。为什么这么肯定呢?因为题目中假设nums[-1] = nums[n] = -∞,因此上述结论成立,而二分法要做的就是逐步逼近一个峰值点。
func findPeakElement(nums []int) int {
if nums == nil {
return -1
}
left, right := 0, len(nums)-1
for left < right {
mid := left + (right-left)>>1
if nums[mid] < nums[mid+1] {
left = mid + 1
} else {
right = mid
}
}
return left //right is also ok
}
这里right=len(nums)-1,并不是模板中的len(nums).除此之外并没有单独判断只剩一个元素的情况。我们还是要使用马克思主义的精髓:具体问题具体分析
- 复杂度分析
时间复杂度:O(logn)
空间复杂度:O(1)。
1.3.8 Lc153:寻找旋转排序数组最小值
- 题目描述
假设按照升序排序的数组在预先未知的某个点上进行了旋转。例如,数组[0,1,2,4,5,6,7] 可能变为[4,5,6,7,0,1,2] 。
请找出其中最小的元素。
提示:
- 1 <= nums.length <= 5000
- -5000 <= nums[i] <= 5000
- nums 中的所有整数都是 唯一 的
- nums 原来是一个升序排序的数组,但在预先未知的某个点上进行了旋转
- 示例
示例 1:
输入:nums = [3,4,5,1,2]
输出:1
示例 2:
输入:nums = [4,5,6,7,0,1,2]
输出:0
示例 3:
输入:nums = [1]
输出:1
- 代码实现
func findMin(nums []int) int {
if nums == nil {
return 0
}
n := len(nums)
if n == 1 || nums[0] < nums[n-1] {
return nums[0]
}
left, right := 0, n-1
for left < right {
mid := left + (right-left)>>1
if nums[mid] > nums[right] {
left = mid + 1
} else {
right = mid
}
}
return nums[left]
}
- 复杂度分析
时间复杂度:O(logn)
空间复杂度:O(1)。
1.3.9Lc154:寻找旋转排序数组最小值II
- 题目描述
假设按照升序排序的数组在预先未知的某个点上进行了旋转。(例如,数组[0,1,2,4,5,6,7]可能变为[4,5,6,7,0,1,2])。
请找出其中最小的元素。
注意数组中可能存在重复的元素。
说明:
这道题是“寻找旋转排序数组中的最小值”的延伸题目。
允许重复会影响算法的时间复杂度吗?会如何影响,为什么?
- 示例
示例 1:
输入:nums = [1,3,5]
输出:1
示例 2:
输入:nums = [2,2,2,0,1]
输出:0
- 代码实现
说明:153与154区别在于154允许使用重复元素,这会使情况变得复杂些:
此时153的解法便不再适用。需要特别处理nums[mid]==nums[right]的情况,因为最小值在right右边,因此right一步一步向左逼近。
func findMin(nums []int) int {
n := len(nums)
if n == 1 {
return nums[0]
}
left, right := 0, n-1
for left < right {
mid := left + (right-left)>>1
if nums[mid] > nums[right] {
left = mid + 1
} else if nums[mid] < nums[right] {
right = mid
} else {
right--
}
}
return nums[left]
}
- 复杂度分析
时间复杂度:O(logn)
空间复杂度:O(1)。
1.3.10 模板三
关于模板三,平常使用的比较少,基本使用模板一二就可以搞定,Leetcode官网上给出了这种方案,但是没有给出此模板实现代码。我是用的Java模板转换过来的。由于官方题解中目前还没有看到使用此模板的解法,例子中只是自己的实现,没有完全参考模板,请选择性阅读。
- 模板代码
int binarySearch(nums []int, target int) {
if (nums == nil || len(nums) == 0)
return -1;
left, right := 0, len(nums)- 1;
for left + 1 < right{
// Prevent (left + right) overflow
int mid = left + (right - left) >> 1;
if nums[mid] == target {
return mid;
} else if nums[mid] < target {
left = mid;
} else {
right = mid;
}
}
// Post-processing:
// End Condition: left + 1 == right
if nums[left] == target return left;
if nums[right] == target return right;
return -1;
}
- 关键属性
- 实现二分查找的另一种方法。
- 搜索条件需要访问元素的直接左右邻居。
- 使用元素的邻居来确定它是向右还是向左。
- 保证查找空间在每个步骤中至少有 3 个元素。
- 需要进行后处理。当剩下2个元素时,循环/递归结束。需要评估其余元素是否符合条件。
- 语法说明
- 初始条件: ```left=0, right=length - 1```
- 终止 : ```left == right - 1```
- 向左查找: ```right = mid```
- 向右查找: ```left = mid````
1.3.11 LC-34:在排序数组中查找元素的第一个和最后一个
- 题目描述
给定一个按照升序排列的整数数组 nums,和一个目标值target。找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值target,返回[-1, -1]。
进阶:
你可以设计并实现时间复杂度为O(log n) 的算法解决此问题吗?
- 示例
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
示例 3:
输入:nums = [], target = 0
输出:[-1,-1]
- 实现
func searchRange(nums []int, target int) []int {
if nums == nil {
return nil
}
left, right := 0, len(nums)-1
for left <= right {
mid := left + (right-left)>>1
if nums[mid] == target {
right = mid
left = mid
for left > 0 && nums[left-1] == nums[left] {
left--
}
for right < len(nums)-1 && nums[right+1] == nums[right] {
right++
}
return []int{left, right}
} else if nums[mid] < target {
left = mid + 1
} else if nums[mid] > target {
right = mid - 1
}
}
return []int{-1, -1}
}
说明:
实现过程中,在找到目标target情况下,不再使用二分法,而是直接向左向右遍历找到第一个和最后一个出现的位置。之前看到过完全使用二分法的实现,在,完全可以参考模板二中的LC278代码实现两个函数,分别用来查询第一个和最后一个target位置。
- 复杂度分析
时间复杂度:log(n)
空间复杂度:log(1)
1.3.12LC-658:找到K个最接近的元素
- 题目描述
给定一个排序好的数组arr,两个整数k和x,从数组中找到最靠近x(两数之差最小)的k个数。返回的结果必须要是按升序排好的。
整数a比整数b更接近x需要满足:
|a - x| < |b - x| 或者
|a - x| == |b - x| 且 a < b
- 示例
示例 1:
输入:arr = [1,2,3,4,5], k = 4, x = 3
输出:[1,2,3,4]
示例 2:
输入:arr = [1,2,3,4,5], k = 4, x = -1
输出:[1,2,3,4]
- 代码实现
刷题的过程中写了两种方法,除此之外,在网上题解中看到另外一种二分法解题思路,很简洁,因此也会将其收录下来学习下。
- 二分法+双指针
- 双指针
- 二分法
下面分别给出三种实现方式:
二分法+双指针
func findClosestElements2(arr []int, k int, x int) []int {
n := len(arr)
if n < k {
return nil
}
if arr[0] > x {
return arr[:k] /*左闭右开*/
}
if arr[n-1] < x {
return arr[n-k:]
}
left, right := 0, n-1
for left+1 < right {
mid := left + (right-left)>>1
if arr[mid] > x {
right = mid
} else if arr[mid] < x {
left = mid
} else {
break
}
}
lk, rk := 0, 0
if left+1 == right { /*x不存在, left<x<right*/
lk, rk = left-k+1, right+k-1
} else { //x存在
mid := left + (right-left)>>1
lk, rk = mid-k+1, mid+k-1
}
if lk < 0 {
lk = 0
}
if rk > n-1 {
rk = n - 1
}
for lk+k-1 < rk {
if x-arr[lk] <= arr[rk]-x {
rk--
} else {
lk++
}
}
return arr[lk : rk+1]
}
自己的二分法+双指针代码实现比较啰嗦,除此之外也尝试了下将这者完全融合成一段代码实现,但是非常遗憾,水平有限并没有成功。
双指针
双指针解法也是比较容易理解的。从数组两端分别开始遍历,将里目标值x比较远的元素去除,循环迭代直到长度满足要求为止。代码实现也比较简单,时间复杂度为O(n),空间复杂度为O(1)。当元素数量特别多时,不如二分法效率高。
func findClosestElements(arr []int, k int, x int) []int {
n := len(arr)
if n < k {
return nil
}
if arr[0] > x {
return arr[:k] /*左闭右开*/
}
if arr[n-1] < x {
return arr[n-k:]
}
//{1, 2, 3, 4, 5}, 4, 3)
left, right := 0, n-1
for left+k-1 < right {
if x-arr[left] <= arr[right]-x {
right--
} else {
left++
}
}
//End Condition: left+k-1 == right
return arr[left : right+1]
}
二分法
这个二分法实现虽然仍然不同于模板三,但是比较接近,同时很简洁,非常值得学习一下。(解题思路:二分查找左边界的开始,注意不是查找区间,而是查找正确区间的左值)
func findClosestElements(arr []int, k int, x int) []int {
start := 0
end := len(arr) - k
for start < end {
mid := start + (end-start)/2
if x-arr[mid] > arr[mid+k]-x {
start = mid + 1
} else {
end = mid
}
}
return arr[start : start+k]
}
时间复杂度:log(n)
空间复杂度:log(1)
1.4小结
很多二分查找问题都归结于这三种模板中的一个,有一些问题也可以使用多个模板进行解决(比如模板三种的例子,我都是其他其他模板解决的)。三个模板的主要差别在于:
- 左右中索引的分配
- 循环或者递归终止条件不同
- 后续处理的必要性(做题时很多根本不需要后续处理)
模板 #1 (left <= right)
- 二分查找的最基础和最基本的形式。
- 查找条件可以在不与元素的两侧进行比较的情况下确定(或使用它周围的特定元素)。
- 不需要后处理,因为每一步中,你都在检查是否找到了元素。如果到达末尾,则知道未找到该元素。
模板 #2 (left < right)
- 一种实现二分查找的高级方法。
- 查找条件需要访问元素的直接右邻居。
- 使用元素的右邻居来确定是否满足条件,并决定是向左还是向右。
- 保证查找空间在每一步中至少有 2 个元素。
- 需要进行后处理。 当你剩下 1 个元素时,循环 / 递归结束。 需要评估剩余元素是否符合条件。
模板 #3 (left + 1 < right)
- 实现二分查找的另一种方法。
- 搜索条件需要访问元素的直接左右邻居。
- 使用元素的邻居来确定它是向右还是向左。
- 保证查找空间在每个步骤中至少有 3 个元素。
- 需要进行后处理。 当剩下 2 个元素时,循环 / 递归结束。 需要评估其余元素是否符合条件。
模板一 |
在有序序列中查找某一个数 |
模板二 |
在有序序列中寻找第一次出现的数(修改后也可以最后一次) |
模板三 |
在有序序列中查询最值 |
我整理的是Word版本的,但是Word到MD格式全乱了,如果有需要word版本的,欢迎留言。Word版本内容持续更新中
LeetCode刷题模板(1):《我要打10个》之二分法的更多相关文章
- LeetCode刷题总结-树篇(中)
本篇接着<LeetCode刷题总结-树篇(上)>,讲解有关树的类型相关考点的习题,本期共收录17道题,1道简单题,10道中等题,6道困难题. 在LeetCode题库中,考察到的不同种类的树 ...
- 看完互联网大佬的「LeetCode 刷题手册」, 手撕了 400 道 Leetcode 算法题
大家好,我是 程序员小熊 ,来自 大厂 的程序猿.相信绝大部分程序猿都有一个进大厂的梦想,但相较于以前,目前大厂的面试,只要是研发相关岗位,算法题基本少不了,所以现在很多人都会去刷 Leetcode ...
- LeetCode刷题专栏第一篇--思维导图&时间安排
昨天是元宵节,过完元宵节相当于这个年正式过完了.不知道大家有没有投入继续投入紧张的学习工作中.年前我想开一个Leetcode刷题专栏,于是发了一个投票想了解大家的需求征集意见.投票于2019年2月1日 ...
- leetcode 刷题进展
最近没发什么博客了 凑个数 我的leetcode刷题进展 https://gitee.com/def/leetcode_practice 个人以为 刷题在透不在多 前200的吃透了 足以应付非算法岗 ...
- LeetCode刷题指南(字符串)
作者:CYC2018 文章链接:https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Leetcode+%E9%A2%98%E8%A7% ...
- leetcode刷题记录--js
leetcode刷题记录 两数之和 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但 ...
- LeetCode刷题总结之双指针法
Leetcode刷题总结 目前已经刷了50道题,从零开始刷题学到了很多精妙的解法和深刻的思想,因此想按方法对写过的题做一个总结 双指针法 双指针法有时也叫快慢指针,在数组里是用两个整型值代表下标,在链 ...
- Leetcode刷题记录(python3)
Leetcode刷题记录(python3) 顺序刷题 1~5 ---1.两数之和 ---2.两数相加 ---3. 无重复字符的最长子串 ---4.寻找两个有序数组的中位数 ---5.最长回文子串 6- ...
- LeetCode刷题总结-数组篇(上)
数组是算法中最常用的一种数据结构,也是面试中最常考的考点.在LeetCode题库中,标记为数组类型的习题到目前为止,已累计到了202题.然而,这202道习题并不是每道题只标记为数组一个考点,大部分习题 ...
随机推荐
- 电脑软件安装过程文档.BA
MD 01-打印并阅读-电脑软件安装过程文档.BAT-即此批处理脚本文档MD 02-阅读-电脑软件安装经验教训文档.DOCX-MD 03-制作-杏雨梨云USB维护系统2019中秋版之国庆更新-可启动U ...
- Maven-内部多个项目依赖自动升级版本的部署
需要自动升级版本的AAA项目发布 (有内部依赖时) 步骤比较复杂, 有一些需要根据实际情况调整. 考虑了以下几种可能性: 依赖模块的版本有更新 依赖模块版本没更新 依赖模块的版本号: 直接定义, 用属 ...
- JVM 内存分配、调优案例
内存分配 对象优先在Eden区分配 大多数情况下,对象在新生代Eden区中分配.当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC. HotSpot虚拟机提供了-XX:+PrintG ...
- postman之断言
1 (状态码断言)和(返回内容断言)
- 跟我一起写 Makefile(十)
四.foreach 函数 foreach函数和别的函数非常的不一样.因为这个函数是用来做循环用的,Makefile中的foreach函数几乎是仿照于Unix标准Shell(/bin/sh)中的for语 ...
- 加载GIF图片优化方案
前言 许多项目需要加载GIF图片,但是在直接使用UIImageView加载存在许多问题,于是查找资料做了一个加载GIF的Demo,思路来源. 思路 使用FLAnimatedImage来加载GIF图片, ...
- noip13
T1 一开始直接丢了个暴力走人50pts,然后开始打表找规律,啥也没找着,最后二十分钟突然看出来了什么,把 \(f_{n,m}\)式子列了一下,发现常数项没啥规律,最后五分钟,突然闪过一丝灵感,但是是 ...
- 带你读AI论文丨LaneNet基于实体分割的端到端车道线检测
摘要:LaneNet是一种端到端的车道线检测方法,包含 LanNet + H-Net 两个网络模型. 本文分享自华为云社区<[论文解读]LaneNet基于实体分割的端到端车道线检测>,作者 ...
- EZpop分析
首先源代码如下 <?php class Modifier { protected $var; public function append($value){ include($value); } ...
- C#中的几种锁:用户模式锁、内核模式锁、动态计数、监视锁
参考网址: https://blog.csdn.net/weixin_43989331/article/details/105356008 C#中的几种锁:用户模式锁.内核模式锁.动态计数.监视锁介绍 ...