递归

时间&空间复杂度

常见列表查找

算法排序

数据结构

递归

在调用一个函数的过程中,直接或间接地调用了函数本身这就叫做递归。

注:python在递归中没用像别的语言对递归进行优化,所以每一次调用都会基于上一次的调用进行,并且他设置了最大递归数量防止递归溢出

递推:每一次都是基于上一次进行下一次执行

回溯:在遇到终止条件,则从最后往回一级级把值返回来

递归的特点:

  1、调用自身

  2、结束条件  ===>  (有穷)

时间&空间复杂度

时间复杂度

算法的时间复杂度是一个函数,它定量描述了该算法的运行时间,时间复杂度常用o表述,适用这种方式时,时间复杂度可被称为是渐进的,它考察当输入值大小趋近无穷时的情况

时间复杂度是用来估计算法运行时间的一个式子。一般来说,时间复杂度高的算法比复杂度低的算法慢

常见的时间复杂度(按效率排序):o(1)<o(logn)<o(n)<o(nlogn)<o(n^2)

不常见的时间复杂度:o(n!)  o(2^n)  o(n^n)

  1. print('Hello world') # O(1)
  2.  
  3. # O(1)
  4. print('Hello World')
  5. print('Hello Python')
  6. print('Hello Algorithm')
  7.  
  8. for i in range(n): # O(n)
  9. print('Hello world')
  10.  
  11. for i in range(n): # O(n^2)
  12. for j in range(n):
  13. print('Hello world')
  14.  
  15. for i in range(n): # O(n^2)
  16. print('Hello World')
  17. for j in range(n):
  18. print('Hello World')
  19.  
  20. for i in range(n): # O(n^2)
  21. for j in range(i):
  22. print('Hello World')
  23.  
  24. for i in range(n):
  25. for j in range(n):
  26. for k in range(n):
  27. print('Hello World') # O(n^3)

如何判断时间复杂度?

  1、循环减半的过程  ==>  o(logn)

  2、几次循环就是n的几次方的复杂度

空间复杂度

空间复杂度:用来评估算法内存占用大小的一个式子

  1. a = 'Python' # 空间复杂度为1
  2.  
  3. # 空间复杂度为1
  4. a = 'Python'
  5. b = 'PHP'
  6. c = 'Java'
  7.  
  8. num = [1, 2, 3, 4, 5] # 空间复杂度为5
  9.  
  10. num = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]] # 空间复杂度为5*4
  11.  
  12. num = [[[1, 2], [1, 2]], [[1, 2], [1, 2]] , [[1, 2], [1, 2]]] # 空间复杂度为3*2*2

定义一个或多个变量,空间复杂度都是为1,列表的空间复杂度为列表的长度

常见列表查找

首先我们先定义一个装饰器,为了后期比较各个算法(无论是排序,还是查找)的时间。

  1. import time
  2.  
  3. def cal_time(func):
  4. def wrapper(*args, **kwargs):
  5. t1 = time.time()
  6. result = func(*args, **kwargs)
  7. t2 = time.time()
  8. print('%s running time : %s seconds.' % (func.__name__, t2-t1))
  9. return wrapper

1、顺序查找

遍历所有元素,查找出对应的。也叫做线性查找

  1. def line_search(data_set, val):
  2. for i in range(len(data_set)):
  3. if data_set[i] == val:
  4. return i

2、二分查找

在计算机科学中,二分搜索(binary search),是一种在有序数组中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半

  1. # 二分查找法 建立在有序区间的基础上实现
  2. def bin_search(data_set, val):
  3. low = 0
  4. high = len(data_set) - 1 # 定义最小最大下标
  5. while low <= high: # 循环
  6. mid = (low + high) // 2 # 取中间值的整数
  7. if data_set[mid] == val: # 如果中间值等于查询值,返回
  8. return mid
  9. elif data_set[mid] < val: # 如果中间值小于查询值,最小下标变成low + 1, 区间减半
  10. low = mid + 1
  11. else:
  12. high = mid - 1 # 同理最大下标变成mid-1, 区间减半

两种查找方法的时间复杂度分别为

  1. 线性查找:o(n)
  2. 二分查找:o(logn)

测试一下:

  1. @cal_time
  2. def _bin_search(data_set, val):
  3. bin_search(data_set, val)
  4. # 不能把装饰器直接用来装饰递归函数,不然会伴随递归函数一起递归的
  5.  
  6. import random
  7. import copy
  8. data = [i for i in range(10000000)]
  9. line_search(data, 99990009)
  10. _bin_search(data, 99990009)

时间效率:

  1. /Library/Frameworks/Python.framework/Versions/3.6/bin/python3 /Users/dandyzhang/PycharmProjects/untitled/综合/算法/算法查找.py
  2. line_search running time : 0.6025080680847168 seconds.
  3. _bin_search running time : 1.52587890625e-05 seconds.
  4.  
  5. Process finished with exit code 0

算法排序

常用的排序算法:冒泡排序,插入排序,归并排序, 快速排序、基数排序、堆排序,选择排序。

首先,我们先来剖析一下最常见的lowB三人组:冒泡排序,选择排序,插入排序。

1. 冒泡排序

冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元n个项目需要O(n^2) 的比较次数,且可以原地排序。尽管这个算法是最简单了解和实现的排序算法之一,但它对于包含大量的元素的数列排序是很没有效率的

最优时间复杂度: O(n)

最坏时间复杂度: O(n^2)

稳定性:稳定的排序

思路

列表相邻的数比较,换位置,最后一个在第一次循环肯定变成有序区的第一个元素,即最大的

  1. # 冒泡排序
  2. # 最好情况o(n) 一般情况o(n^2) 最坏情况o(n^2)
  3. @cal_time
  4. def bubble_sort(li):
  5. for i in range(len(li) -1):
  6. for j in range(len(li) - i - 1):
  7. if li[j] > li[j+1]:
  8. li[j], li[j+1] = li[j+1], li[j]
  9.  
  10. # 冒泡排序优化
  11. @cal_time
  12. def bubble_sort_1(li):
  13. for i in range(len(li) -1):
  14. exchange = False
  15. for j in range(len(li) - i - 1):
  16. if li[j] > li[j+1]:
  17. li[j], li[j+1] = li[j+1], li[j]
  18. exchange = True
  19. if not exchange: # 可能一次没减少,可能是排好序的省了全部的循环,只走了一趟
  20. break

测试一下冒泡排序及其优化版的时间:

  1. data = list(range(5000))
  2. random.shuffle(data) # 打乱列表顺序,如果注释掉这一句,就是极端情况
  3. bubble_sort(data)
  4. bubble_sort_1(data) # 绝大多数情况下都会是比第一种快的
  5. # 冒泡排序分为最好情况,一般情况, 最坏情况, 时间复杂度是不一样的
  6.  
  7. bubble_sort running time : 2.3754842281341553 seconds.
  8. bubble_sort_1 running time : 0.0004961490631103516 seconds.

2.选择排序

最优时间复杂度:O(n^2)

最坏时间复杂度:O(n^2)

稳定性:不稳定的排序

思路

一趟便利记录最小的数,放到第一个位置;再遍历记录剩余列表中最小数,继续放置;

  1. # 选择排序法
  2. @cal_time
  3. def select_sort(li):
  4. for i in range(len(li) - 1):
  5. min_loc = i # 设置初始值永远为第一位数, 循环跟后面的数进行比较
  6. for j in range(i + 1, len(li)): # 不需要跟自身相比,所以+1
  7. if li[j] < li[min_loc]: # 如果后面循环到的数小于现在认为的最小位置
  8. min_loc = j # 记录下循环到的数的下标
  9. li[i], li[min_loc] = li[min_loc], li[i] # 循环结束后取最小的下标跟当前比对的位置互换
  10.  
  11. select_sort(data)

3.插入排序

最坏时间复杂度: O(n^2)

最优时间复杂度: O(n)

稳定性:稳定的排序

思路

跟打扑克牌抓牌的操作很相似,抓牌的时候跟有序区进行遍历的比较,插入在合适的位置

  1. @cal_time
  2. def insert_sort(li):
  3. for i in range(1, len(li)): # 从1开始
  4. tmp = li[i] # 循环到的需要跟有序区进行对比的数
  5. j = i - 1 # 循环到的数跟之前的有序区进行比较
  6. while j >= 0 and li[j] > tmp: # 比较的位置不在最左边并且循环到的需要对比的数小于有序区的被比较的数
  7. li[j+1] = li[j] # 有序区被比较的数向右移动一位
  8. j = j -1 # 递减往左比较
  9. li[j + 1] = tmp # li[j+1] = li[j] ==> 比如3的位置的值被放到4号了,3号空了应该放在3号,但是下面又减了1,所以是j+1
  10. # -1的话,直接+1到起始位置0,另外提一个没什么卵用的优化,遍历有序区查找,其实可以用二分查找插入点,但是位置还是要一个个移动,所以。。。
  11.  
  12. insert_sort(data)

这次测试下lowB三人组的时间

  1. data = [i for i in range(5000)]
  2. random.shuffle(data)
  3. data1 = copy.deepcopy(data)
  4. data2 = copy.deepcopy(data)
  5. data3 = copy.deepcopy(data)
  6. bubble_sort(data)
  7. bubble_sort_1(data1)
  8. select_sort(data2)
  9. insert_sort(data3)

bubble_sort running time : 2.424175977706909 seconds.
  bubble_sort_1 running time : 2.353872776031494 seconds.
  select_sort running time : 0.9465441703796387 seconds.
  insert_sort running time : 1.176313877105713 seconds.

***************************************************************************************************************************************

下面研究下比较高端的排序

快速排序

思路
1、取一个元素p(第一个元素),使元素p归位
2、列表被p分成两部分,左边都比p小,右边都比p大
3、递归完成排序

  1. # 快速排序 时间复杂度nlogn
  2. def quick_sort_x(data, left, right): # 建立模型,已经存在左右两块区域
  3. if left < right:
  4. mid = partition(data, left, right) # 分区
  5. quick_sort_x(data, left, mid - 1) # 递归左分区
  6. quick_sort_x(data, mid + 1, right) # 递归右分区
  7.  
  8. def partition(data, left, right): # 分区,建立一个左边小,右边大的分区
  9. tmp = data[left] # 取最左边的存入tmp,以此为指针
  10. while left < right: # 左指针跟右指针没右碰到
  11. while left < right and data[right] >= tmp: # 右边指向的数大于tmp
  12. right -= 1 # 继续循环
  13. data[left] = data[right] # 右边的数小于tmp的时候移动到左边的left
  14. while left < right and data[left] <= tmp: # 左边的小于tmp
  15. left += 1 # 继续循环
  16. data[right] = data[left] # 左边的大于tmp,指向的左边值放到右边
  17. data[left] = tmp # 此时left跟right已经相等 也可以将tmp放在right
  18. return left # 同理也可以return right
  19.  
  20. @cal_time
  21. def quick_sort(data): # 这个就不解释了,看灵性
  22. return quick_sort_x(data, 0, len(data) - 1)

跟lowB三人组比较下:

  1. data = list(range(5000))
  2. random.shuffle(data)
  3. data1 = copy.deepcopy(data)
  4. data2 = copy.deepcopy(data)
  5. data3 = copy.deepcopy(data)
  6. data4 = copy.deepcopy(data)
  7. bubble_sort_1(data1)
  8. insert_sort(data2)
  9. select_sort(data3)
  10. quick_sort(data4)
  11.  
  12. bubble_sort_1 running time : 2.3831076622009277 seconds.
  13. insert_sort running time : 1.2162189483642578 seconds.
  14. select_sort running time : 1.002126932144165 seconds.
  15. quick_sort running time : 0.012326955795288086 seconds. # 为什么叫快排,显而易见了。

绝大多数的语言 C++ /java都是快速排序,但python不是,python的排序跟快速排序是一个时间复杂度级别,C封装的。所以C的排序肯定是比python的排序还要快。

快排也不是一直都很快,比如一组数据都是按照倒序排好的,每次取最左边分区的话只能分得一个元素,时间复杂度可想而知。

快速排序的最坏情况

最好情况 o(nlogn)

一般情况o(nlogn)

最坏情况o(n^2)

先来比较下python系统内置排序跟快排。

系统内置排序

  1. # 系统内置排序
  2. @cal_time
  3. def sys_sort(data):
  4. return data.sort()

比较:

  1. data = list(range(5000))
  2. random.shuffle(data)
  3. data4 = copy.deepcopy(data)
  4. data5 = copy.deepcopy(data)
  5. quick_sort(data4)
  6. sys_sort(data5)
  7.  
  8. quick_sort running time : 0.012069225311279297 seconds.
  9. sys_sort running time : 0.0011510848999023438 seconds.

可以发现python内置排序算法,比快速排序还要快的多得多。内置排序算法是什么呢?我也不知道,后续有空可以研究。

备注

上面的代码递归测试可能会遇到递归最大限度的问题。

解决方案

  1. import sys
  2. sys.setrecursionlimit(10000)

快排遇到最坏情况可以反过来大小调换处理,大于换小于

  1. def partition(data, left, right):
  2. tmp = data[left]
  3. while left < right:
  4. while left < right and data[right] <= tmp: # mark1
  5. right -= 1
  6. data[left] = data[right]
  7. while left < right and data[left] >= tmp: # mark2
  8. left += 1
  9. data[right] = data[left]
  10. data[left] = tmp
  11. return left

堆排序

在引入堆排序的思想之前,先补充下二叉树的知识。

  1. https://baike.baidu.com/item/%E4%BA%8C%E5%8F%89%E6%A0%91/1602879?fr=aladdin

只是找个链接让大家了解二叉树概念:


  1. 二叉树 ==》 特殊的树,父节点只有2个子节点
  2. 完全二叉树 ==》 从后往前不能隔断的二叉树
  3. 满二叉树 ==》 全部节点都有的二叉树
  4. 大根堆&小根堆 ==》 根结点是最大或最小的

思路:

子节点中最大的跟父节点比较,上位,从下往上攀登

  1. # 堆排序
  2. def shift(data, low, high):
  3. i = low
  4. j = 2 * i + 1
  5. tmp = data[i]
  6. while j <= high: # 孩子在堆里
  7. if j < high and data[j] < data[j + 1]: # j < high代表有右孩子, 并且右孩子比左孩子大
  8. j += 1
  9. if tmp < data[j]: # 如果父节点小于最大的孩子节点
  10. data[i] = data[j] # 最大的孩子节点上位
  11. i = j # 孩子成为新父节点
  12. j = 2 * i + 1 # 新孩子节点
  13. else:
  14. break
  15. data[i] = tmp # 上位完的孩子节点,或者本身
  16.  
  17. @cal_time
  18. def heap_sort(data): # 升序
  19. n = len(data)
  20. for i in range(n // 2 - 1, -1, -1): # n//2-1 最后一个有孩子的父亲的下标
  21. shift(data, i, n-1)
  22. # 堆建好了
  23. for i in range(n - 1, -1, -1): # i指向堆的最后
  24. data[0], data[i] = data[i], data[0] # 父节点下位,孩子节点上去
  25. shift(data, 0, i - 1) # 调整出新的父节点,大的树放在最左节点,不再参与循环
  26.  
  27. def heap_sort(data): # li 降序
  28. n = len(data)
  29. for i in range(n // 2 - 1, -1, -1): # n//2-1 最后一个有孩子的父亲的下标
  30. shift(data, i, n-1)
  31. # 堆建好了
  32. li = []
  33. for i in range(n - 1, -1, -1): # i指向堆的最后
  34. li.append(data[0])
  35. data[i] = data[0]
  36. shift(data, 0, i - 1) # 调整出新的父节点

归并排序

思路

两段有序列表,一次次相互比较拿最小的  ==>  操作被称为一次归并

  1. 1、分解:将列表越分越小,直至分成一个元素
  2. 2、一个元素是有序的
  3. 3、合并:将两个有序列表归并,列表越来越大
  4.  
  5. 简述就是:先递归到最小单位下进行大小比较,调整位置,再往上进行合并比对调整

时间复杂度:o(nlogn) 空间复杂度:o(n)

代码实现:

  1. def merge(li, low, mid, high):
  2. i = low
  3. j = mid + 1
  4. ltmp = []
  5. # 实际上i,j已经将区分好,0~mid | mid+1 high
  6. while i <= mid and j <= high: # 当两边指针都没有走完的时候
  7. if li[i] < li[j]: # 如果左边小于右边的把左边的加入空列表,因为左右已经是有序的,所以一定是降序的了
  8. ltmp.append(li[i])
  9. i += 1
  10. else:
  11. ltmp.append(li[j]) # 不满足的话,右边的一定小
  12. j += 1
  13. # 左指针或者右指针已经走完
  14. while i <= mid: # 右指针走完,只剩左指针
  15. ltmp.append(li[i])
  16. i += 1
  17. while j <= high: # 左指针走完,只剩右指针
  18. ltmp.append(li[j])
  19. j += 1
  20. # print(ltmp)
  21. li[low: high + 1] = ltmp # 处理完,即拍完序,再赋值给原传入数组,右I/O操作!!
  22.  
  23. def _mergesort(li, low, high):
  24. if low < high: # 左右指针不重合继续分区,最小化分区
  25. mid = (low + high) // 2 # 中间指针
  26. _mergesort(li, low, mid) # 左分区处理
  27. _mergesort(li, mid + 1, high) #右分区处理
  28. merge(li, low, mid, high) # 最小分区后合并排序
  29.  
  30. @cal_time # 不解释了
  31. def mergesort(li, low, high):
  32. _mergesort(li, low, high)

上面三种快的排序算法进行比较:

  1. data = list(range(100000, 0, -1))
  2. random.shuffle(data)
  3. data1 = copy.deepcopy(data)
  4. data2 = copy.deepcopy(data)
  5. data3 = copy.deepcopy(data)
  6. quick_sort(data1)
  7. heap_sort(data2)
  8. mergesort(data3, 0, len(data) - 1)
  9.  
  10. quick_sort running time : 0.3668999671936035 seconds.
  11. heap_sort running time : 0.5506401062011719 seconds.
  12. mergesort running time : 0.4741668701171875 seconds.

三种快的排序的缺点:
  快速排序:极端情况下排序效率低
  归并排序:需要额外的内存开销
  堆排序:在快的排序算法中相对较慢
  所以一般情况下:时间:快速排序 < 归并排序 < 堆排序
  

真的,再说最后一个。

希尔排序

观察一下”插入排序“:其实不难发现她有个缺点:

  如果当数据是”5, 4, 3, 2, 1“的时候,此时我们将“无序块”中的记录插入到“有序块”时,估计俺们要崩盘,

每次插入都要移动位置,此时插入排序的效率可想而知。

  shell根据这个弱点进行了算法改进,融入了一种叫做“缩小增量排序法”的思想,其实也蛮简单的,不过有点注意的就是:

增量不是乱取,而是有规律可循的。

思路:

是一种分组插入排序算法的优化
先取一个整数d = n//2,将元素从头开始,分为n//2个元素一组
取第二个整数 d1 = d // 2 同上
直到按1来分组

希尔排序每趟并不使某些元素有序,而是使整体数据越来越接近有序,最后一趟排序使得所有数据有序
时间复杂度:1.3n 或者 (1+T)n

  1. @cal_time
  2. def mergesort(li, low, high):
  3. _mergesort(li, low, high)
  4.  
  5. def shell_sort(li):
  6. gap = len(li) // 2 # 取差值
  7. while gap >= 1: # 差值大于等于1
  8. for i in range(gap, len(li)): # 第一组差值往后循环
  9. tmp = li[i] # 后半区间的开始
  10. j = i - gap # 间隔gap个的前一个数
  11. while j >= 0 and tmp < li[j]: # 前一个数存在,tmp 小于前面的数
  12. li[j + gap] = li[j] # 大的放后面
  13. j -= gap # 减去一个差值,看是否存在前前个值
  14. li[j + gap] = tmp
  15. gap /= 2

时间复杂度:

希尔排序的时间复杂度是所取增量序列的函数,尚难准确分析。有文献指出,当增量序列为d[k]=2^(t-k+1)时,希尔排序的时间复杂度为O(n^1.5), 其中t为排序趟数。

稳定性: 不稳定

希尔排序效果:

练习题

  1. https://leetcode.com/problems/two-sum/?tab=Description

1、根据提供的整数,查找有序数列 返回下标范围

例如:a = [1,2,3,3,4,4,4,5,5,6,6]; val = 3; 返回(2,3)

  1. data = [1,2,3,3,3,4,4,5]
  2.  
  3. def bin_search(data, val):
  4. low = 0
  5. high = len(data) - 1
  6. while low <= high:
  7. mid = (low + high) // 2
  8. if data[mid] == val:
  9. left = mid
  10. right = mid
  11. while left >= 0 and data[left] == val:
  12. left -= 1
  13. while right <= high and data[right] == val:
  14. right += 1
  15. return (left + 1, right -1)
  16. elif data[mid] < val:
  17. low = mid + 1
  18. else:
  19. high = mid - 1
  20. print(bin_search(data, 5))

2、列表[1,2,5,4]与目标整数3,返回2个加起来等于目标数的下标

例如1+2=3,结果为(0, 1)

  1. data = [1, 2, 4, 5, 6]
  2. target = 3
  3.  
  4. # 方法一 循环试
  5. for i in range(len(data)):
  6. for j in range(i, len(data)):
  7. if data[i] + data[j] == target:
  8. print(i, j)
  9.  
  10. # 方法二 二分法
  11.  
  12. def bin_search(data, res, low, high):
  13.  
  14. while low <= high:
  15. mid = (low + high) // 2
  16. if data[mid] == res:
  17. return mid
  18. elif data[mid] < res:
  19. low = mid + 1
  20. else:
  21. high = mid - 1
  22.  
  23. def func2():
  24. import copy
  25. data2 = copy.deepcopy(data)
  26. for i in range(len(data2)):
  27. a = i
  28. b = bin_search(data2, target - data2[i], i + 1, len(data2) - 1)
  29. if b:
  30. return (data.index(data2[a]), data.index(data2.index(data2[b])))

3、约瑟夫问题

题目:有一组数首位比如0,1,2,3,4,5,6,7,8,以m为循环间隔数,杀掉从开始数第m个数,直到结束。

方法一:通过列表解决问题。

  1. # 约瑟夫问题
  2. # 1 2 3 4 5 6 7 8 9
  3. # 0 1 2 3 4 5 6 7 8
  4. # 循环去除隔4个的元素
  5. def func(n, m): # n 总人数,m隔的数
  6. people = [i for i in range(1, n + 1)]
  7. x = 0
  8. while len(people) > 0:
  9. dead_location = (x + (m - 1)) % len(people) # 当前位置 + 下次循环的m 跟总长度取余
  10. yield people.pop(dead_location)
  11. x = dead_location
  12.  
  13. print(list(func(9, 4)))
  14. # 时间复杂度o(n^2)

方法二:通过链表解决问题

  1. class LinkList:
  2. class Node:
  3. def __init__(self, item=None):
  4. self.item = item
  5. self.next = None
  6.  
  7. class LinkListIterator:
  8. def __init__(self, node):
  9. self.node = node
  10.  
  11. def __next__(self):
  12. if self.node:
  13. cur_node = self.node
  14. self.node = cur_node.next
  15. return cur_node.item
  16. else:
  17. raise StopIteration
  18. def __iter__(self):
  19. return self
  20.  
  21. def __init__(self, iterable=None):
  22. self.head = LinkList.Node(0)
  23. self.tail = self.head
  24. self.extend(iterable)
  25.  
  26. def append(self, obj):
  27. s = LinkList.Node(obj)
  28. self.tail.next = s
  29. self.tail = s
  30.  
  31. def extend(self, iterable):
  32. for obj in iterable:
  33. self.append(obj)
  34. self.head.item += len(iterable)
  35.  
  36. def remove_nth_node(self, node, m):
  37. for i in range(m - 2):
  38. node = node.next
  39. p = node.next
  40. node.next = p.next
  41. self.head.item -= 1
  42. return p
  43. # p 可以删, 可以自动回收
  44.  
  45. def __iter__(self):
  46. return self.LinkListIterator(self.head.next)
  47.  
  48. def __len__(self):
  49. return self.head.item
  50.  
  51. def __str__(self):
  52. return '<<' + ','.join(map(str, self)) + '>>'
  53.  
  54. def yuesefu_link(n, m):
  55. people = LinkList([i for i in range(1, n + 1)])
  56. people.tail.next = people.head.next
  57. x = people.head.next
  58. while len(people) > 0:
  59. p = people.remove_nth_node(x, m)
  60. x = p.next
  61. yield p.item
  62. print(list(yuesefu_link(9,4)))
  63. # 时间复杂度 o(nm)

Python 基础算法的更多相关文章

  1. Python基础算法综合:加减乘除四则运算方法

    #!usr/bin/env python# -*- coding:utf-8 -*-#python的算法加减乘除用符号:+,-,*,/来表示#以下全是python2.x写法,3.x以上请在python ...

  2. python基础算法

    一.简介 定义和特征 定义:算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制.也就是说,能够对一定规范的输入,在有限时 ...

  3. Python <算法思想集结>之初窥基础算法

    1. 前言 数据结构和算法是程序的 2 大基础结构,如果说数据是程序的汽油,算法则就是程序的发动机. 什么是数据结构? 指数据在计算机中的存储方式,数据的存储方式会影响到获取数据的便利性. 现实生活中 ...

  4. Python小白的发展之路之Python基础(一)

    Python基础部分1: 1.Python简介 2.Python 2 or 3,两者的主要区别 3.Python解释器 4.安装Python 5.第一个Python程序 Hello World 6.P ...

  5. Python基础+Pythonweb+Python扩展+Python选修四大专题 超强麦子学院Python35G视频教程

    [保持在百度网盘中的, 可以在观看,嘿嘿 内容有点多,要想下载, 回复后就可以查看下载地址,资源收集不易,请好好珍惜] 下载地址:http://www.fu83.cc/ 感觉文章好,可以小手一抖 -- ...

  6. 改写《python基础教程》中的一个例子

    一.前言 初学python,看<python基础教程>,第20章实现了将文本转化成html的功能.由于本人之前有DIY一个markdown转html的算法,所以对这个例子有兴趣.可仔细一看 ...

  7. python基础——sorted()函数

    python基础——sorted()函数 排序算法 排序也是在程序中经常用到的算法.无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小.如果是数字,我们可以直接比较,但如果是字符串或者两个d ...

  8. python基础——filter函数

    python基础——filter函数 Python内建的filter()函数用于过滤序列. 和map()类似,filter()也接收一个函数和一个序列.和map()不同的是,filter()把传入的函 ...

  9. Python基础:新式类的属性访问

    一.概述 二.准备工作 1.讨论对象 2.名词解释 三.实例绑定的属性访问 1.获取属性 一般规则 参考源码 示例验证 2.设置属性 一般规则 参考源码 示例验证 3.删除属性 一般规则 参考源码 示 ...

随机推荐

  1. JavaScrip相关知识总结

    1.javascript是一种基于对象的语言,其中有四个常用的“全局对象”的成员使用,因为没有“全局对象关键字global”而直接使用,所以感觉像违背了JavaScript基于对象编程的原则,但其实是 ...

  2. 关于 vscode 格式化自己的代码 使用shift+alt+f

    关于 vscode 格式化自己的代码 使用shift+alt+f,这样就好了

  3. Tree Restoration Gym - 101755F (并查集)

    There is a tree of n vertices. For each vertex a list of all its successors is known (not only direc ...

  4. 【清北学堂2018-刷题冲刺】Contest 7

    Task 1:小奇采药 [问题描述]  小奇是只天资聪颖的喵,他的梦想是成为世界上最伟⼤的医师.  为此,他想拜喵星球最有威望的医师为师.  医师为了判断他的资质,给他出了⼀个难题.  医师把他带到⼀ ...

  5. VirtualBox安装linux

    VBox相较于VMware要小巧,虚拟机该有的都有了.搭建记录下,学习... centos版本:CentOS-6.6-i386-bin-DVD1 VBox版本:6.0.4-128413-Win 之后可 ...

  6. 我们数学中常用的自然常数e代表什么?看完长知识了!

    我们在学习期间都接触过自然常数e,也知道e ≍ 2.718,学过极限的同学应该也知道 那么大家知道e的含义是什么吗?为啥叫“自然常数”? e的含义可以用一个计算利息的例子来解释. 假如你有1块钱,银行 ...

  7. mysql报错汇总

    一.启动mysql: Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'  #/var/r ...

  8. C++中string、char *、char[]的转换

    头段时间有人问过我这个问题,可是我一点头绪都没有,直接说不会.现在从网上找了点资料,看了看,知道点东西了. 一.string转char*. 主要有三种方法可以将str转换为char*类型,分别是:da ...

  9. Java Web服务收到请求时线程的情况

    Web请求线程的状态 在开发中,突然想到了这样的一个问题, Java对每一次Web的请求,是否都会创建一条线程去进行处理呢?也就是说,当一个Class的方法同时有1000个请求访问时,线程是如何运作的 ...

  10. Web API中的路由(二)——属性路由

    一.属性路由的概念 路由让webapi将一个uri匹配到对应的action,Web API 2支持一种新类型的路由:属性路由.顾名思义,属性路由使用属性来定义路由.通过属性路由,我们可以更好地控制We ...