递归,排序
Posted perfey
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了递归,排序相关的知识,希望对你有一定的参考价值。
面试题: 归并算法 两个有序序列进行归并 l1 = [1, 2, 5, 6, 8,10] l2 = [3, 4, 7,9,12] l3 = [] i = 0 j = 0 while i < len(l1) and j < len(l2): if l1[i] < l2[j]: l3.append(l1[i]) i += 1 else: l3.append(l2[j]) j = j + 1 while i < len(l1): l3.append(l1[i]) i += 1 while i < len(l2): l3.append(l2[i]) i += 1 print(l3) 求阶乘后结果的末尾0的个数 n= 5 rus = 1 while n>0: rus = rus*n n-=1 s = str(rus) count =0 s= ‘120000000‘ for i in range(len(s)-1,-1,-1): if s[i]==‘0‘: count +=1 else: break print(count) 字典排序: alist =[{‘name‘:‘a‘,‘age‘:20},{‘name‘:‘b‘,‘age‘:30},{‘name‘:‘c‘,‘age‘:25}] alist = sorted(alist,key=lambda dic:dic[‘age‘]) print(alist) 斐波那契数列 a, b, c = 1, 2, 3 n = 400000 i = 0 while a < n: print(a) i += 1 a, b, c = b, c, b + c print(i) def fib(n): li = [1,1] for i in range(2,n+1): li.append(li[-1]+li[-2]) return li[-1] def fib(n): if n ==0 or n == 1: return 1 a = 1 b = 1 c = 1 for i in range(2,n+1): a = b b = c c = a + b return c # 青蛙跳台阶问题 def func(n): if n == 0: return 0 if n == 1: return 1 if n == 2: return 2 return func(n - 1) + func(n - 2) print(func(4)) 递归 汉诺塔问题 def hanoi(n,A,B,C): if n>0: hanoi(n-1,A,C,B) print(‘%s -> %s‘ % (A,C)) hanoi(n-1,B,A,C) hanoi(2,‘A‘,‘B‘,‘C‘) 二分查找 def bin_search(li, val): ‘‘‘使用low和high标注索引,mid为中间索引,这里的索引代表指针,每次以中间值比较大小,比较完后改变索引‘‘‘ low = 0 high = len(li) - 1 while low <= high: mid = (high - low) // 2 if li[mid] > val: high = mid - 1 elif li[mid] < val: low = mid + 1 else: return mid return -1 使用and代替if语句 def func(): print(‘aaa‘) x = -3 x > 0 and func() # 等价于 if x > 0: func() # 所以可以使用and代替if语句() # a and b <==> a if a == 0 else b # a or b <==> b if a == 0 else a 十种排序算法 # 推荐:https://blog.csdn.net/yangnianjinxin/article/details/77918882 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法 low逼三人组 冒泡(稳定 o(n2)) # 走n趟,没趟交换比较选出最大的 def bubble_sort(li): for i in range(len(li) - 1): exchange = False # 没有交换表示已经排好序了,就不用再继续执行了 for j in range(len(li) - 1 - i): if li[j] > li[j + 1]: li[j], li[j + 1] = li[j + 1], li[j] exchange = True if not exchange: return 选择排序(不稳定) # 一趟遍历选择记录中最小的数,放到第一个位置 # 再一趟遍历记录剩余列表中最小的数,继续放置 def select_sort(li): for i in range(len(li) - 1): min_pos = i for j in range(i + 1, len(li)): if li[j] < li[min_pos]: min_pos = j li[min_pos], li[j] = li[j], li[min_pos] 插入排序 # 列表分为有序区和无序区两个部分,最初有序区只有一个元素 # 每次从无序区选择一个元素,插入到有序区的位置,直到无序区变空 # 类似于玩纸牌时的插牌 # 可以优化空间使用二分查找来寻找插入点(并没有什么卵用) def insert_sort(li): for i in range(1, len(li)): # 无序区 j = i-1 # 有序区最后一个数 tmp = li[i] while j >= 0 and li[j] > tmp: # 有序区从大到小逐一比较,直到有序区数小于li[i] li[j+1] = li[j] j -= 1 li[j+1] = tmp 牛逼三人组(o(nlogn)) 快排 # 取一个元素p(第一元素),使元素p归位 # 列表被p分为两部分,左边的都比p小,右边的都比p大 # 递归完成排序 def _quick_sort(li, left, right): if left < right: # 至少两个元素 mid = partition(li, left, right) _quick_sort(li, left, mid-1) _quick_sort(li, mid+1, right) def quick_sort(li): _quick_sort(li, 0, len(li)-1) def partition(li, left, right): i = random.randint(left, right) # 随机选一个数,防止最坏情况 li[left], li[i] = li[i], li[left] tmp = li[left] while left < right: while left < right and li[right] >= tmp: #从右开始选,直到找到一个小于tmp的数,把这个数填在left位置 right -= 1 li[left] = li[right] while left < right and li[left] <= tmp: #从左开始选,直到找到一个大于tmp的数,把这个数填在right位置 left += 1 li[right] = li[left] li[left] = tmp return left # 一行代码实现快排 # 这样空间复杂度会高 def quicksortshort(arr): return [] if arr==[] else quicksortshort([y for y in arr[1:] if y<arr[0]]) + [arr[0]]+ quicksortshort([y for y in arr[1:] if y>=arr[0]]) 堆排 # 1,建立堆 # 2,得到堆顶元素,为最大元素 # 3,去掉堆顶,将堆最后一个元素放到堆顶,此时可通过一个调整重新使堆有序 # 4,堆顶元素为第二大元素 # 5,重复步骤3,直到堆变空 def sift(li, low, high): # 调整,从子孩子中选出最大的和父节点比较,如果大于父节点就和父节点的值交换,然后父节点的值继续和子节点的子节点进行比较 # low 表示根位置 high 表示最后元素的位置 tmp = li[low] i = low # i指向空位 j = 2 * i + 1 # j指向孩子 # 把tmp写回来有两种条件 1. tmp > li[j] 2. j位置没有值 (也就是i已经是叶子了) while j <= high: # 对应退出条件2 if j + 1 <= high and li[j+1] > li[j]: # 如果右孩子存在且右孩子更大 j += 1 if li[j] > tmp: li[i] = li[j] i = j j = 2 * i + 1 else: # 对应退出条件1 break li[i] = tmp li = [3,5,6,2,0,4,1,9,8,7] def heap_sort(li): n = len(li) # 1. 建立堆 for low in range(n//2-1, -1, -1): # li = [3,5,6,2,0,4,1,9,8,7] ‘‘‘ 3(索引0) 5(1) 6(2) 2(3) 0(4) 4(5) 1(6) 9(7) 8(8) 7(9) ‘‘‘ # 如 n=10时,low的值依次是 4,3,2,1,0 从最后的非叶子节点开始调整 sift(li, low, n-1) print(li) # 此时的li已经是一个大根堆了 # [9, 8, 6, 5, 7, 4, 3, 0, 1, 2] ‘‘‘ 9(索引0) 8(1) 6(2) 5(3) 7(4) 4(5) 3(6) 0(7) 1(8) 2(9) ‘‘‘ # 2. 挨个出数 退休-棋子-调整 for high in range(n-1, -1, -1): # high 的值 9,8,7,6,,5,4,3,2,1,0 li[0], li[high] = li[high], li[0] # 这样交换后最大的就变到了列表的最后位置上, sift(li, 0, high-1) # 然后调整的时候就不把已经退休的(最大的)考虑在内了 python内置的堆模块 import heapq li = [2,5,7,8,9,6,1,4,3] heapq.heapify(li) #调整变为小根堆 print(li) # [1, 3, 2, 4, 9, 6, 7, 5, 8] heapq.heappush(li, 0) # 插入新值,自动调整为小根堆 print(li) # [0, 1, 2, 4, 3, 6, 7, 5根堆, 8, 9] print(heapq.heappop(li)) # 堆顶退休(最小值),继续调整为小 print(heapq.heappop(li)) print(heapq.nlargest(5, li)) # 输出最大的5个数 # [9, 8, 7, 6, 5] print(heapq.nsmallest(5, li)) # 输出最小的5个数 # [2, 3, 4, 5, 6] 列表中取出前k大的数 # 1,取列表前k个元素建立一个小根堆,堆顶就是这个堆中最小的数,也是这个堆中第k大的数 # 2,依次向后遍历原列表,对于列表中的元素,如果小于堆顶,则忽略该元素,如果大于堆顶则将堆顶更换为改元素,并且对堆进行一次调整 # 3,遍历列表所有元素后,倒序弹出堆顶 归并 def merge(li, low, mid, high): li_tmp = [] i = low j = mid + 1 while i <= mid and j <= high: if li[i] <= li[j]: li_tmp.append(li[i]) i += 1 else: li_tmp.append(li[j]) j += 1 while i <= mid: li_tmp.append(li[i]) i += 1 while j <= high: li_tmp.append(li[j]) j += 1 for i in range(len(li_tmp)): # 把归并排好的两个列表放回到li中 li[i+low] = li_tmp[i] def _merge_sort(li, low, high): if low < high: # 2个元素及以上 mid = (low + high) // 2 _merge_sort(li, low, mid) _merge_sort(li, mid+1, high) #print(li[low:mid+1], li[mid+1:high+1]) merge(li, low, mid, high) #print(li[low:high + 1]) def merge_sort(li): _merge_sort(li, 0, len(li)-1) 没什么人用的排序 基数排序 希尔排序 桶排序 二叉树 列表中索引:父节点 -> 左孩子节点 i -> 2i+1 父节点 -> 右孩子节点 i -> 2i+2 孩子节点 -> 父节点 i -> (i-1)//2 堆顶 i = 0 所有父节点 i_list =[i for i in range(len(li)//2)] 大根堆:一个完全二叉树,满足任一节点都比其孩子节点大 小根堆:一个完全二叉树,满足任一节点都比其孩子节点小 当根节点的左右子树都是堆时(这里的示例是大根堆),可以通过一次向下调整来将其变换成一个堆
以上是关于递归,排序的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript - 代码片段,Snippets,Gist
8种面试经典!排序详解--选择,插入,希尔,冒泡,堆排,3种快排,快排非递归,归并,归并非递归,计数(图+C语言代码+时间复杂度)
8种面试经典排序详解--选择,插入,希尔,冒泡,堆排,3种快排及非递归,归并及非递归,计数(图+C语言代码+时间复杂度)
8种面试经典排序详解--选择,插入,希尔,冒泡,堆排,3种快排及非递归,归并及非递归,计数(图+C语言代码+时间复杂度)