数组相关算法

1.寻找最小的k个数

有n个整数,请找出其中最小的k个数,要求时间复杂度尽可能低。

全部排序。使用快速排序算法排序之后并且输出最小的k个数,时间复杂度为O(nlogn)

def quick_sort(array, left, right):
    if left >= right:
        return
    low = left
    high = right
    key = array[low]
    while left < right:
        while left < right and array[right] > key:
            right -= 1
        array[left] = array[right]
        while left < right and array[left] <= key:
            left += 1
        array[right] = array[left]
    array[left] = key
    quick_sort(array, low, left-1)
    quick_sort(array, left+1, high)

以上为一般的快速排序算法。由于是对数组直接进行操作,不需要返回值。

线性选择算法

在选择第k个最小元素时其平均时间复杂度为O(n)。

算法思想很简单,类似于快速排序。

我写的快速排序暂时有bug,以后再修改上传。

2.寻找和为定值的两个数

输入一个整数数组和一个整数,在数组中查找一对数,满足它们的和正好是输入的那个整数。

如果有多对数的和等于输入的整数,输出任意一对即可。

穷举法

def two_sum(array, n):
    len_a = len(array)
    for i in range(len_a):
        for j in range(len_a):
            if i != j and array[i] + array[j] == n:
                return array[i], array[j]

 

排序夹逼

先利用快速排序将数组变为有序数组,然后利用二分查找。可以将时间复杂度降为O(nlogn)。

或者是利用快速排序将数组变为有序数组后,使用两个指针从两段往中间扫描,这样查找的时间复杂度为O(n)。

def binary_search(list_a, n):
    low = 0
    high = len(list_a)-1
    while low <= high:
        mid = (low+high)/2
        if list_a[mid] == n:
            return True
        elif list_a[mid] < n:
            low = mid+1
        else:
            high = mid-1
    return False
    
def two_sum(array, n): array.sort() for i in array: if binary_search(array, n-i):
       if array.index(i)!=array.index(n-i):   
return i, n-i

如果n是其中一个数的两倍,则会出现bug。即数组中的一个数的出现了两次,2i == n。因此需要附加额外的判断条件。

 

def two_sum(array, n):
    begin = 0
    end = len(array)-1
    while begin < end:
        if array[begin]+array[end] == n:
            return array[begin], array[end]
        elif array[begin]+array[end] < n:
            begin += 1
        else:
            end -= 1

 

与上面的相比,这个算法需要数组本身为有序。

不需要额外的判断条件防止i和n-i为同一个数的这种特殊情况。

 

 

3.寻找和为定值的多个数

输入两个整数n和sum,要求从数列1,2,3,...,n中取任意个数,使其和等于sum,请将其中所有可能的组合列出来。

n问题转化为n-1问题

思路是如果取第n个数,问题转化为n-1和sum-n的问题

如果不取第n个数,问题转化为n-1和sum的问题

实现部分还有一点看不懂,所以暂时跳过。以后有机会补上。

 

4.最大连续子数组和

给定一个整数数组,数组里可能有整数,负数和零。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。

求所有子数组的和的最大值。

蛮力枚举

def max_substring(array, length):
    max_sum = array[0]
    cur_sum = 0
    for i in range(length):
        for j in range(i, length):
            for k in range(i, j+1):
                cur_sum += array[k]
                if cur_sum > max_sum:
                    max_sum = cur_sum
            cur_sum = 0
    return max_sum

动态规划

def max_substring(array, length):
    max_sum = array[0]
    cur_sum = 0
    for i in range(length):
        if cur_sum >= 0:
            cur_sum += array[i]
        else:
            cur_sum = array[i]
        if cur_sum > max_sum:
            max_sum = cur_sum
    return max_sum

此方法从前往后扫描一遍数组,即完成求最大连续子数组和的需求,所以时间复杂度为O(n)。

 

5.跳台阶问题

一个台阶总共有n级,如果一次可以跳一级,也可以跳两级,求总共有多少种跳法。

递归

def fib(n):
    if n == 1:
        return 1
    if n == 2:
        return 2
    if n > 2:
        return fib(n-1)+fib(n-2)

递推

def fib(n):
    a = 0
    b = 1
    for i in range(n):
        a, b = b, a+b
    return b

 

6.奇偶数排序

给定一个整数数组,请调整数组中数的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。

要求时间复杂度为O(n)。

若把奇数看成小的数,偶数看成大的数,那么按照题目要求的奇数放在前面偶数放在后面,

就相当于小数放在前面大数放在后面,联想一下快速排序的划分过程,就是通过一个主元把整个数组分成大小两部分。

划分过程有以下两种实现。

一头一尾两个指针同时往中间扫描

def is_odd(n):
    return (n & 1) == 1


def odd_even_sort(array, length):
    if array == [] or length <= 0:
        return
    low = 0
    high = length-1
    while low < high:
        if is_odd(array[low]):
            low += 1
        elif not is_odd(array[high]):
            high -= 1
        else:
            array[low], array[high] = array[high], array[low]

 

一前一后两个指针同时从左往右扫  如果前指针遇到的数比主元小,则后指针右移一位,然后交换各自指向的数。

def odd_even_sort(array, length):
if array == [] or length <= 0:
return i
= -1 for j in range(length): if is_odd(array[j]): i += 1 array[i], array[j] = array[j], array[i]

 

posted @ 2018-04-17 14:08  铁树小寒  阅读(401)  评论(0编辑  收藏  举报