求递增数列中所有A[i]=i的元素(阿里巴巴2013笔试题)

来源:互联网 发布:2007年网络流行歌曲 编辑:程序博客网 时间:2024/06/07 05:21

求递增数列中所有A[i]=i的元素

阅读更多博客,请访问博主的个人网站 点击访问网站

题意描述

给定一个排好升序的数组A[1]、A[2]、……、A[n],其元素两两不相等。请设计一高效的算法找出中间所有A[i] = i的下标。并分析其复杂度。

思路分析

该题目有两个重要的条件:
1. 排好升序的数组
2. 元素两两不相等

我们根据以上两个已知条件可以得出以下定理:

定理1:在递增序列中A中,对于A的所有元素A[i],如果满足A[i] = i, 则他们组成一个连续的序列。

对于定理1这里不作证明,只给出两个例子来阐述定理的意义。
1. 已知A中满足条件的元素只有A[i],A[j],A[k]三个,且i < j < k,那么我们根据定理1就可以断言:i + 1 = j 且 j + 1 = k。
2. 已知A中有元素A[i] = i, A[i + 1] = i + 1,但是A[i + 2] ≠ i + 2,那么A[i + 2]后面的元素也不会再有满足条件的元素了。同理,若A[i - 1] ≠i - 1,那么可以推出A[i - 1]前面也不会再有满足条件的元素了。

算法设计

由定理1知,所有满足条件的元素挨在一块组成一个连续数列。我们的算法就是找出这个数列的左边界和右边界。
1. 二分查找左边界,即满足 A[i] = i 且 A[i - 1] < i - 1的位置。
2. 二分查找右边界,即满足A[i] = i 且A[i + 1] > i + 1。
3. 左边界到右边界之间的即为满足条件的元素。

代码实现(python)

class Solution:    def getLeftBound(self, a):        low = 0        high = len(a) - 1        while low <= high:            mid = (low + high) / 2            if a[mid] == mid and (mid == 0 or a[mid - 1] != mid - 1):                return mid            elif a[mid] < mid:                low = mid + 1            elif a[mid] > mid:                high = mid - 1            else:                high = mid - 1        return -1    def getRightBound(self, a):        low = 0        high = len(a) - 1        while low <= high:            mid = (low + high) / 2            if a[mid] == mid and (mid == len(a) - 1 or a[mid + 1] != mid + 1):                return mid            elif a[mid] < mid:                low = mid + 1            elif a[mid] > mid:                high = mid - 1            else:                low = mid + 1        return -1    def getAns(self, a):        l = self.getLeftBound(a)        r = self.getRightBound(a)        return a[l : r + 1]s = Solution()a = [-1, 0, 2, 3, 4, 5, 6, 9]print s.getAns(a)

复杂度分析(时间)

  • 代码中getLeftBound()和getRightBound()都是二分查找的过程,复杂度为O(logn)
  • 最后返回满足条件的元素 的操作,复杂度为O(n)
1 0
原创粉丝点击