Interview Questions: Analysis of Algorithms

Analysis of Algorithms

3-SUM in quadratic time. Design an algorithm for the 3-SUM problem that takes time proportional to n 2 n^2 n2 in the worst case. You may assume that you can sort the n integers in time proportional to n 2 n^2 n2 or better.

利用two pointer的思想进行处理,复杂度为 O ( N 2 ) O(N^2) O(N2)

public int threeSum(int[] a) {
    int count = 0;
    // 需要先进行排序处理
    Arrays.sort(a);
    // 循环中保证a[i]<a[j]<a[k]
    for (int i = 0; i < a.length - 2; i++) {
        int j = i + 1;
        int k = a.length - 1;
        // j和k从两头向中间移动
        while (j < k) {
            int sum = a[i] + a[j] + a[k];
            if (sum == 0) {
                count++;
                // 处理三元组元素相同的情况
                if (a[j] == a[j + 1]) {
                    j++;
                } else {
                    k--;
                }
            } else if (sum < 0) {
                j++;
            } else {
                k--;
            }
        }
    }
    return count;
}

Search in a bitonic array. An array is bitonic if it is comprised of an increasing sequence of integers followed immediately by a decreasing sequence of integers. Write a program that, given a bitonic array of nn distinct integer values, determines whether a given integer is in the array.

  • Standard version: Use ∼3lgn compares in the worst case.
  • Signing bonus: Use ∼2lgn compares in the worst case (and prove that no algorithm can guarantee to perform fewer than ∼2lgn compares in the worst case).

~3lgn: 1lgn用于二分查找最大值,划分左右区间;1lgn用于二分查找左区间;1lgn用于二分查找右区间

~2lgn: 节省1lgn关键在于不找最大值,直接依据不同情况来划分左右区间并进行查找。

  1. a[mid]>a[mid-1],中间元素在左边递增区间时:
    示意图
    如果key>a[mid],说明key只可能在mid右边,那么问题就变为在一个更小的抛物线上找key,递归进行处理即可;如果key<a[mid],那么key既可能在mid左边,也可能在mid右边,若在左边只要对左半边进行二分查找,若在右边也可以直接对右半部分的抛物线进行二分查找,原因在于key<a[mid],那么key只可能在横向红线的下方出现,即使key在右半部分也只会在右半部分的递减区域出现。

  2. a[mid]>a[mid+1],中间元素在右边递减区域时:与上述情况正好相反。

public class Bitonic {
    // 处理抛物线部分
    public boolean searchBitonic(int[] a, int left, int right, int key) {
        int mid = (left + right) / 2;
        // 直接找到key返回
        if (key == a[mid]) {
            return true;
        }
        if (a[mid] > a[mid - 1]) {		// mid在左侧递增部分
            if (key > a[mid]) {		// 递归处理右部分抛物线
                return searchBitonic(a, mid + 1, right, key);
            } else {    // 对左右两部分进行二分查找
                return searchLeft(a, left, mid - 1, key) || searchRight(a, mid + 1, right, key);
            }
        } else if (a[mid] > a[mid + 1]) {		// mid在右侧递减部分
            if (key > a[mid]) {		// 递归处理左部分抛物线
                return searchBitonic(a, left, mid - 1, key);
            } else {		// 对左右两部分进行二分查找
                return searchRight(a, mid + 1, right, key) || searchLeft(a, left, mid - 1, key);
            }
        }
    }

    // 递增部分二分查找
    private boolean searchLeft(int[] a, int left, int right, int key) {
        while (left <= right) {
            int mid = (left + right) / 2;
            if (a[mid] == key) {
                return true;
            }
            if (a[mid] < key) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return false;
    }

    // 递减部分二分查找
    private boolean searchRight(int[] a, int left, int right, int key) {
        while (left <= right) {
            int mid = (left + right) / 2;
            if (a[mid] == key) {
                return true;
            }
            if (a[mid] < key) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return false;
    }
}

Egg drop. Suppose that you have an nn-story building (with floors 1 through nn) and plenty of eggs. An egg breaks if it is dropped from floor TT or higher and does not break otherwise. Your goal is to devise a strategy to determine the value of TT given the following limitations on the number of eggs and tosses:

  • Version 0: 1 egg, ≤T tosses.
  • Version 1: ∼1lgn eggs and ∼1lgn tosses.
  • Version 2: ∼lgT eggs and ∼2lgT tosses.
  • Version 3: 2 eggs and ∼ 2 n 2\sqrt{n} 2n tosses.
  • Version 4: 2 eggs and ≤ c T c\sqrt{T} cT tosses for some fixed constant c.

以下分析转载自 https://www.cnblogs.com/evasean/p/7208986.html

version 0: 拿着一个鸡蛋从1~n依次扔就可以,到floor T会碎,故复杂度为≤T。

version 1: 采用二分查找,首先从n/2层开始扔: if(鸡蛋碎) 从(n/2)/2层开始扔;else 从n/2+(n/2)/2层开始扔。二分方法需要lgn个鸡蛋尝试lgn次。

version 2: 依次从1, 2, 4, 8, 16, 32,… 2 k 2^k 2k开始扔,如果鸡蛋在 2 k 2^k 2k碎了,那么 2 k − 1 ≤ T ≤ 2 k 2^{k-1}≤T≤2^k 2k1T2k,这时已经使用了 lgT 次步,接下来在 [ 2 k − 1 + 1 , 2 k ) [2^{k-1}+1,2^{k}) [2k1+1,2k)区间进行version 1的二分查找方法,需要花费lgT步。这两种操作加起来总共花费2lgT步。

version 3: 将0~n层楼分成 [ 1 , n − 1 ] [1, \sqrt{n}-1] [1,n 1], [ n , 2 n − 1 ] [\sqrt{n}, 2\sqrt{n}-1] [n ,2n 1], [ 2 n , 3 n − 1 ] [2\sqrt{n},3\sqrt{n}-1] [2n ,3n 1] [ k n , ( k + 1 ) n − 1 ] [k\sqrt{n}, (k+1)\sqrt{n}-1] [kn ,(k+1)n 1]…个区间,用一个鸡蛋分布从1开始在各个区间的起始楼层扔,如果在 k n k\sqrt{n} kn 层碎了,那就从 ( k − 1 ) n + 1 (k-1)\sqrt{n}+1 (k1)n +1开始逐层扔。第一步区间选择用了 n \sqrt{n} n 的复杂度,第二步区间内部扔鸡蛋用了 n \sqrt{n} n 的复杂度,总共用了 2 n 2\sqrt{n} 2n

version 4: 尝试从1, 4, 9, 16, 25,… ( k − 1 ) 2 (k-1)^2 (k1)2, k 2 k^2 k2…楼层扔鸡蛋,加入鸡蛋在楼层 k 2 k^2 k2碎了,意味着 ( k − 1 ) 2 ≤ T ≤ k 2 (k-1)^2 ≤T≤ k^2 (k1)2Tk2,这一步尝试了 T \sqrt{T} T ( k = T ) (k=\sqrt{T}) (k=T )。接着从楼层 ( k − 1 ) 2 + 1 (k-1)^2+1 (k1)2+1开始逐层扔,最多尝试至 k 2 − 1 k^2-1 k21结束,这一步需要尝试 k 2 − 1 − ( k − 1 ) 2 − 1 + 1 = 2 T − 2 k^2-1-(k-1)^2-1+1=2\sqrt{T}-2 k21(k1)21+1=2T 2次。总共用了 3 T − 2 3\sqrt{T}-2 3T 2次。


参考

Bitonic search - iteye_12150
Coursera Algorithms week1 算法分析 练习测验: Egg drop 扔鸡蛋问题 - evasean

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值