数组进行多少次OP操作,才能有序

1 题目描述:

有一个数组:2,1,4,3。对于数组,有一种操作op(idx):将该index对应的数字移到首位。比如:

op(3):  2 1 43 -> 3 2 1 4

op(1):  3 2 14 -> 2 3 1 4

op(2):  2 3 1 4 -> 1 2 3 4

问对于给定的数组,数组各个元素是任意的整数,可能有重复值,需要多少次OP操作,才能使得数组有序?

对于上面的例子,需要3次即可。

2. 问题解析:

最坏的情况需要 n 次就够了,第 i 次找到数组中倒数第 i 大的数,然后进行OP操作,最后一定会使得该数组是有序的。

但是要最少几次,如何解决?

2.1 时间:O(n^2)  空间:O(1)

对于 2 1 4 3,4肯定不需要OP,接下来对于3,必须要OP,变成了 3 2 1 4。如果3进行OP了,那么其他小于3的数(1,2)都需要进行OP的,否则不能跑到 3 的前面去。

再比如 2 1 6 3 7 5 4, 发现7、6都需要OP,而从 5 开始需要进行OP了,那么答案就是所有<=5 的数了。这种算法需要能找到 2 1 6 3 7 5 4 中 递增序列6, 7. 复杂度是O(n^2),空间复杂度是O(1)。

2.2 时间:O(n) 空间:O(1)

8 6 5 7 9 5 4

目标:找到最大的数、第二大的数、第三大的数,且最大的数在最后,其他几位数依次在前面。比如

8 6 5 7 9 5 4 ->8 6 5 7 9 5 4

5 2 1 6 3 7 0 4 ->5 2 1 6 3 7 0 4

3 4 8 10 8 -> 3 4 8 10 8 (这种情况下只能是10,因为8出现2次,其中1次还在10后面,因此排除8)

当找到这个递增序列后,比如:5 2 1 6 3 7 0 4->5 2 1 6
3 7 0 4。 那么我知道4一定在5之后出现了,那么4一定要进行op操作,放到首位,只要4放到了首位,那么其他的3,2,1,0等<=4的数,全都是要进行操作的。(3也要放到首位,那么2也要放到首位,那么...)。可以看到只有 5, 6, 7三个数不需要进行op操作。因此总的op数量是n-3 = 8 - 3 = 5.

为了找到这个序列,我打算:从右往左遍历,

idx: 为遍历的指针;p: 上述递增序列的最低位指针, _min: 记录arr[idx, p-1]之间的最大的值。在遍历过程中,不断地把递增序列移到右侧,比如

idx: 6, p: 6,

8 6 5 7 9 5 4

_min: uninitialzed

idx: 5, p: 6,

8 6 5 7 9 5 4 [ 5比4大,因此交换 5和4的位置 ]

8 6 5 7 9 4 5

_min: 4 (_min更新为4)

idx: 4, p: 6

8 6 5 7 9 4 5  [ 9比5大,因此交换 9 和 5 的位置 ]

8 6 5 7 5 4 9

_min: 5 (更新为5和4中的最大者)

idx: 3, p: 6

8 6 5 7 5 4 9

8 6 5 4 5 7 9  [ 7 比 9 小,因此7可以纳入递增序列中: 交换4和7,p-- ]

_min: 5 (4,5中的最大者)

idx: 2, p: 5

8 6 5 4 5 7 9  [ 由于5 <= _min(5), 因此直接 idx--]

idx:1 , p: 5

8 6 5 4 5 7 9  [ 6大于_min,因此是ok,更新递增序列, swap(6, 5), p--]

8 5 5 4 6 7 9  [swap之后的结果]

idx: 0, p: 4

8 5 5 4 6 7 9 [ 8比_min大,8比6都大,因此p不断自增,知道8 < 9才停止,此时p指向了9,如下图]

8 5 5 4 6 7 9 [ 8 比 9 小,因此swap(8, 7)]

7 5 5 4 6 8 9 [结果]

idx: -1, p: 5

-> break;

因此最大递增序列是长度为2,{8, 9}。因此返回 n- 2 即 7 - 2 = 5

复杂度分析:

扫描的时间为 O(n)。对于swap操作,最后的递增序列类似于一个栈,每个元素最多进栈出栈一次,也是最多 O(n)。 因此时间复杂度是 O(n),空间复杂度是 O(1)。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-09 06:29:17

数组进行多少次OP操作,才能有序的相关文章

将两个数组A和B合并为一个有序的C数组

1 # include<iostream> 2 # include<cstdio> 3 # include<algorithm> 4 using namespace std; 5 void Sort(int a[],int b[],int c[],int n,int m) 6 { 7 int A=0, B=0, C=0; 8 while(A<n && B<m) 9 { 10 if(a[A] <= b[B]) 11 c[C++] = a[

四:redis的sets类型相关操作(有序和无序集合)

================四五种(有序和无序集合):sets类型(就是集合)============= 一介绍:  set表示集合,添加是是随意添加的----->无序集合 set是集合,它是string类型的无序集合. set是通过hash table实现的,添加,删除和查找的复杂度都是0(1). 对集合我们可以取并集.交集.差集. 通过这写操作我们可以实现sns中的好友推荐和blog的tag功能 1:sadd 向名称key的set中添加元素(唯一的) 例:sadd myset1 one 

关于leetcode中对数组O(1)空间消耗操作的几道题

其实这几道题在leetcode中都是比较容易的,但是如果刚开始不理解题意的话可能就会进入陷阱. 整数数组中的几个操作如下面所示,无非是怎样进行数组元素的的交换. Remove Element Given an array and a value, remove all instances of that value in place and return the new length. The order of elements can be changed. It doesn't matter

数组的增删改查操作

做批量数据录入时须要对json内的数组进行增删改查操作,splice还是非常强大的记录一下用法. var lang = ["php","java","javascript"]; //删除 var removed = lang.splice(2,1); console.log(lang); //php,javascript //console.log(removed); //java ,返回删除的项 //插入 var insert = lang.s

MongoDB .Net Driver(C#驱动) - 内嵌数组/嵌入文档的操作(增加、删除、修改、查询(Linq 分页))

目录 一.前言 (一) 运行环境 二.前期准备工作 (一) 创建 MongoDBContext MongoDb操作上下文类 (二)创建测试类 (三) 创建测试代码 三.内嵌数组增加元素操作 (一) Update.Set()方法 替换内嵌数组(不推荐使用) (二)Update.Push()方法 直接将元素压入内嵌数组(推荐) (三) Update.PushEach()方法 将多个元素压入内嵌数组(推荐) 四.内嵌数组删除元素操作 (一) Update.Set()方法 替换内嵌数组(不推荐使用) (

java常用的数组、字符串、集合操作以及数据结构与算法基本知识

java中常用封装的数组 .字符串. 集合来操作对象,但数据结构中常用的有栈和队列   数与图以及他们之间的排序,查找. 数组声明没有分配内存空间  只有创建或者是初始化时才分配,创建时把数组中的数据类型数据所在的内存空间首地址赋值给数组名,在创建每个对象时,都会给该对象分配地址和它存储的数据 .如变量    int arr[]; int arr[]={1,2,3};  arr=new int[10] ,int arr[][]={{1,9,7},{1,2,3}}  int arr[][]=new

[Effective JavaScript 笔记]第46条:使用数组而不要使用字典来存储有序集合

对象属性无序性 js对象是一个无序属性集合. var obj={}; obj.a=10; obj.b=30; 属性a和属性b并没有谁前谁后之说.for...in循环,先输出哪个属性都有可能.获取和设置不同的属性与顺序无关,都会以大致相同的效率产生相同的结果.也就是说访问属性a和访问属性b,没有哪个访问更快之说.ES标准并未规定属性存储的任何特定顺序,甚至于枚举对象也未涉及.for...in循环会挑选一定的顺序来枚举对象的属性,标准允许js引擎自由选择一个顺序,它们的选择会微妙地改变程序行为.如要

关于数组中重复元素的操作

//在有序的数组中,删除重复的元素 //在有序的数组中,删除重复的元素 #include<iostream> #include<math.h> #include<string.h> using namespace std; int main() { int a[]= {1,2,2,2,2,3,4,5,5,5,5,6}; int len =sizeof(a)/sizeof(a[0]); int i,j; for(i=0,j=1; j<len; j++) { if(a

python数组,字典的一些操作

新手刚刚开始学习python,如果有写错或写的不好的地方,请大家多多指教!在python中输出当前系统import sysprint(sys.platform)输出当前在那个目录import osos.getcwd()输出一个变量有多少位s = 'spam'len(s)替换变量的值s = 'z' + s[1:]查找变量内的值s.find('pa')  #找到会返回1,找不到会返回-1临时修改变量的值s.replace('pa', 'XZC')  #将变量内pa临时替换成XZC使用exec运行文件