直通BAT面试算法精讲--排序(4)

案例四

荷兰国旗问题
三色排序问题

对只包含0,1,2的整数数组进行排序,要求使用交换、原地排序,而不是利用计数进行排序,做到0全在数组左边,1在中间,2在右边
测试用例:
arr = [1,1,0,0,2,1,1,0]
输出:[0,0,0,1,1,1,1,2]

解题思路:
在数组左侧设置一个0区域,初始长度为0,在数组右侧设置一个2区域,初始长度为0
从左右到遍历,如果当前值为1,直接跳到下一个位置。
若当前数为0,则将其与0区域的下一个元素交换,并将0区域向右扩散。
若当前数为2,则将其与2区域的前一个元素交换,并将2区域向前扩散。判断交换后的当前值是否还需再次交换
直至当前位置与2区域的左边界相等为止
时间复杂度为O(n),空间复杂度为O(1)

def sort(arr):
    if not arr:
        return arr
    index0 = 0
    index2 = len(arr)-1
    i = 0
    while i <= index2:
        if arr[i] == 0:
            exchange(arr,i,index0)
            index0 += 1
        if arr[i] == 2:
            exchange(arr,i,index2)
            index2 -= 1
            i -= 1 #这步很关键,与后面元素交换后,当前位置不变
        i += 1
    return arr

def exchange(arr,i,j):
    arr[i],arr[j] = arr[j],arr[i]

案例五

有序矩阵查找练习题
在行列都排好序的矩阵中找数
0 1 2 5
2 3 4 7
4 4 4 8
5 7 7 9
若k为7,返回true;若k为6,返回false。
若矩阵为(m*n),该题最优解可以做到时间复杂度O(m+n),额外空间复杂度O(1)。
方法,从右上角或者左下角找。

解题思路:
从右上角开始查找,如果这个值大于被查找的值的话,减去一列
如果这个值比被查找的值小的话,减去一行

def search(arr,k):
    if not arr:
        return False

    rows = len(arr)
    cols = len(arr[0])
    row = 0
    col = cols -1
    while rowand col>0:
        if arr[row][col] > k:
            col -= 1
        elif arr[row][col] < k:
            row += 1
        else:
            return True
    return False

案例六

最短子数组问题

给定一个数组,要求返回该数组中需要排序的最短子数组的长度

测试用例:
arr=[1,5,4,3,2,6,7]
返回:4
因为只有[5,4,3,2]需要排序

解题思路:
从左到右遍历,记录最大值,只关心右边数比左边数小的这种情况,并记录发生这种情况最右的位置。
从右往左遍历,记录最小值,和比最小值大的最左边的数的下标。
最左位置至最右位置这段,就是需要排序的数组长度

def shortest_arr(arr):
    if not arr:
        return 0
    n = len(arr)
    max = arr[0]
    min = arr[n-1]
    left = n-1
    right = 0

    for i in range(1,len(arr)):
        if arr[i] >= max:
            max = arr[i]
        else:
            right = i

    for i in range(n-1,-1,-1):
        if arr[i] <= min:
            min = arr[i]
        else:
            left = i
    if leftreturn right-left+1
    else:
        return 0

案例七

给定一个整形数组arr,返回如果排序之后,相邻两数的最大差值。
例如:
1 2 3 4 7 8 9
最大是3,4 和7之间
不用考虑同一个桶的相邻数,只用考虑桶之间的相邻数。

你可能感兴趣的:(直通BAT)