数据结构 - 红黑树
红黑树与AVL的比较:
AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多;
红黑是用非严格的平衡来换取增删节点时候旋转次数的降低;
所以简单说,如果你的应用中,搜索的次数远远大于插入和删除,那么选择AVL,如果搜索,插入删除次数几乎差不多,应该选择RB。
红黑树详解:
https://xieguanglei.github.io/blog/post/red-black-tree.html
教你透彻了解红黑树:
https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/03.01.md
编程题
1 台阶问题/斐波那契
问:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
fib = lambda n: n if n <= 2 else fib(n - 1) + fib(n - 2) # 第一种方法:递归啊😄
def memo(func): # 第二种记忆方法
cache = {}
def wrap(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrap
@memo
def fib(i):
if i < 2:
return 1
return fib(i-1) + fib(i-2)
def fib(n): # 第三种方法,求公约数,公倍数类同,也是 二分查找法
a, b = 0, 1
for _ in xrange(n):
a, b = b, a + b
return b
相关:
斐波那契数列
(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1, F(n)=F(n-1)+F(n-2)(n>=2,n∈N*)在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从1963起出版了以《斐波纳契数列季刊》为名的一份数学杂志,用于专门刊载这方面的研究成果。
斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368........
这个数列从第3项开始,每一项都等于前两项之和。
如果设F(n)为该数列的第n项(n∈N*),那么这句话可以写成如下形式:F(n)=F(n-1)+F(n-2)
通项公式
该数列是一个神奇的,当 n 越大的时候前与后数字比值越接近黄金分割点0.618,在生活中,斐波那契数列中的斐波那契数会经常出现在我们的眼前——比如松果、凤梨、树叶的排列、某些花朵的花瓣数(典型的有向日葵花瓣),蜂巢,蜻蜓翅膀,超越数e(可以推出更多),黄金矩形、黄金分割、等角螺线,十二平均律等。
自然界中“巧合”
斐波那契数列在自然科学的其他分支,有许多应用。例如,树木的生长,由于新生的枝条,往往需要一段“休息”时间,供自身生长,而后才能萌发新枝。所以,一株树苗在一段间隔,例如一年,以后长出一条新枝;第二年新枝“休息”,老枝依旧萌发;此后,老枝与“休息”过一年的枝同时萌发,当年生的新枝则次年“休息”。这样,一株树木各个年份的枝桠数,便构成斐波那契数列。这个规律,就是生物学上著名的“鲁德维格定律”。
另外,观察延龄草、野玫瑰、南美血根草、大波斯菊、金凤花、耧斗菜、百合花、蝴蝶花的花瓣,可以发现它们花瓣数目具有斐波那契数:3、5、8、13、21、……
其中百合花花瓣数目为3,梅花5瓣,飞燕草8瓣,万寿菊13瓣,向日葵21或34瓣,雏菊有34,55和89三个数目的花瓣。
这些植物懂得斐波那契数列吗?应该并非如此,它们只是按照自然的规律才进化成这样。这似乎是植物排列种子的“优化方式”,它能使所有种子具有差不多的大小却又疏密得当,不至于在圆心处挤了太多的种子而在圆周处却又稀稀拉拉。叶子的生长方式也是如此,对于许多植物来说,每片叶子从中轴附近生长出来,为了在生长的过程中一直都能最佳地利用空间,要考虑到叶子是一片一片逐渐地生长出来,而不是一下子同时出现的),每片叶子和前一片叶子之间的角度应该是222.5度,这个角度称为“黄金角度”,因为它和整个圆周360度之比是黄金分割数 0.618 的倒数,而这种生长方式就决定了斐波那契螺旋的产生。向日葵的种子排列形成的斐波那契螺旋有时能达到89,甚至144条。1992年,两位法国科学家通过对花瓣形成过程的计算机仿真实验,证实了在系统保持最低能量的状态下,花朵会以斐波那契数列长出花瓣。
数学相关的还有 阶梯问题 抛硬币问题 兔子繁殖问题
斐波那契弧线也是花朵,台风眼的形状
实现汉诺塔功能
重点其实是:不要一开始就关心每一步怎么解决的,你只需要把函数当成一个实现你目的的神器,随时调用。也就是递归。
比如说我们有一个万能神器move,只需要给它几个参数,即可自动完成一个功能:把n个盘子利用缓冲区,从起点运送到终点,期间严格遵守汉诺塔规则。
这里你暂时不需要去了解每一个步是如何实现的。
move(N,起点,缓冲区,终点)
N: 盘子的个数。
现在有个n个盘子,a,b,c三个塔。
把n个盘子抽象成两个盘子,n-1 和 底下最大的盘 1
这个最简单的玩法如何实现呢
首先:把n-1 移到 缓冲区 -------过程1
然后:把1 移到 终点 -------过程2
最后:把缓冲区的n-1 移到 终点 -------过程3
过程1 如何实现?
还是召唤神器吧。
move(N,起点,缓冲区,终点)
此时,我们的起点是a,终点是b ,N=n-1,缓冲区只能是c了
move(n-1,a,c,b)
过程2呢?
move(1,a,b,c)
过程3呢?
move(n-1,b,a,c)
哦哦 神器的力量太大,止不住咋办。。知乎
if (N == 1):
a -> c #此时我已经不需要缓冲区了
In [63]: def move(n,a,b,c): # 最后汇总如下:
...: if n == 1:
...: print('a--> c')
...: else:
...: move(n-1, a,c,b)
...: move(1,a,b,c)
...: move(n-1,b,a,c) # 该方法联想到算法图解一书中,关于递归的阐述:找到 基线条件 递归条件
变态台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
fib = lambda n: n if n < 2 else 2 * fib(n - 1)
矩形覆盖
我们可以用2*1
的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1
的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
f = lambda n: 1 if n < 2 else f(n - 1) + f(n - 2)
# 或者这样:
def rectange(n):
if n < 2: # 这句定义了 f(0)=f(1) = 1
return 1
else:
return f(n-1) + f(n-2)
杨氏矩阵查找 (难)
在一个m行n列二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
def get_value(l, r, c):
return l[r][c]
def find(l, x):
m = len(l) - 1
n = len(l[0]) - 1
r = 0
c = n
while c >= 0 and r <= m:
value = get_value(l, r, c)
if value == x:
return True
elif value > x:
c = c - 1
elif value < x:
r = r + 1
return False
实现杨辉三角
较为便捷,代码量较少的实现方式如下:
# -*- coding: utf-8 -*-
#!/usr/bin/env python
def triangles():
L = [1]
while True:
yield L
L.append(0)
L = [L[i - 1] + L[i] for i in range(len(L))]
该方式用到了列表生成式,理解起来较困难,下面是另一种方式:
def triangles():
ret = [1]
while True:
yield ret
for i in range(1, len(ret)):
ret[i] = pre[i] + pre[i - 1]
ret.append(1)
pre = ret[:]
另一个不用生成器的版本:
def YangHui (num = 10):
LL = [[1]]
for i in range(1,num):
LL.append([(0 if j== 0 else LL[i-1][j-1])+ (0 if j ==len(LL[i-1]) else LL[i-1][j]) for j in range(i+1)])
return LL
链表成对调换 (不懂)
1->2->3->4转换成2->1->4->3.
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
# @param a ListNode
# @return a ListNode
def swapPairs(self, head):
if head != None and head.next != None:
next = head.next
head.next = self.swapPairs(next.next)
next.next = head
return next
return head
合并两个有序列表(不懂)
尾递归
def _recursion_merge_sort2(l1, l2, tmp):
if len(l1) == 0 or len(l2) == 0:
tmp.extend(l1)
tmp.extend(l2)
return tmp
else:
if l1[0] < l2[0]:
tmp.append(l1[0])
del l1[0]
else:
tmp.append(l2[0])
del l2[0]
return _recursion_merge_sort2(l1, l2, tmp)
def recursion_merge_sort2(l1, l2):
return _recursion_merge_sort2(l1, l2, [])