22
33https://leetcode-cn.com/problems/search-insert-position/
44
5+ > 二分查找法是数组里的常用方法,彻底掌握它是十分必要的。
6+
7+ # 编号35:搜索插入位置
8+
9+ 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
10+
11+ 你可以假设数组中无重复元素。
12+
13+ 示例 1:
14+ 输入: [ 1,3,5,6] , 5
15+ 输出: 2
16+
17+ 示例 2:
18+ 输入: [ 1,3,5,6] , 2
19+ 输出: 1
20+
21+ 示例 3:
22+ 输入: [ 1,3,5,6] , 7
23+ 输出: 4
24+
25+ 示例 4:
26+ 输入: [ 1,3,5,6] , 0
27+ 输出: 0
28+
529# 思路
630
7- 这道题目其实是一道很简单的题 ,但是为什么通过率相对来说并不高呢,我理解是大家对 边界处理的判断有所失误,导致的 。
31+ 这道题目不难 ,但是为什么通过率相对来说并不高呢,我理解是大家对边界处理的判断有所失误导致的 。
832
9- 这道题目,我们要在数组中插入目标值 ,无非是这四种情况
33+ 这道题目,要在数组中插入目标值 ,无非是这四种情况。
1034
1135<img src =' ../pics/35_搜索插入位置3.png ' width =600 > </img ></div >
1236
@@ -15,14 +39,15 @@ https://leetcode-cn.com/problems/search-insert-position/
1539* 目标值插入数组中的位置
1640* 目标值在数组所有元素之后
1741
18- 这四种情况确认清楚了,我们就可以尝试解题了
42+ 这四种情况确认清楚了,就可以尝试解题了。
1943
20- 暴力解题 不一定时间消耗就非常高,关键看实现的方式,就像是二分查找时间消耗不一定就很低,是一样的 。
44+ 接下来我将从暴力的解法和二分法来讲解此题,也借此好好讲一讲二分查找法 。
2145
22- 这里我给出了一种简洁的暴力解法,和两种二分查找的解法
46+ ## 暴力解法
2347
48+ 暴力解题 不一定时间消耗就非常高,关键看实现的方式,就像是二分查找时间消耗不一定就很低,是一样的。
2449
25- # 解法:暴力枚举
50+ ## 暴力解法C++代码
2651
2752```
2853class Solution {
@@ -42,50 +67,55 @@ public:
4267 }
4368};
4469```
45- 效率如下:
46- <img src =' ../pics/35_搜索插入位置.png ' width =600 > </img ></div >
4770
48- 时间复杂度:O(n)
71+ 时间复杂度:O(n)
4972时间复杂度:O(1)
5073
74+ 效率如下:
75+
76+ <img src =' ../pics/35_搜索插入位置.png ' width =600 > </img ></div >
5177
52- # 二分法
78+ ## 二分法
5379
54- 既然暴力解法的时间复杂度是On,我们就要尝试一下使用二分查找法 。
80+ 既然暴力解法的时间复杂度是O(n),就要尝试一下使用二分查找法 。
5581
5682<img src =' ../pics/35_搜索插入位置4.png ' width =600 > </img ></div >
5783
58- 大家注意这道题目的前提是数组是有序数组,这也是使用二分查找的基础条件
84+ 大家注意这道题目的前提是数组是有序数组,这也是使用二分查找的基础条件。
5985
6086以后大家** 只要看到面试题里给出的数组是有序数组,都可以想一想是否可以使用二分法。**
6187
6288同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下表可能不是唯一的。
6389
64- 大体讲解一下二分法的思路,这里来举一个例子,例如在这个数组中,我们使用二分法寻找元素为5的位置 ,并返回其下标
90+ 大体讲解一下二分法的思路,这里来举一个例子,例如在这个数组中,使用二分法寻找元素为5的位置 ,并返回其下标。
6591
6692<img src =' ../pics/35_搜索插入位置5.png ' width =600 > </img ></div >
6793
68- 二分查找涉及的很多的边界条件,逻辑比较简单,就是写不好
94+ 二分查找涉及的很多的边界条件,逻辑比较简单,就是写不好。
95+
96+ 相信很多同学对二分查找法中边界条件处理不好。
6997
70- 相信很多同学对二分查找法中边界条件处理不好,例如 到底是 小于 还是 小于等于, 到底是+1 呢,还是要-1呢
98+ 例如到底是 ` while(left < right) ` 还是 ` while(left <= right) ` , 到底是` right = middle ` 呢,还是要` right = middle - 1 ` 呢?
7199
72- 这是为什么呢,主要是 ** 我们对区间的定义没有想清楚,这就是我们的不变量 **
100+ 这里弄不清楚主要是因为 ** 对区间的定义没有想清楚,这就是不变量 ** 。
73101
74- 我们要在二分查找的过程中 ,保持不变量,这也就是** 循环不变量** (感兴趣的同学可以查一查)
102+ 要在二分查找的过程中 ,保持不变量,这也就是** 循环不变量** (感兴趣的同学可以查一查)。
75103
76104## 二分法第一种写法
77105
78- 以这道题目来举例,以下的代码中我们定义 target 是在一个在左闭右闭的区间里,也就是[ left, right]
106+ 以这道题目来举例,以下的代码中定义 target 是在一个在左闭右闭的区间里,** 也就是[ left, right] (这个很重要)** 。
107+
108+ 这就决定了这个二分法的代码如何去写,大家看如下代码:
79109
80- 这就决定了我们 这个二分法的代码如何去写,大家看如下代码
110+ ** 大家要仔细看注释,思考为什么要写while(left <= right), 为什么要写right = middle - 1 ** 。
81111
82112```
83113class Solution {
84114public:
85115 int searchInsert(vector<int>& nums, int target) {
86116 int n = nums.size();
87117 int left = 0;
88- int right = n - 1; // 我们定义target在左闭右闭的区间里 ,[left, right]
118+ int right = n - 1; // 定义target在左闭右闭的区间里 ,[left, right]
89119 while (left <= right) { // 当left==right,区间[left, right]依然有效
90120 int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
91121 if (nums[middle] > target) {
@@ -105,27 +135,29 @@ public:
105135 }
106136};
107137```
108- 时间复杂度:O(logn)
138+ 时间复杂度:O(logn)
109139时间复杂度:O(1)
110140
111141效率如下:
112142<img src =' ../pics/35_搜索插入位置2.png ' width =600 > </img ></div >
113143
114144## 二分法第二种写法
115145
116- 如果说我们定义 target 是在一个在左闭右开的区间里,也就是[ left, right)
146+ 如果说定义 target 是在一个在左闭右开的区间里,也就是[ left, right) 。
117147
118148那么二分法的边界处理方式则截然不同。
119149
120150不变量是[ left, right)的区间,如下代码可以看出是如何在循环中坚持不变量的。
121151
152+ ** 大家要仔细看注释,思考为什么要写while (left < right), 为什么要写right = middle** 。
153+
122154```
123155class Solution {
124156public:
125157 int searchInsert(vector<int>& nums, int target) {
126158 int n = nums.size();
127159 int left = 0;
128- int right = n; // 我们定义target在左闭右开的区间里 ,[left, right) target
160+ int right = n; // 定义target在左闭右开的区间里 ,[left, right) target
129161 while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间
130162 int middle = left + ((right - left) >> 1);
131163 if (nums[middle] > target) {
@@ -146,11 +178,17 @@ public:
146178};
147179```
148180
149- 时间复杂度:O(logn)
181+ 时间复杂度:O(logn)
150182时间复杂度:O(1)
151183
152- ## 总结
153- 希望通过这道题目 ,可以帮助大家对二分法有更深的理解
184+ # 总结
185+
186+ 希望通过这道题目,大家会发现平时写二分法,为什么总写不好,就是因为对区间定义不清楚。
187+
188+ 确定要查找的区间到底是左闭右开[ left, right),还是左闭又闭[ left, right] ,这就是不变量。
189+
190+ 然后在** 二分查找的循环中,坚持循环不变量的原则** ,很多细节问题,自然会知道如何处理了。
191+
154192
155193> 更过算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。
156194
0 commit comments