0%

剑指Offer算法题-旋转数组的最小数字--Swift

题目:把一个数组最开始的若干个元素搬到数组的尾部,我们称之为数组的旋转。输入一个递增数组的旋转,输出旋转数组的最小元素。例如,数组{3,4,5,1,2}为数组{1,2,3,4,5}的一个旋转,该数组的最小值为 1

方案一

遍历数组,找寻最小值

方案二

旋转之后的数组实际上可以划分为 2 个递增的数组。而且前面的子数组的元素都大于等于后面子数组的元素,并且最小的元素刚好是 2 个子数组的分界点。

我们可以用两个指针分别指向数组的第一个元素记为 P1 和最后一个元素记为 P2,若旋转的个数大于 0,P1 一定是大于等于 P2 的,若旋转的个数等于 0,则 P1 就是最小值。此时先考虑旋转个数大于 0 的情况。

接着我们可以找到数组的 M,如果 M 大于 P1,我们可以认为 M 位于前面的递增数组,则可以把 P1 指向 M,如果 M 小于 P2,我们可以认为 M 位于后面的递增数组,则可以把 P2 指向 M。然后把 M 指向此时 P1 与 P2 的中间,直到 P1 小于 P2 或者 P1 和 P2 的下标相邻

还有一个特殊情况就是 P1=P2=M 时,此时不知道 M 是位于前面的递增数组还是后面的递增数组,就只能遍历 P1 到 P2 之间的值,找到最小值。

方案一代码(swift)

1
func minInOrder<T:Comparable>(rotationArray:Array<T>) -> T? {
2
    var minItem = rotationArray.first
3
    for item in rotationArray {
4
        if minItem! > item {
5
            minItem = item
6
        }
7
    }
8
    return minItem
9
}

方案二代码 (swift)

1
func min<T:Comparable>(rotationArray:Array<T>) -> T? {
2
    if rotationArray.count < 1 {
3
        return nil
4
    }
5
    var aheadIndex = 0
6
    var tailIndex = rotationArray.count - 1
7
    //先让中间指向头部,是因为如果头部元素如果小于尾部元素,则证明旋转了0个元素,此时头部元素等于最小值
8
    var middleIndex = aheadIndex
9
    while rotationArray[aheadIndex] >=  rotationArray[tailIndex]{
10
        if(tailIndex - aheadIndex == 1) {
11
            middleIndex = tailIndex
12
            break
13
        }
14
        //此处不要写成(aheadIndex + tailIndex) / 2,因为这么写,当数组元素比较多时,可以会造成溢出问题
15
        middleIndex = aheadIndex + (tailIndex - aheadIndex) / 2
16
        if rotationArray[aheadIndex] == rotationArray[tailIndex] && rotationArray[aheadIndex] == rotationArray[middleIndex] {
17
        //把P1到P2之间的元素,重新生成一个新数组,然后调用方案一的写法
18
            return minInOrder(rotationArray: Array(rotationArray[aheadIndex...tailIndex]))
19
        }
20
        if rotationArray[middleIndex] >= rotationArray[aheadIndex] {
21
            aheadIndex = middleIndex
22
        }else if rotationArray[middleIndex] <= rotationArray[tailIndex] {
23
            tailIndex = middleIndex
24
        }
25
    }
26
    return rotationArray[middleIndex]
27
}