zoukankan      html  css  js  c++  java
  • 数组进行多少次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)。




    3, 更优算法

    这样的算法的时间复杂度是 O(n),空间复杂度是 O(1)。

    详细思路:8 6 5 7 10 9 4。从左往右找到阶段性的山腰(8,10)。然后把之间的山谷和山背都去掉(6,5,7, 以及 9,4)

    有p1, p2两个指针。p1指向8。p2指向6,比8小,然后右移。指向5,还是小于8。接着右移。最后指向了10,此时 p1也更新指向到10. 片

    继续从9開始走。

    p1指向过(8,10),p2指向过(6,5,7,9,4)p2中最大的是9,因此须要把 p1 指向过的(8,10)中比9小的排除掉就是最后的答案。排除的过程就是:p1,p2 再反复上面的过程,仅仅是如今须要记录 p1 所指向的元素中比 9大的数量是多少,这就是最后的答案。

    上面这样的方法,写代码简单。可行。

    时间空间复杂度也是能够的。


  • 相关阅读:
    [翻译] SVProgressHUD
    使用CoreData [4]
    Android学习笔记之AndroidManifest.xml文件解析
    Android 版本自动更新
    两个android程序间的相互调用(apk互调)
    Android 生成含签名文件的apk安装包
    【已解决】Android ADT中增大AVD内存后无法启动:emulator failed to allocate memory 8
    android adt与android sdk有什么关系,他们在开发中各起到什么作用
    Please ensure that adb is correctly located at……问题解决方案
    安装Android SDK时,点击SDK Manager.exe闪退,并且jdk的环境变量是对的。
  • 原文地址:https://www.cnblogs.com/lxjshuju/p/7018679.html
Copyright © 2011-2022 走看看