旋转数组的最小数字+堆排介绍19.9.14

题目描述

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。

输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。

例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。

NOTE:给出的所有元素都大于0,若数组大小为0,请返回0

时间限制:3秒 空间限制:32768K

最差的方式就是遍历,得到最小的值——>时间复杂度为O(n)

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        if(array.length == 0)
            return 0;
        //最简单且最没有啥技巧的方式:
        int min = 2147483647;
        for(int i=0;i<array.length;i++){
            if(array[i]<min)
                min = array[i];
        }
        return min; 
    }
}

  //第二种:稍复杂——>时间复杂度nLog(n)

  //前几天学了堆,把数组想象成堆结构,小的数向上调整

  //从第一个数据开始;

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        if(array.length == 0)
            return 0;
        int i,t;
        for(i=0; i<array.length; i++){
            while(array[i] < array[(i-1)/2]){//子节点比父节点小,交换
                t = array[i];
                array[i] = array[(i-1)/2];
                array[(i-1)/2] = t;
                i = (i-1)/2; //新的数继续和前面的父节点比较
            }
        }
        return array[0];//经过堆调整后,得到数组首部就是最小值
    }
}

 

 

1.堆排介绍

1.1 满二叉树:左右两个孩子全有

 

1.2 完全二叉树:如果不是满二叉树,则子树是从左往右补齐的也是完全二叉树

1.3 一个数组可以想象成一颗完全二叉树

左子:index=2*i+1

右子:index=2*i+2

索引 i 的父节点下标:(i-1)/2

1.4 堆——完全二叉树

大根堆:在一棵完全二叉树中,任何一棵子树的最大值都是子树的头部

小根堆:在一棵完全二叉树中,任何一棵子树的最小值都是子树的头部

 

1.5 数组——>大根堆

1.6 数组建立大根堆时间复杂度分析:

      完全二叉树:N个数,高度Log(N);

      每加入一个数,其本质是与它的上一层做比较,所以加入数的时间复杂度是O(Log(N))

      举例:i加入到i-1所组成的满二叉树中,它需要的时间复杂度是Log(i-1),由此总的为Log1+Log2+Log3……LogN-1; —>O(N)

 

1.7 大根堆是一个往上调整的过程,不断与父节点比较交换,这个过程叫做heapInsert.

public static void heapInsert(int[] arr, int index)  {
  while(arr[index] > arr[(index-1)/2]){//与父节点比较
     swap(arr,index ,(index-1)/2);
     index = (index-1)/2;
  }//直到index=0或者小于父节点,结束
}

1.8 当某个子树的头部数据发生了变化,向下调整,过程称为heapify

public static void heapify(int[] arr, int index, int  size) {
   int left = 2*index+1;
   while(left<size){
      int largest = left+1<heapSize && arr[left+1]>arr[left]?left+1:left;//左右孩子先比较,得出最大值的下标
           inr largest = arr[largest]>arr[index]?largest:index;
           if(largest == index){
               break;
           }
          swap(arr,largset,index);
          left= 2*index+1;
}

1.9 堆的用处(非常有用!!!)

输入一串数组,随时求平均值

大根堆里堆顶放所有值的最大值,小根堆堆顶放所有值的最小值,进去之后,大根堆和小根堆按照自身规则调整。

来一个数先于大根堆比较,大于大根堆的放小根堆,小于大根堆的放大根堆,而且只要某一边比另一边大于1,就把数多的堆顶弹到另一个数少的根堆里。

 

大根堆调整后,并不一定是有序的。只是建堆过程:O(LogN),  堆排序O(NLogN)

①但唯一能确定的是,堆顶肯定是最大的,

所以先把堆顶与最后一个数交换,然后最后一个值固定不动,看成是数组长度已经少一个。

 

②将新的堆顶重新heapInsert调整: 5 5 4 5 3

继续上述操作,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值