常用算法的实现
整理排序、查找、链表、字符串与组合问题等常见算法的 Python 实现和笔记。
算作自己的一次复习
排序
冒泡排序
C语言
#include <stdbool.h>#include <stdio.h>
#define GET_ARRAY_LEN(array, len) {len = (sizeof(array) / sizeof(array[0]));}
void bubbleSort(int a[], int count) { int index, temp; bool flag = true;
for (index = 1; index <= count; index++) { for (int pos = 0; pos < count - index; pos++) { if (a[pos] > a[pos + 1]) { temp = a[pos]; a[pos] = a[pos + 1]; a[pos + 1] = temp; flag = false; } } if (flag) { break; } }}
void main() { int a[] = {1, 2, 323423, 234, 43652, 234, 24, 6457, 7457, 35, 23}; int len; GET_ARRAY_LEN(a, len);
bubbleSort(a, len); for (int i = 0; i < len; i++) { printf("%d ", a[i]); }}python
#!/usr/bin/python# -*- coding: utf-8 -*-
def bubble_sort(r_list): flag = True for index in range(len(r_list)-1, 0, -1): if flag: flag = False for i in range(index): if r_list[i] > r_list[i+1]: r_list[i], r_list[i+1] = r_list[i+1], r_list[i] flag = True
if __name__ == '__main__': test_list = [4, 6, 9, 11, 3, 2, 0] bubble_sort(test_list) print test_list插入排序
python 递归版本
def insert_sort(r_list): r_len = len(r_list) if r_len > 1: r_list = insert_sort(r_list[:r_len-1]) + [r_list[-1]] else: return r_list
i = r_len - 1 while i > 0: j = i - 1 if r_list[j] > r_list[i]: r_list[i], r_list[j] = r_list[j], r_list[i]
i -= 1
return r_listpython another version
def insert_sort(r_list, r_len=None): if r_len is None: r_len = len(r_list) if r_len > 1: insert_sort(r_list, r_len-1) else: return
i = r_len - 1 j, temp = i, r_list[i] while j > 0 and temp < r_list[j-1]: r_list[j] = r_list[j-1] j -= 1 r_list[j] = temp堆排序
使用官方库
import heapqdata = [9, 3, 5, 7, 2, 4, 6, 8, 0]result = []
heapq.heapify(data)while data: result.append(heapq.heappop(data))
return result自己写
def heap_adjust(heap, i, h_len): while 2 * i + 1 < h_len: child = 2 * i + 1 if child + 1 < h_len: if heap[child] < heap[child + 1]: child += 1
if heap[i] < heap[child]: heap[i], heap[child] = heap[child], heap[i] i = child else: break
def heap_sort(heap): n = len(heap) for x in reversed(xrange(n // 2)): heap_adjust(heap, x, n)
for y in xrange(n-1, 0, -1): heap[0], heap[y] = heap[y], heap[0] heap_adjust(heap, 0, y)快速排序
def qsort(L): if len(L) <= 1: return L return qsort([lt for lt in L[1:] if lt < L[0]]) + [L[0]] + qsort([ge for ge in L[1:] if ge >= L[0]])线性排序
主要有计数排序、桶排序和基数排序,均为稳定算法
查找
查找数组中的最大值和最小值
思路:
-
数组中的元素每两个进行一组一次比较,较大元素放到大元素表中,较小元素放到小元素表中,分组的复杂度n/2
-
在小元素表中逐个比较找到最小值即整个数组的最小值,复杂度n/2;在大元素表中逐个比较找到最大值,即数组的最大值,复杂度也是n/2
总的复杂度3n/2,代码如下
def find_max_and_min(r_list): r_len = len(r_list) if r_len < 1: return (None,) * 2
if r_len % 2 == 0: start = 2 max_item, min_item = r_list[0], r_list[1] if max_item < min_item: max_item, min_item = min_item, max_item else: max_item, min_item = (r_list[0],) * 2 start = 1
while start < r_len: min_test, max_test = r_list[start], r_list[start + 1] if min_test > max_test: min_test, max_test = max_test, min_test
if min_test < min_item: min_item = min_test if max_test > max_item: max_item = max_test
start += 2
return max_item, min_item二分查找
使用官方库
from bisect import bisect_left
def binary_search(a, x, low=0, high=None): high = high if high is not None else len(a) # hi defaults to len(a) pos = bisect_left(a, x, low, high) return (pos if pos != high and a[pos] == x else -1)自己写
def binary_search(r_list, target): low, high = 0, len(r_list) while low <= high: mid = (low + high) // 2 if r_list[mid] == target: return mid elif r_list[mid] > target: high = mid - 1 else: low = mid + 1
return -1用递归写
def binary_search(r_list, target, low=0, high=None): if high is None: high = len(r_list)
if low <= high: mid = (low + high) // 2 mid_val = r_list[mid] if mid_val == target: return mid elif mid_val > target: return binary_search(r_list, target, low, mid-1) else: return binary_search(r_list, target, low+1, high) else: return -1链表
反转单链表
主要设置好变量,这个不难,所以一般会要求写得快又准
class Node(object): def __init__(self, data=None): self.data = data self.next = None
def reverse(r): if r.next is None: return r
head = r cur = r.next tail = r # new linked node tail, will return as new head while cur: tmp = cur.next head.next = tmp cur.next = tail tail = cur cur = tmp
return tail
def print_node(x): link_list = [] while x: link_list.append(x.data) x = x.next
print ' -> '.join(map(str, link_list))
def main(): a = Node(1) a.next = Node(2) a.next.next = Node(3)
print_node(a) print
b = reverse(a) print_node(b)
if __name__ == '__main__': main()字符串
最长公共子串
代码来自英文维基,原理是构造矩阵,找最长的对角线连续不为0的长度
def longest_common_substring(s1, s2): m = [[0] * (1 + len(s2)) for i in xrange(1 + len(s1))] longest, x_longest = 0, 0 for x in xrange(1, 1 + len(s1)): for y in xrange(1, 1 + len(s2)): if s1[x - 1] == s2[y - 1]: m[x][y] = m[x - 1][y - 1] + 1 if m[x][y] > longest: longest = m[x][y] x_longest = x else: m[x][y] = 0 return s1[x_longest - longest: x_longest]最长公共子序列
不要求字符是连续的,下面解法有最大递归1000的限制,所以还是使用自顶向上的DP更好一点,有兴趣可以看这里
def memoize(fn): cache = dict() def wrapped(*v): key = tuple(v) # tuples are hashable, and can be used as dict keys if key not in cache: cache[key] = fn(*v) return cache[key] return wrapped
def lcs(xs, ys): @memoize def lcs_(i, j): if i and j: xe, ye = xs[i-1], ys[j-1] if xe == ye: return lcs_(i-1, j-1) + [xe] else: return max(lcs_(i, j-1), lcs_(i-1, j), key=len) else: return [] return lcs_(len(xs), len(ys))最大子序列
待续
排列与组合
组合
通常的实现是10置换法
def combinations(iterable, r): # combinations('ABCD', 2) --> AB AC AD BC BD CD # combinations(range(4), 3) --> 012 013 023 123 pool = tuple(iterable) n = len(pool) if r > n: return indices = range(r) yield tuple(pool[i] for i in indices) while True: for i in reversed(range(r)): if indices[i] != i + n - r: break else: return indices[i] += 1 for j in range(i+1, r): indices[j] = indices[j-1] + 1 yield tuple(pool[i] for i in indices)排列
其实就是将组合得到的每个分组进行全排列
def permutations(iterable, r=None): # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC # permutations(range(3)) --> 012 021 102 120 201 210 pool = tuple(iterable) n = len(pool) r = n if r is None else r if r > n: return indices = range(n) cycles = range(n, n-r, -1) yield tuple(pool[i] for i in indices[:r]) while n: for i in reversed(range(r)): cycles[i] -= 1 if cycles[i] == 0: indices[i:] = indices[i+1:] + indices[i:i+1] cycles[i] = n - i else: j = cycles[i] indices[i], indices[-j] = indices[-j], indices[i] yield tuple(pool[i] for i in indices[:r]) break else: return这两段代码里都用到了for...else的语句结构,return放不放在else下的区别是,当for循环里break时,可以跳过return,否则必须经过return。当经过完所有for的条件后,将会返回
这两段代码的结果都是字典序由小到大