思路:在冒泡排序(升序)中,每次都是从排列的最左端开始,逐个和身后的比较,
如果大于身后的,则交换位置继续和后面的比较,如果身后的,则身后的接着和
后面的比较直到到达队尾。但是在这里,在冒泡的过程中,如果选择的人比身后
的人矮就会停止冒泡,这时仍然每次选择从最左端开始冒泡的话,如果最矮
的已经排列在首端,冒泡就无法进行下去,好在题目并没有限定我们每次选择从
哪里开始冒泡,这样一来就好办多了.
1.首先,在题目给定的操作条件下,1(身高最矮的人)必然不会被选择,因为选择
他没有任何效果,那么如果1的前面还有人的话,这些人一定要被选择进行操作才
有可能越过1排到1后面去。1后面的排列只有两种可能,1)1后面的排列已经是升序
排列,2)1后面的排列不是升序排列。对应不同的情况如何选择1前面的人让他们
排到1后面去呢?
1)1后面的是升序排列,会出现卡顿的情况,即选择了1前面的某个人i,但是在i
之后,1之前还存在比i高的人,为此我们决定每一次都选择1之前最高的那个人
进行操作,因为当1之前最高的人挪到1后面去之后,第二高的人就变成了
1之前最高的人,这样一来就不会出现卡顿的情况,假定1前面有k个人的话
我们只需要k次操作就可以将1前面的人全部挪到1后面去。并且由于1后面的
是升序排列,根据选择操作的规定,每一次1前面的数i在被选择进行操作挪到
1后面的过程中,必然会构成一个新的升序排列,因为i遇到1后面比i小的人
会和它交换位置,遇到比他高的人或者到了队尾则会停下来,则i最终停下来
的时候i一定高于他前面的人,一定矮于他后面的人或者到了队尾,而1和
i之间的排列以及i之后的排列并无任何操作保持升序性质,故1之后的序列
仍然保持升序性质
2)1后面的是无序排列,那么我们就将1后面的无序排列变成升序排列回到情况1)
即可
2.由1知道,现在要解决的问题是如何将1后面的无序排列变成升序排列
假设1后面有m个人,要将这m个人排列成升序排列,这不就回到了我们要解决的问
题上来了吗?题目要我们解决的是将n个人排列成升序排列,因此我们在调用步骤1
直到m=0,即最矮的人后面没有人,那么最矮的人的后面一定是升序排列,
需要注意一点当m=0时,此时最矮的人一定是数组a原始排列的最后一个人,因为
从前面的步骤来看我们每轮选取数组的时候都是砍掉最矮的人的前面排列,保留
其后边的排列。
由此我们可以写出递归程序miniSelection0
算法流程:
(1).确定数组a的最小值minV的位置loc0
(2).确定数组a[loc0+1:]的最小值的位置loc1
(3).直到数组a[locm+1:]为空数组,其最小值的位置为loc(m+1) = 0
(4).求和loc0 + loc1 + ... + loc(m+1)即为最少次数

     def miniSelection0(self, n: int, a: int):
          if n == 0: return 0
           loc = 0
          minV = a[0]
          for i in range(1, n):
              if minV > a[i]:
                  minV = a[i]
                  loc = i
         return loc + self.miniSelection0(n-loc-1, a[loc+1:])  

从上面的算法分析和算法流程我们可以发现在整个数组的更新过程中,有一些点
是不会被选取进行操作的,这些点就是每一轮数组当中的最小值,而其它的数一定
有一次会被选取进行操作,而整个数组的个数已知,如果我们知道了不会被选取进
行操作的人的个数,剩下的就是会被选取的人的个数。那么我们如何确定所有不会
被选取的人呢?我们知道第一个不会被选取的人一定是整个数组a的最小值minV,设
其在数组a的第loc位,根据前面的算法流程,第二个不会被选取的人一定是a[loc]之后
的数组的最小值minV1,设其在数组a的第loc1位,第三个不会被选取的人一定是a[loc1]
之后数组的最小值minV2,设其位置为a[loc2],...,直到最后一个不会被选取的人a[-1],
其位置为n-1, 我们发现loc < loc1 < loc2 < ... < n-1, 并且a[loc] < a [loc1] <
a[loc2] < ... < a[n-1], 刚好符合单调栈的特性。
由此我们可以写出单调栈程序miniSelection1
算法流程:
(1).如果数组个数小于2,直接返回0,不用任何操作
(2).将a[0]入栈,即s[0] = [a[0]]
(3).从i=1开始遍历所有元素a[i],
如果a[i]大于栈顶元素,即a[i] > s[-1], 将a[i]入栈,遍历下一个元素a[i+1]
如果a[i]小于栈顶元素,即a[i] < s[-1], 将栈顶元素弹出:
如果栈为空,直接将a[i]入栈,遍历下一个元素a[i+1]
如果栈不为空,继续比较a[i]和新栈顶元素的大小,重复上面的步骤
直到a[i] > s[-1]或者栈为空
(4).遍历完所有元素后,栈s中的元素就是不会被选取进行操作的元素,数组a元素
的个数减去栈s的元素的个数就是最小的操作次数

    def miniSelection1(self, n: int, a: list) -> int:
          if n == 0: return 0
          s = [a[0]]
          for i in range(1, n):
              while s and a[i] < s[-1]:
                  s.pop()
              s.append(s[i])
          return n-len(s)