数组相关算法
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]