03算法复杂度(下)

1.最好情况时间复杂度(best case time complexity)

最好情况时间复杂度:在最理性的情况下,执行这段代码的时间复杂度,比如下面的代码中,最好的情况,x为arr的第一个元素,则时间复杂度为O(1):

/**
     * 最好:O(1)
     * 最坏:n -> O(n)
     * 平均: x的位置可能在 0,1,...n-1 以及 不在arr中, 共n+1种情况,每种情况的概率为 1/(n+1)<br>
     *     因此,平均复杂度为: 1 * ( 1/(n+1) ) + 2 * ( 1/(n+1) ) + ... + n * ( 1/(n+1) ) + n *( 1/(n+1) ) = ( n(n+3) )/ ( 2* (n+1)
     *     -> O(n)
     * @param arr
     * @param n
     * @param x
     * @return
     */
    public static int cal2(int [] arr, int n, int x) {
        // 总 n -> O(n)?
        int i = 0; // 1
        int pos = -1; // 1
        for(; i < n; ++i) { // n?
            if(arr[i] == x) { // n?
                pos = i; // n?
                break;
            }
        }

        return pos;
    }

2.最坏情况时间复杂度(worst case time complexity)

最坏情况复杂度,就是在最糟糕的情况下,执行这段代码的时间复杂度,如下的代码中,如果arr中无x, 则需要把整个arr都遍历一遍,复杂度为O(n):

/**
     * 最好:O(1)
     * 最坏:n -> O(n)
     * 平均: x的位置可能在 0,1,...n-1 以及 不在arr中, 共n+1种情况,每种情况的概率为 1/(n+1)<br>
     *     因此,平均复杂度为: 1 * ( 1/(n+1) ) + 2 * ( 1/(n+1) ) + ... + n * ( 1/(n+1) ) + n *( 1/(n+1) ) = ( n(n+3) )/ ( 2* (n+1)
     *     -> O(n)
     * @param arr
     * @param n
     * @param x
     * @return
     */
    public static int cal2(int [] arr, int n, int x) {
        // 总 n -> O(n)?
        int i = 0; // 1
        int pos = -1; // 1
        for(; i < n; ++i) { // n?
            if(arr[i] == x) { // n?
                pos = i; // n?
                break;
            }
        }

        return pos;
    }

3.平均情况时间复杂度(average case time complexity)

最好、最坏时间复杂度其实都是极端情况下的代码复杂度,发生的概率并不大,具有普适性的还是平均时间负责度

  • 粗略平均:

    x的位置可能在 0,1,...n-1 以及 不在arr中, 共n+1种情况,累加再除以n+1得平均时间:
    (1+2+3+...+n+n)/ (n+1) = ( n(n+3) )/ ( 2* (n+1)  -> O(n)
    
  • 精准平均:运用概率统计,

    精准平均: x的位置可能在 0,1,...n-1 以及 不在arr中, 共n+1种情况,每种情况的概率为 1/2,而数组中每个元素的概率为1/n:
         因此,平均复杂度为: 1*(1/2)*(1/n) + 2*(1/2)*(1/n) + 3*(1/2)*(1/n) + ... + n*(1/2)(1/n) + n*(1/2) = (3n+1)/4 -> O(n)
    

    这个值就是概率论中的加权平均值,也叫做期望值,所以平均时间复杂度的全称应该叫做加权平均时间复杂度 或者 期望时间复杂度

    /**
         * 最好:O(1)
         * 最坏:n -> O(n)
         * 粗略平均: x的位置可能在 0,1,...n-1 以及 不在arr中, 共n+1种情况,累加再除以n+1得平均时间:<br>
         *    ( 1+2+3+...+n+n)/ (n+1) = ( n(n+3) )/ ( 2* (n+1)
         *     -> O(n)
         * 精准平均: x的位置可能在 0,1,...n-1 以及 不在arr中, 共n+1种情况,每种情况的概率为 1/2,而数组中每个元素的概率为1/n<br>
         *     因此,平均复杂度为: 1*(1/2)*(1/n) + 2*(1/2)*(1/n) + 3*(1/2)*(1/n) + ... + n*(1/2)*(1/n) + n*(1/2) = (3n+1)/4
         *     -> O(n)
         * @param arr
         * @param n
         * @param x
         * @return
         */
        public static int cal2(int [] arr, int n, int x) {
            // 总 n -> O(n)?
            int i = 0; // 1
            int pos = -1; // 1
            for(; i < n; ++i) { // n?
                if(arr[i] == x) { // n?
                    pos = i; // n?
                    break;
                }
            }
    
            return pos;
        }
    

4.均摊时间复杂度(amortized time complexity)

/**
     * 最好:只一次 O(1)
     * 最差: n+n -> 2n -> O(n)
     * 平均: 1*( 1/(n+1) ) + 1*( 1/(n+1) ) + ...+ n * ( 1/(n+1) ) = n/2n+2 -> O(1)
     * 均摊: O(1): 前n次 都为O(1), 每隔n+1次,复杂度为O(n), 把这n次操作均摊到<br>
     *     前面的n次,总的复杂度为 O(1).
     * @param val
     * @param n
     */
    public static void insert(int val, int n) {
        int[] arr = new int[n];
        int count = 0;

        if(count == arr.length) { // 1
            int sum = 0; // 1
            for(int i=0; i < arr.length; i++) { // count == arr.length ? n : 0
                sum = sum + arr[i]; // count == arr.length ? n : 0
            }

            arr[0] = sum; // count == arr.length ? 1 : 0
            count = 1; // count == arr.length ? 1 : 0
        }

        arr[count] = val;  // 1

        ++count; // 1
    }


均摊其实是平均的一种特殊情况,特点:

对于 insert() 函数来说,O(1) 时间复杂度的插入和 O(n) 时间复杂度的插入,出现的频率是非常有规律的,而且有一定的前后时序关系,一般都是一个 O(n) 插入之后,紧跟着 n-1O(1) 的插入操作,循环往复。
每一次 O(n) 的插入操作,都会跟着 n-1O(1) 的插入操作,所以把耗时多的那次操作均摊到接下来的 n-1 次耗时少的操作上,均摊下来,这一组连续的操作的均摊时间复杂度就是 O(1)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值