文章目录

  • 题目
  • 思路
    • 如何建立左右区间?
    • 如何查找最高点?
    • 那我们怎么判断 `num` 到底处于什么样的位置呢?
    • 如何确定插入位置?
    • 插入元素
  • 代码

题目

给一个只循环递增一次的数组 res,res 满足首元素大于等于尾元素,形如:

4,5,6,7,2,4

再给出一个整型数字 num,将其插入到数组中应在的位置。

示例:

输入:

res = 4,5,6,7,2,4
num = 3

输出:

4,5,6,7,2,3,4


思路

用二分查找确定应该插入的位置,难点在于左右区间的建立。

如何建立左右区间?

首先明确两点,对于整个数组而言:

  • 首元素一定 大于等于 尾元素
  • 以数组的最大值为界限,最大值左边的元素一定 大于等于 右边的元素

用图像表示数组是这样的(黑色表下标,紫色表值):

我们可以看到,要插入的元素无非在最高点的左边或右边(自下文始,最高点用high替代,首元素位置用begin表示,尾元素位置用last表示):

  • num 处于最高点左边时,二分查找的范围应该是 [begin, high]
  • num 处于最高点右边时,二分查找的范围应该是 [high+1,last]

也就是说,划定二分查找范围(左右区间的建立)的重中之重在于最高点的确定。

如何查找最高点?

个人想到两种方法:

  • 遍历查找,时间复杂度O(n)

算法思想没有什么多说的,中规中矩的遍历。

int high = 0;
for (int i = 1; i < res.size(); i++) {if (res[high] > res[i]) {break;}high = i;
}
  • 二分查找,时间复杂度O(log2n)

算法思想是:

  1. 先以数组首元素、尾元素作为二分查找的左右边界,中间元素暂定为high
  2. 左边界小于右边界 作为while的循环条件
  3. 首先判断此时的high是否大于首元素
  4. 大于首元素证明此时的high处于 真正最高点的左边就是真正最高点,此时需要判定high+1中元素和high中元素之间的关系:
  1. 如果high+1中元素大于high中元素,表明 真正最高点应该在high的左边,因此更新左边界—— left = high + 1
  2. 如果high+1中元素小于high中元素,表明 high即为真正最高点 ,因此break出while循环即可
  1. 小于首元素证明此时的high处于 真正最高点的右边 ,此时需要判定high和high-1所指元素之间的关系:
  1. 如果 res[high - 1] < res[high] (如举例中high=6时,4>3),表明最高点仍在 high-1的左边,也就是high-1也处于真正最高点的右边,因此要更新右边界—— right = high - 2
  2. 如果 res[high - 1] > res[high] , 此时表明high-1即为最高点,因此将high–并break出while循环即可
  1. 每次循环更新完左右边界之后需要更新high值—— high = left + (right - left) / 2;
  2. 跳出while循环得到的high即为最高点的位置
int size = res.size() - 1;
int left = 0;
int right = size;
int high = left + (right - left) / 2;
int flag = res[0];
while (left < right) {if (res[high] >= flag) {if (res[high + 1] > res[high]) {left = high + 1;}else {break;}}else {if (res[high - 1] < res[high]) {right = high - 2;}else {high--;break;}}high = left + (right - left) / 2;
}

那我们怎么判断 num 到底处于什么样的位置呢?

这时应该结合之前我们说到的一句话:

首元素一定 大于等于 尾元素

那我们做个归纳,如果:

  1. num > res[0] ,num 处于 high 左边
  2. res[end] < num == res[0] ,num 处于 high 右边,插入到尾元素的位置
  3. res[end] == num == res[0] ,不可能出现这种情况,因为这种情况下num没有位置可以插入。
  4. res[end] == num < res[0] ,num 处于 high 左边,插入到首元素的位置
  5. res[end] > num ,num 处于 high 右边

第二点和第四点是什么意思呢?

关于第二点,我们举这样一个例子:

输入:

res = 5,6,7,2,4
num = 5

输出:

res = 5,6,7,2,4,5

关于第四点,我们举这样一个例子:

输入:

res = 6,7,2,4,5
num = 5

输出:

res = 5,6,7,2,4,5

因此根据上面的归纳我们可以得到代码:

注意:因为第三种情况不可能出现,因此我们在描述第2、4种情况时可以省略大小比较,因为当2、4种描述的等于关系成立时,大小关系必然成立。

if (res[size] > num || num == res[0]) { // num处于high右边left = high + 1;right = size;
}
if(num > res[0] || num == res[size]) { // num处于high左边left = 0;right = high;
}

如何确定插入位置?

建立好左右边界后就可以根据二分查找来确定插入位置了。

  1. 当左边界小于右边界时执行二分查找。
  2. 中间点(mid)对应的元素小于 num 时,左边界更改为 mid+1
  3. mid 对应的元素大于 num 时,右边界更改为 mid-1
int mid = left + (right - left) / 2;
while (left <= right)
{if (res[mid] < num) {left = mid + 1; }else {right = mid - 1;}mid = left + (right - left) / 2;
}

插入元素

最终使用insert函数进行插入:

res.insert(res.begin() + mid, num);

insert会将给定值插入到给定位置之前。


代码

class Solution {public:vector<int> fun(vector<int> res, int num) {int size = res.size() - 1;int left = 0;int right = size;/*int high = 0;for (int i = 1; i < res.size(); i++) {if (res[high] > res[i]) {break;}high = i;}*/// 与上面注释部分一样都是查最高点int high = left + (right - left) / 2;int flag = res[0];while (left < right) {if (res[high] > flag) {if (res[high + 1] > res[high]) {left = high + 1;}else {break;}}else {if (res[high - 1] < res[high]) {right = high - 2;}else {high--;break;}}high = left + (right - left) / 2;}// 确定左右边界if (res[size] > num || num == res[0]) { // num处于high右边left = high + 1;right = size;}if(num > res[0] || num == res[size]) { // num处于high左边left = 0;right = high;} // 确定插入位置int mid = left + (right - left) / 2;while (left <= right){if (res[mid] < num) {left = mid + 1; }else {right = mid - 1;}mid = left + (right - left) / 2;} res.insert(res.begin() + mid, num);return res;}
};

用例测试:

int main() {Solution s;vector<int> iv = { 4,5,6,7,1,2,4 };int num = 3;iv = s.fun(iv, num);for (auto i = iv.begin(); i != iv.end(); i++) {cout << *i << " ";}cout << endl;
}

在循环递增一次的数组中插入元素相关推荐

  1. java向数组中插入元素

    /*** * @Title: test_insert_array* @Description: 该方法的主要作用:像数组中插入元素* @param 设定文件 * @return 返回类型:void * ...

  2. 向一个数组中插入元素

    向一个数组中插入元素是平时很常见的一件事情.你可以使用push在数组尾部插入元素,可以用unshift在数组头部插入元素,也可以用splice在数组中间插入元素. 但是这些已知的方法,并不意味着没有更 ...

  3. 有序数组中插入元素依然保持有序

    有序数组中插入元素依然保持有序 如何在一个有序数组中插入元素,使得数组依然保持有序,废话不多说直接上代码(C/C++) 如何在一个有序数组中插入元素,使得数组依然保持有序,废话不多说直接上代码(C/C ...

  4. Java数组中插入元素

    **问题:Java中如何向一个已经升序排序好的数组中插入元素,得到的数组依然是升序数组 效果: int[] array = {1,3,7,12,24,36,48}; 插入数字9后新数组为 int[] ...

  5. java 数组中插入元素_Java数组添加元素

    java 数组中插入元素 How to add elements to an array in java We know that java array size is fixed, so we ca ...

  6. Swift for循环:用于索引,数组中的元素?

    本文翻译自:Swift for loop: for index, element in array? Is there a function that I can use to iterate ove ...

  7. C++数组中插入元素。

    问题: 在已经排序的数组中插入一个数,插入后的数组仍是有序的. 为了简化问题,将顺序规定为升序数组类型为double. 插入函数的代码如下: //将data插入到数组arr中,使插入后仍是升序. vo ...

  8. vb excel 连续多个值赋值_VB实现向数组中插入元素

    爱学习,更爱VB编程 大家好,数组在编程中应用广泛.在各种编程语言中,数组都占据非常重要的地位,所以熟练应用数组去解决程序中的问题就显得尤为必要了. 今天,我们共同来学习如何把一个元素插入到数组中. ...

  9. C语言,往排好序的数组中插入元素

    例题:有一个已经排好序的数组,元素分别是:1,3,5,7,9,从键盘上输入一个元素,将这个元素插入到数组中,使数组仍保持从小到大排序. 输出时各元素的最小宽度为5. 例: (1)输入:0  输出:   ...

最新文章

  1. JavaScript 学习笔记— —类型判断
  2. laravel+vue.js的学习以及为什么浏览器中要有井号“#”
  3. 前后端传递时间参数偶遇参数类型转换异常
  4. 登录多实例MySQL失败,修改密码临时解决,原因不明
  5. 扩展控件--NumberTextBox
  6. JavaScript基础学习(二)—JavaScript基本概念
  7. 最近一段时间遇到的费了时间的问题
  8. 分支程序设计02 - 零基础入门学习C语言11
  9. 深入浅出 python epub_《机器学习从认知到实践(第2辑)(套装共3册,Python+TensorFlow)》epub+mobi+azw3...
  10. 2017IEC计算机第二次作业
  11. 斯坦福首位华人女院长,“人造皮肤”赋予机器和残疾人触觉
  12. 阿里云高级专家王林平:云数据库的运维体系构建
  13. 基于3D技术的机器视觉解决方案
  14. Mac配置OpenGL环境
  15. 远程桌面系统管理员以限制你登入计算机,windows远程连接时:系统管理员已经限制你可以使用的登录类型(网络或交互式)解决办法...
  16. exlsx表格教程_excel表格格式刷的使用教程详解
  17. windows下远程连接Mysql
  18. 从苹果创业神话看资本运营应集中优势兵力
  19. [leetcode]剑指offer(C++版题解)
  20. ECCV 2022开奖!清华、浙大校友斩获最佳论文奖

热门文章

  1. python正则表达式group用法_【Python】正则表达式用法
  2. vue v-if判断数组元素的值_Vue项目上线做的一些基本优化
  3. access vba代码大全_VBA 实践指南 -- VBA连接各种数据库
  4. c语言学籍管理系统小程序,学籍业务办理系统(开源 v2.0发布 优化代码,增加小程序端)...
  5. c语言链表复数实验,数据结构实验—复数计算器 大神提意见
  6. datagridview 当前上下文中不存在bind_全面解析JavaScript中this指向问题
  7. DMA及cache一致性的学习心得
  8. linux+qt+定时精度,Qt QTimer测试定时精度
  9. C#的变迁史10 - C# 5.0 之其他增强篇
  10. 第六节:深入研究Task实例方法ContinueWith的参数TaskContinuationOptions