├── Code4_UnionFindSet.py ├── Part0_Sort ├── Code11_MaxGap.py ├── Code11_MinSum.py ├── Code11_NetherlandsFlag.py ├── Code11_heapSort.py ├── Code1_BubbleSort.py ├── Code1_BucketSort.py ├── Code1_HeapSort.py ├── Code1_InsertionSort.py ├── Code1_MergeSort.py ├── Code1_QuickSort.py ├── Code1_SelectionSort.py ├── Code21_KMP_ShortestHaveTwice.py ├── Code2_BFPRT.py ├── Code2_KMP.py └── Code2_Manacher.py ├── Part1_Array ├── Code3_Array_To_Queue.py ├── Code3_Array_To_Stack.py ├── Code3_CatDogQueue.py ├── Code3_FindNumInSortedMatrix.py ├── Code3_GetMinStack.py ├── Code3_Queue_To_Stack.py ├── Code3_RandomPool.py ├── Code3_Stack_To_Queue.py ├── Code3_ZigZagPrintMatrix.py ├── Code3_spiralOrderPrintMatrix.py ├── Code4_BinarySearch.py ├── Code4_IsLands.py ├── Code4_findLessValueIndex.py ├── Code8_GetKNumsRand.py ├── Code8_MaxABS.py ├── Code8_MaxRecSize.py ├── Code8_MaxSumOfSubArray.py ├── Code8_MaxSumOfSubMatrix.py ├── Code8_SlidingWindowMaxArray.py ├── Code8_SubArrayNumber.py ├── helixWriteNumber.py └── maxMulValue.py ├── Part2_LinkedList ├── Code3_CopyListWithRandom.py ├── Code3_FindFirstIntersectNode.py ├── Code3_LinkedListIsPalindrome.py ├── Code3_PrintCommonPart.py ├── Code3_ReverseList.py └── Code3_SmallerEqualBigger.py ├── Part3_Tree ├── Code4_GetNextNode.py ├── Code4_PaperFolding.py ├── Code4_PreInPosRecur.py ├── Code4_PrintTree.py ├── Code5_TrieTree.py ├── Code8_MaxTreeOfArray.py ├── Code8_Morris.py ├── Code9_BSTMaxTopoSize.py ├── Code9_FindMaxBST.py ├── Code9_IsBalance.py ├── Code9_SkipList.py └── lowestAncestor.py ├── Part4_HeapStructure ├── Code4_IPO.py ├── Code4_LessMoney.py └── Code4_MedianHolder.py ├── Part5_Graph ├── Code5_BFS.py ├── Code5_DFS.py ├── Code5_DefineGraph.py ├── Code5_Dijkstra.py ├── Code5_Kruskal.py ├── Code5_Prim.py └── Code5_TopologySort.py ├── Part6_Recursion_DP ├── Code7_CoinMethodNum.py ├── Code7_Fibonacci.py ├── Code7_Knapsack.py ├── Code7_MinCoinNum.py ├── Code7_MinCoinNum_2.py ├── Code7_MinPathSum.py ├── Code7_r_Factorial.py ├── Code7_r_Hanio.py ├── Code7_r_PrintAllPermutation.py ├── Code7_r_PrintAllSubSequence.py ├── Code7_r_reverseStack.py └── Code8_MinDistance.py ├── Part7_StringQuestion ├── Code8_IsDeformation.py ├── Code8_IsRatation.py ├── Code8_rotateWord.py └── maxUnique.py ├── README.md └── getPower.py /Code4_UnionFindSet.py: -------------------------------------------------------------------------------- 1 | """并查集""" 2 | 3 | class Data(object): 4 | """数据的类型与结构(支持任何类型) 5 | """ 6 | 7 | class unionFindSets(object): 8 | """并查集类 9 | """ 10 | def __init__(self): 11 | """初始化结构""" 12 | self.fatherMap = dict() 13 | self.sizeMap = dict() 14 | 15 | def makeSets(self, datas): 16 | """初始化并查集 17 | """ 18 | self.fatherMap.clear() 19 | self.sizeMap.clear() 20 | for each in datas: 21 | self.fatherMap[each] = each 22 | self.sizeMap[each] = 1 23 | 24 | 25 | def findFather(self, data): 26 | """查找数据的父节点,查找过程中打平链 27 | """ 28 | father = self.fatherMap.get(data) 29 | if father != data: 30 | father = self.findFather(father) 31 | 32 | self.fatherMap[data] = father 33 | return father 34 | 35 | 36 | def union(self, a, b): 37 | """合并a,b所在的两个集合 38 | """ 39 | if a == None or b == None: 40 | return None 41 | 42 | aFather = self.findFather(a) 43 | bFather = self.findFather(b) 44 | 45 | if aFather != bFather: 46 | aSize = self.sizeMap.get(aFather) 47 | bSize = self.sizeMap.get(bFather) 48 | if aSize > bSize: 49 | self.fatherMap[bFather] = aFather 50 | self.sizeMap[aFather] = aSize + bSize 51 | else: 52 | self.fatherMap[aFather] = bFather 53 | self.sizeMap[bFather] = aSize + bSize -------------------------------------------------------------------------------- /Part0_Sort/Code11_MaxGap.py: -------------------------------------------------------------------------------- 1 | """最大间隔问题: 无序数组,返回排完序之后相邻两数的最大差值!要求:时间复杂度O(n) 2 | """ 3 | import sys 4 | import random 5 | import copy 6 | def generateRandomArray(maxLen, maxSize): 7 | arr = [] 8 | for _ in range(int(random.random() * maxLen + 1)): 9 | arr.append(int(random.random() * maxSize + 1)) 10 | return arr 11 | 12 | def maxGap(arr): 13 | length = len(arr) 14 | maxVal, minVal = -sys.maxsize, sys.maxsize 15 | for i in range(length): 16 | maxVal, minVal = max(maxVal, arr[i]), min(minVal, arr[i]) 17 | 18 | if maxVal == minVal: return 0 ###【重点】 19 | 20 | bNum = length + 1 21 | mins = [maxVal] * bNum 22 | maxs = [minVal] * bNum 23 | hasNum = [False] * bNum 24 | for i in range(length): 25 | bid = (arr[i]-minVal) * length // (maxVal-minVal) ### 26 | mins[bid] = min(mins[bid], arr[i]) 27 | maxs[bid] = max(maxs[bid], arr[i]) 28 | hasNum[bid] = True 29 | 30 | res = 0 31 | lastMax = maxs[0] 32 | for bid in range(1, bNum): 33 | if hasNum[bid]: 34 | res = max(res, mins[bid]-lastMax) 35 | lastMax = maxs[bid] 36 | 37 | return res 38 | 39 | 40 | def comparator(arr): 41 | arr.sort() 42 | res = 0 43 | for i in range(1, len(arr)): 44 | res = max(res, arr[i]-arr[i-1]) 45 | 46 | return res 47 | 48 | if __name__ == '__main__': 49 | iterNum = 5000 50 | maxLen = 100 51 | maxSize = 100 52 | succeed = True 53 | 54 | while iterNum > 0: 55 | iterNum -= 1 56 | 57 | arr = generateRandomArray(maxLen, maxSize) 58 | arr_copy = copy.copy(arr) 59 | 60 | res = maxGap(arr) 61 | res1 = comparator(arr_copy) 62 | 63 | if res != res1: 64 | succeed = False 65 | break 66 | 67 | print('nice!' if succeed == True else 'Fucking Ficked!') 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /Part0_Sort/Code11_MinSum.py: -------------------------------------------------------------------------------- 1 | """给定一个数组1,3,2,4,3,计算所有小和 2 | """ 3 | import random 4 | import copy 5 | 6 | def minSum(arr): 7 | if arr == None or len(arr) < 2: 8 | return 0 9 | 10 | return subMergeSort(arr, 0, len(arr)-1) 11 | 12 | def subMergeSort(arr, l, r): 13 | if l >= r: return 0 14 | mid = l + (r-l)//2 15 | return subMergeSort(arr, l, mid) + subMergeSort(arr, mid+1, r) + merge(arr, l, mid, r) 16 | 17 | def merge(arr, l, mid, r): 18 | res = 0 19 | 20 | p1, p2 = l, mid+1 21 | helpArr = [] 22 | 23 | while p1 <= mid and p2 <= r: 24 | if arr[p1] < arr[p2]: 25 | res += arr[p1] * (r-p2+1) ### 26 | helpArr.append(arr[p1]); p1+=1 27 | else: 28 | helpArr.append(arr[p2]); p2+=1 29 | 30 | while p1 <= mid: 31 | helpArr.append(arr[p1]); p1+=1 32 | while p2 <= r: 33 | helpArr.append(arr[p2]); p2+=1 34 | 35 | for i in range(len(helpArr)): 36 | arr[l+i] = helpArr[i] 37 | 38 | return res 39 | 40 | 41 | def comparator(arr): 42 | if arr == None and len(arr) < 2: 43 | return 0 44 | 45 | res = 0 46 | for i in range(1, len(arr)): 47 | for j in range(i): 48 | res += arr[j] if arr[j] < arr[i] else 0 49 | 50 | return res 51 | 52 | def generateRandomArray(maxLen, maxVal): 53 | arr = [] 54 | length = int(maxLen * random.random() + 1) 55 | for _ in range(length): 56 | arr.append(int(maxVal * random.random() + 1)) 57 | return arr 58 | 59 | 60 | 61 | if __name__ == '__main__': 62 | interNum = 5000 63 | maxLen = 100 64 | maxVal = 100 65 | succeed = True 66 | 67 | while interNum > 0: 68 | interNum -= 1 69 | 70 | arr = generateRandomArray(maxLen, maxVal) 71 | arrCopy = copy.copy(arr) 72 | 73 | if comparator(arr) != minSum(arrCopy): 74 | succeed = False 75 | break 76 | print(arrCopy) 77 | 78 | print('nice!' if succeed == True else 'Fucking Fucked!') -------------------------------------------------------------------------------- /Part0_Sort/Code11_NetherlandsFlag.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def generateRandomArray(length): 4 | arr = [] 5 | for _ in range(length): 6 | arr.append(int(random.random() * 3)) 7 | 8 | return arr 9 | 10 | 11 | def partition(arr, l, r, p): 12 | less, more = l-1, r+1 13 | 14 | while l < more: 15 | if arr[l] < p: 16 | less += 1; arr[less], arr[l] = arr[l], arr[less]; l += 1 17 | elif arr[l] > p: 18 | more -= 1; arr[more], arr[l] = arr[l], arr[more] 19 | else: 20 | l += 1 21 | return less+1, more-1 22 | 23 | 24 | if __name__ == '__main__': 25 | 26 | arr = generateRandomArray(10) 27 | print(arr) 28 | 29 | left, right = partition(arr, 0, len(arr)-1, 1) 30 | print(arr) 31 | print(left, right) -------------------------------------------------------------------------------- /Part0_Sort/Code11_heapSort.py: -------------------------------------------------------------------------------- 1 | """查找前k个最小的数,用堆排序实现 【注:没有BFPRT好】 2 | """ 3 | 4 | def getMinKNumsByHeap(arr, k): 5 | """通过建立k个元素大根堆 找到无序数组中 前k个最小的数 6 | """ 7 | if arr == None or k <= 0 or len(arr) <= k: 8 | return arr 9 | 10 | res = [arr[0]] 11 | for i in range(1, k): 12 | res.append(arr[i]) 13 | insertHeap(res, i) 14 | 15 | for i in range(k, len(arr)): 16 | if res[0] > arr[i]: 17 | res[0] = arr[i] 18 | heapify(res, 0, k) 19 | 20 | return res 21 | 22 | 23 | def insertHeap(arr, index): 24 | parent = (index-1) >> 1 25 | while parent >= 0 and arr[parent] < arr[index]: 26 | arr[parent], arr[index] = arr[index], arr[parent] 27 | index = parent 28 | parent = (index-1) >> 1 29 | 30 | 31 | def heapify(arr, index, length): 32 | 33 | left = 2 * index + 1 34 | while left < length: 35 | largest = left+1 if left+1 < length and arr[left+1] > arr[left] else left 36 | largest = index if arr[index] >= arr[largest] else largest 37 | 38 | if largest == index: 39 | break 40 | 41 | arr[index], arr[largest] = arr[largest], arr[index] 42 | index = largest 43 | left = 2 * index + 1 44 | 45 | 46 | 47 | def generateRandomArray(maxLen, maxVal): 48 | length = int(random.random() * maxLen) + 1 49 | 50 | arr = [] 51 | for _ in range(length): 52 | arr.append(int(random.random() * maxVal) + 1) 53 | return arr 54 | 55 | 56 | import copy 57 | import random 58 | 59 | if __name__ == '__main__': 60 | iterNum = 5000 61 | maxLen = 100 62 | maxVal = 100 63 | succeed = True 64 | 65 | for _ in range(iterNum): 66 | arr = generateRandomArray(maxLen, maxVal) 67 | arrCopy = copy.copy(arr) 68 | k = int(random.random() * len(arr)) + 1 69 | 70 | res1 = getMinKNumsByHeap(arr, k) 71 | res1.sort() 72 | arrCopy.sort() 73 | res2 = arrCopy[:k] 74 | 75 | if res1 != res2: 76 | succeed = False 77 | break 78 | 79 | print("nice" if succeed == True else "fucking fucked!") 80 | print(res1) 81 | print(res2) 82 | 83 | -------------------------------------------------------------------------------- /Part0_Sort/Code1_BubbleSort.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def bubbleSort(arr, length): 4 | """ 5 | 冒泡排序 6 | """ 7 | 8 | if arr == None or length < 2: 9 | return None 10 | 11 | while length > 0: 12 | length -= 1 13 | 14 | for i in range(length): 15 | if arr[i] > arr[i+1]: 16 | arr[i], arr[i+1] = arr[i+1], arr[i] 17 | 18 | 19 | def generateUnOrderArr(length): 20 | arr = [] 21 | 22 | for _ in range(length): 23 | arr.append(int(random.random()*100)) 24 | 25 | return arr 26 | 27 | 28 | 29 | if __name__ == '__main__': 30 | i = 0 31 | chios = True 32 | while i < 5000: 33 | i += 1 34 | 35 | arr = generateUnOrderArr(int(random.random() * 100)) 36 | arrCopy = arr.copy() 37 | 38 | arr.sort() 39 | bubbleSort(arrCopy, len(arrCopy)) 40 | 41 | if arr != arrCopy: 42 | chios = False 43 | break 44 | 45 | print("yes" if chios == True else "err") 46 | print(arr) 47 | print(arrCopy) 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Part0_Sort/Code1_BucketSort.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import copy 3 | import random 4 | 5 | def bucketSort(arr): 6 | if arr == None or len(arr) < 2: 7 | return None 8 | 9 | maxVal = -sys.maxsize 10 | for i in range(len(arr)): 11 | maxVal = maxVal if maxVal > arr[i] else arr[i] 12 | 13 | bucket = [0] * (maxVal + 1) 14 | for i in range(len(arr)): 15 | bucket[arr[i]] += 1 16 | 17 | i = 0 18 | for j in range(len(bucket)): 19 | while bucket[j] > 0: 20 | arr[i] = j; i += 1; bucket[j] -= 1 21 | 22 | 23 | def generateRandomArray(maxLen, maxVal): 24 | arr = [] 25 | length = int(maxLen * random.random() + 1) 26 | for _ in range(length): 27 | arr.append(int(maxVal * random.random() + 1)) 28 | return arr 29 | 30 | if __name__ == '__main__': 31 | 32 | interNum = 5000 33 | maxLen = 100 34 | maxVal = 100 35 | succeed = True 36 | 37 | while interNum > 0: 38 | interNum -= 1 39 | 40 | arr = generateRandomArray(maxLen, maxVal) 41 | arrCopy = copy.copy(arr) 42 | 43 | arr.sort() 44 | bucketSort(arrCopy) 45 | 46 | if arr != arrCopy: 47 | succeed = False 48 | break 49 | print(arrCopy) 50 | 51 | print('nice!' if succeed == True else 'Fucking Fucked!') -------------------------------------------------------------------------------- /Part0_Sort/Code1_HeapSort.py: -------------------------------------------------------------------------------- 1 | """堆排序""" 2 | 3 | import random 4 | import copy 5 | 6 | def heapify(arr, index, length): 7 | """堆化 8 | """ 9 | left = 2 * index + 1 10 | while left < length: 11 | largest = left + 1 if (left+1) < length and arr[left+1] > arr[left] else left 12 | largest = index if arr[index] >= arr[largest] else largest 13 | 14 | if largest == index: 15 | break 16 | 17 | arr[largest], arr[index] = arr[index], arr[largest] 18 | index = largest 19 | left = 2 * index + 1 20 | 21 | 22 | def insertHeap(arr, index): 23 | """index位置元素插入堆 24 | """ 25 | par_i = (index - 1) // 2 26 | while par_i >= 0 and arr[index] > arr[par_i]: 27 | arr[par_i], arr[index] = arr[index], arr[par_i] 28 | index = par_i 29 | par_i = (index - 1) // 2 30 | 31 | 32 | def heapSort(arr): 33 | """堆排序 34 | """ 35 | if arr == None or len(arr) < 2: 36 | return arr 37 | 38 | length = len(arr) 39 | for i in range(1, length): 40 | insertHeap(arr, i) 41 | 42 | length -= 1 43 | arr[0], arr[length] = arr[length], arr[0] 44 | 45 | while length > 1: 46 | heapify(arr, 0, length) 47 | length -= 1 48 | arr[0], arr[length] = arr[length], arr[0] 49 | 50 | 51 | 52 | def generateRandomArray(max_len, max_val): 53 | """生成随机数组 54 | """ 55 | length = int(random.random() * max_len + 1) 56 | 57 | arr = [] 58 | for _ in range(length): 59 | arr.append(int(random.random() * max_val + 1)) 60 | 61 | return arr 62 | 63 | 64 | if __name__ == '__main__': 65 | iterNum = 5000 66 | max_len = 100 67 | max_val = 100 68 | succeed = True 69 | 70 | while iterNum > 0: 71 | iterNum -= 1 72 | 73 | arr = generateRandomArray(max_len, max_val) 74 | arr_copy = copy.copy(arr) 75 | 76 | arr.sort() 77 | heapSort(arr_copy) 78 | 79 | if arr != arr_copy: 80 | succeed = False 81 | break 82 | 83 | print(arr_copy) 84 | print("today is a beatiful day!" if succeed else "What's the Fucked!") 85 | 86 | -------------------------------------------------------------------------------- /Part0_Sort/Code1_InsertionSort.py: -------------------------------------------------------------------------------- 1 | import random 2 | import copy 3 | 4 | def insertionSort(arr, length): 5 | """ 6 | 插入排序 7 | """ 8 | if arr == None or length < 2: 9 | return None 10 | 11 | for un_i in range(1, length): 12 | o_i = un_i - 1 13 | while o_i >= 0 and arr[o_i] > arr[o_i+1]: 14 | arr[o_i], arr[o_i+1] = arr[o_i+1], arr[o_i] 15 | o_i -= 1 16 | 17 | 18 | def generateRandomArray(maxSize, maxValue): 19 | 20 | arr = [] 21 | length = int(maxSize*random.random()+1) 22 | 23 | for _ in range(length): 24 | arr.append(int(maxValue*random.random() + 1)) 25 | 26 | return arr 27 | 28 | 29 | if __name__ == '__main__': 30 | interNum = 5000 31 | maxSize = 100 32 | maxValue = 1000 33 | succeed = True 34 | 35 | while interNum > 0: 36 | interNum -= 1 37 | arr = generateRandomArray(maxSize, maxValue) 38 | arrCopy = copy.copy(arr) 39 | 40 | arr.sort() 41 | insertionSort(arrCopy, len(arrCopy)) 42 | 43 | if arr != arrCopy: 44 | succeed = False 45 | break 46 | 47 | print('nice!' if succeed == True else 'Fucking Fucked!') 48 | 49 | print(arr) 50 | print(arrCopy) 51 | 52 | -------------------------------------------------------------------------------- /Part0_Sort/Code1_MergeSort.py: -------------------------------------------------------------------------------- 1 | import random 2 | import copy 3 | 4 | def merge(arr, l, mid, r): 5 | helpArr = [] 6 | p1, p2 = l, mid+1 7 | while p1<=mid and p2<=r: 8 | if arr[p1] < arr[p2]: 9 | helpArr.append(arr[p1]); p1+=1 10 | else: 11 | helpArr.append(arr[p2]); p2+=1 12 | 13 | while p1 <= mid: 14 | helpArr.append(arr[p1]); p1+=1 15 | while p2 <= r: 16 | helpArr.append(arr[p2]); p2+=1 17 | 18 | for i in range(len(helpArr)): 19 | arr[l+i] = helpArr[i] 20 | 21 | 22 | def subMergeSort(arr, l, r): 23 | if l >= r: return None 24 | 25 | mid = l + (r-l)//2 26 | subMergeSort(arr, l, mid) 27 | subMergeSort(arr, mid+1, r) 28 | merge(arr, l, mid, r) 29 | 30 | def mergeSort(arr): 31 | if arr == None or len(arr) < 2: 32 | return arr 33 | 34 | subMergeSort(arr, 0, len(arr)-1) 35 | 36 | 37 | def generateRandomArray(maxLen, maxVal): 38 | arr = [] 39 | length = int(maxLen * random.random() + 1) 40 | for _ in range(length): 41 | arr.append(int(maxVal * random.random() + 1)) 42 | return arr 43 | 44 | 45 | if __name__ == '__main__': 46 | interNum = 5000 47 | maxLen = 100 48 | maxVal = 100 49 | succeed = True 50 | 51 | while interNum > 0: 52 | interNum -= 1 53 | 54 | arr = generateRandomArray(maxLen, maxVal) 55 | arrCopy = copy.copy(arr) 56 | 57 | arr.sort() 58 | mergeSort(arrCopy) 59 | 60 | if arr != arrCopy: 61 | succeed = False 62 | break 63 | print(arrCopy) 64 | 65 | print('nice!' if succeed == True else 'Fucking Fucked!') -------------------------------------------------------------------------------- /Part0_Sort/Code1_QuickSort.py: -------------------------------------------------------------------------------- 1 | import random 2 | import copy 3 | 4 | def partition(arr, l, r): 5 | less, more = l-1, r 6 | 7 | while l < more: 8 | if arr[l] < arr[r]: 9 | less += 1 10 | arr[less], arr[l] = arr[l], arr[less] 11 | l += 1 12 | elif arr[l] > arr[r]: 13 | more -= 1 14 | arr[more], arr[l] = arr[l], arr[more] 15 | else: 16 | l += 1 17 | 18 | arr[more], arr[r] = arr[r], arr[more] 19 | 20 | return less+1, more 21 | 22 | 23 | def subQuickSort(arr, l, r): 24 | if l >= r: 25 | return None 26 | 27 | randNum = l + int(random.random() * (r - l + 1)) 28 | arr[r], arr[randNum] = arr[randNum], arr[r] 29 | [begin, end] = partition(arr, l, r) 30 | 31 | subQuickSort(arr, l, begin-1) 32 | subQuickSort(arr, end+1, r) 33 | 34 | 35 | def quickSort(arr): 36 | if arr == None or len(arr) < 2: 37 | return None 38 | 39 | length = len(arr) 40 | subQuickSort(arr, 0, length-1) 41 | 42 | 43 | def generateRandomArray(maxLen, maxVal): 44 | arr = [] 45 | length = int(maxLen * random.random() + 1) 46 | for _ in range(length): 47 | arr.append(int(maxVal * random.random() + 1)) 48 | return arr 49 | 50 | if __name__ == '__main__': 51 | 52 | interNum = 5000 53 | maxLen = 100 54 | maxVal = 100 55 | succeed = True 56 | 57 | while interNum > 0: 58 | interNum -= 1 59 | 60 | arr = generateRandomArray(maxLen, maxVal) 61 | arrCopy = copy.copy(arr) 62 | 63 | arr.sort() 64 | quickSort(arrCopy) 65 | 66 | if arr != arrCopy: 67 | succeed = False 68 | break 69 | print(arrCopy) 70 | 71 | print('nice!' if succeed == True else 'Fucking Fucked!') -------------------------------------------------------------------------------- /Part0_Sort/Code1_SelectionSort.py: -------------------------------------------------------------------------------- 1 | import random 2 | import copy 3 | 4 | def selectionSort(arr, length): 5 | """ 6 | 选择排序 7 | """ 8 | for i in range(length-1): 9 | min_i = i 10 | for j in range(i+1, length): 11 | if arr[min_i] > arr[j]: 12 | min_i = j 13 | arr[i], arr[min_i] = arr[min_i], arr[i] 14 | 15 | def generateRandomArray(maxLength, maxValue): 16 | arr = [] 17 | length = int(maxLength * random.random() + 1) 18 | 19 | for _ in range(length): 20 | arr.append(int(maxValue*random.random() + 1)) 21 | 22 | return arr 23 | 24 | 25 | if __name__ == '__main__': 26 | interNum = 5000 27 | maxLength = 100 28 | maxValue = 100 29 | succeed = True 30 | 31 | while interNum > 0: 32 | interNum -= 1 33 | arr = generateRandomArray(maxLength, maxValue) 34 | arrCopy = copy.copy(arr) 35 | 36 | arr.sort() 37 | selectionSort(arrCopy, len(arrCopy)) 38 | 39 | if arr != arrCopy: 40 | succeed = False 41 | break 42 | 43 | print('nice!' if succeed == True else 'Fucking Fucked!') 44 | 45 | arr = generateRandomArray(maxLength, maxValue) 46 | print(arr) 47 | selectionSort(arr,len(arr)) 48 | print(arr) 49 | -------------------------------------------------------------------------------- /Part0_Sort/Code21_KMP_ShortestHaveTwice.py: -------------------------------------------------------------------------------- 1 | """将一个小字符串abcabc扩展为一个大的字符串abcabcabc,要求大字符串包含小字符串两次""" 2 | def getStartIndex(str1): 3 | 4 | nextArr = [-1, 0] 5 | cn = 0 6 | while len(nextArr) < len(str1)+1: 7 | if str1[len(nextArr)-1] == str1[cn]: 8 | cn += 1 9 | nextArr.append(cn) 10 | elif cn > 0: 11 | cn = nextArr[cn] 12 | else: 13 | nextArr.append(cn) 14 | 15 | return nextArr[-1] 16 | 17 | 18 | def answer(str1): 19 | if str1 == None or len(str1) == 0: return "" 20 | if len(str1) == 1: return str1 + str1 21 | if len(str1) == 2: 22 | return (str1 + str1[0]) if str1[0] == str1[1] else (str1 + str1) 23 | 24 | return str1 + str1[getStartIndex(str1):] 25 | 26 | if __name__ == '__main__': 27 | str1 = "a" 28 | print(answer(str1)) 29 | 30 | str1 = "aa" 31 | print(answer(str1)) 32 | 33 | str1 = "ab" 34 | print(answer(str1)) 35 | 36 | str1 = "abcdabcd" 37 | print(answer(str1)) 38 | 39 | str1 = "abracadabra" 40 | print(answer(str1)) 41 | 42 | -------------------------------------------------------------------------------- /Part0_Sort/Code2_BFPRT.py: -------------------------------------------------------------------------------- 1 | """BFPRT: 在无序数组中找到前k个最小的数, K从 1 到 N""" 2 | 3 | def getMinKNumsByBFPRT(arr, k): 4 | """得到前k个最小的数 5 | """ 6 | if k < 1 or k > len(arr): 7 | return None 8 | 9 | minKth = getMinKthByBFPRT(arr, k) 10 | 11 | res = [] 12 | for i in range(len(arr)): 13 | if arr[i] < minKth: 14 | res.append(arr[i]) 15 | while len(res) < k: 16 | res.append(minKth) 17 | 18 | return res 19 | 20 | def getMinKthByBFPRT(arr, k): 21 | """得到第k个小的数 22 | """ 23 | arrCopy = copy.copy(arr) 24 | return select(arrCopy, 0, len(arrCopy)-1, k-1) 25 | 26 | def select(arr, begin, end, index): 27 | """"BFPRT主程序 28 | """ 29 | if begin == end: 30 | return arr[begin] 31 | 32 | pivot = getMedianOfMedians(arr, begin, end) 33 | L, R = partition(arr, begin, end, pivot) 34 | 35 | if index >= L and index <= R: 36 | return pivot 37 | elif index < L: 38 | return select(arr, begin, L-1, index) 39 | else: 40 | return select(arr, R+1, end, index) 41 | 42 | def getMedianOfMedians(arr, begin, end): 43 | """得到数组中位数的中位数 44 | """ 45 | num = end - begin + 1 46 | offset = 0 if num%5==0 else 1 47 | 48 | mArr = [0] * (num//5 + offset) 49 | for i in range(len(mArr)): 50 | beginI = begin + i * 5 51 | endI = min(end, beginI+4) 52 | mArr[i] = getMedian(arr, beginI, endI) 53 | 54 | return select(mArr, 0, len(mArr)-1, len(mArr)//2) 55 | 56 | 57 | def getMedian(arr, begin, end): 58 | """通过插入排序得到,中位数 59 | """ 60 | insertSort(arr, begin, end) 61 | sum1 = begin + end ### 62 | mid = (sum1 // 2) 63 | return arr[mid] 64 | 65 | def insertSort(arr, begin, end): 66 | """插入排序 67 | """ 68 | for un_i in range(begin+1, end+1): 69 | o_i = un_i - 1 70 | while o_i >= 0 and arr[o_i] > arr[o_i + 1]: 71 | arr[o_i], arr[o_i+1] = arr[o_i+1], arr[o_i] 72 | o_i -= 1 73 | 74 | def partition(arr, begin, end, p): 75 | """划分过程 76 | """ 77 | less = begin - 1 78 | more = end + 1 79 | cur = begin #### 80 | 81 | while cur < more: 82 | if arr[cur] < p: 83 | less += 1 84 | arr[less], arr[cur] = arr[cur], arr[less] 85 | cur += 1 86 | elif arr[cur] > p: 87 | more -= 1 88 | arr[more], arr[cur] = arr[cur], arr[more] 89 | else: 90 | cur += 1 91 | 92 | return less + 1, more - 1 93 | 94 | 95 | def generateRandomArray(maxLen, maxVal): 96 | length = int(random.random() * maxLen) + 1 97 | 98 | arr = [] 99 | for _ in range(length): 100 | arr.append(int(random.random() * maxVal) + 1) 101 | return arr 102 | 103 | 104 | import copy 105 | import random 106 | 107 | if __name__ == '__main__': 108 | iterNum = 5000 109 | maxLen = 100 110 | maxVal = 100 111 | succeed = True 112 | 113 | for _ in range(iterNum): 114 | arr = generateRandomArray(maxLen, maxVal) 115 | arrCopy = copy.copy(arr) 116 | k = int(random.random() * len(arr)) + 1 117 | 118 | res1 = getMinKNumsByBFPRT(arr, k) 119 | res1.sort() 120 | arrCopy.sort() 121 | res2 = arrCopy[:k] 122 | 123 | if res1 != res2: 124 | succeed = False 125 | break 126 | 127 | print("nice" if succeed == True else "fucking fucked!") 128 | -------------------------------------------------------------------------------- /Part0_Sort/Code2_KMP.py: -------------------------------------------------------------------------------- 1 | """给定两个字符串str1 和 match,长度分别是N和M。实现一个算法, 2 | 如果字符串str1中含有子串match,则返回match在str1中的开始位置,不含有则返回-1 3 | """ 4 | def getNextArray(match): 5 | """基于match串生成next数组 6 | """ 7 | if len(match) == 1: 8 | return [-1] 9 | 10 | nextArr = [-1, 0] 11 | cn = 0 # cn 表示前一个字符最长匹配前缀的下一个字符位置(前一个字符最长匹配前缀的长度) 12 | while len(nextArr) < len(match): 13 | if match[len(nextArr)-1] == match[cn]: 14 | cn += 1 15 | nextArr.append(cn) 16 | elif cn > 0: 17 | cn = nextArr[cn] 18 | else: 19 | nextArr.append(0) 20 | 21 | return nextArr 22 | 23 | 24 | def getIndexOf(st1, match): 25 | """KMP算法 26 | """ 27 | if str1 == None or match == None or len(match) < 1 or len(str1) < len(match): 28 | return -1 29 | 30 | nextArr = getNextArray(match) 31 | 32 | i1, i2 = 0, 0 33 | while i1 < len(str1) and i2 < len(match): 34 | if str1[i1] == match[i2]: 35 | i1 += 1; i2 += 1 36 | elif nextArr[i2] == -1: 37 | i1 += 1 38 | else: 39 | i2 = nextArr[i2] 40 | 41 | return (i1 - len(match)) if i2 == len(match) else -1 42 | 43 | 44 | 45 | if __name__ == '__main__': 46 | str1 = "abcabcababaccc" 47 | match = "acc" 48 | print(getIndexOf(str1, match)) -------------------------------------------------------------------------------- /Part0_Sort/Code2_Manacher.py: -------------------------------------------------------------------------------- 1 | """manacher算法: 返回字符串中最长回文串的长度 2 | """ 3 | import sys 4 | 5 | def manacherArray(str1): 6 | manacherArr = [] 7 | 8 | index = 0 9 | for i in range(len(str1) * 2 + 1): 10 | manacherArr.append('#' if i%2 == 0 else str1[index]) 11 | if i%2 != 0: index += 1 12 | 13 | return manacherArr 14 | 15 | 16 | def maxLcpsLength(str1): 17 | if str1 == None or len(str1) == 0: 18 | return 0 19 | 20 | mcArr = manacherArray(str1) 21 | mcLength = len(mcArr) 22 | R, C = -1, -1 # 最右回文右边界R, 及其对应的回文中心C 23 | maxmum = -sys.maxsize 24 | pArr = [0] * mcLength # 从每个字符出发,最长回文半径 25 | for i in range(mcLength): 26 | pArr[i] = min(R-i, pArr[2*C-i]) if R > i else 1 27 | while i + pArr[i] < mcLength and i - pArr[i] > -1: 28 | if mcArr[i+pArr[i]] == mcArr[i-pArr[i]]: 29 | pArr[i] += 1 30 | else: 31 | break 32 | 33 | if i+pArr[i] > R: 34 | R = i + pArr[i] 35 | C = i 36 | 37 | maxmum = max(maxmum, pArr[i]) 38 | 39 | return maxmum - 1 40 | 41 | 42 | if __name__ == '__main__': 43 | str1 = "abc12344321ab" 44 | print(maxLcpsLength(str1)) -------------------------------------------------------------------------------- /Part1_Array/Code3_Array_To_Queue.py: -------------------------------------------------------------------------------- 1 | """用数组实现队列结构 2 | """ 3 | class ArrayQueue(object): 4 | if __init__(self, initSize): 5 | if initSize < 0: 6 | raise IllegalArgmentException("The init size is less than 0") 7 | 8 | self.items = [0] * initSize 9 | self.size = 0 10 | self.first = 0 11 | self.last = 0 12 | 13 | def push(self, item): 14 | if self.size == len(self.items): 15 | raise ArrayIndexOutOfBoundsException("The queue is full!") 16 | 17 | self.size += 1 18 | self.items[self.last] = item 19 | self.last = 0 if self.last == len(self.items) - 1 else self.last + 1 20 | 21 | def pull(self): 22 | if self.size == 0: 23 | raise ArrayIndexOfBoundsException("The queue is empty!") 24 | 25 | self.size -= 1 26 | tmp = self.first 27 | self.first = 0 if self.first == len(self.items) - 1 else self.first + 1 28 | 29 | return self.items[tmp] 30 | 31 | def peak(self): 32 | if self.size == 0: 33 | raise ArrayIndexOfBoundsException("The queue is empty!") 34 | 35 | return self.items[self.first] 36 | 37 | -------------------------------------------------------------------------------- /Part1_Array/Code3_Array_To_Stack.py: -------------------------------------------------------------------------------- 1 | """用数组实现栈结构 2 | """ 3 | class Stack(object): 4 | def __init__(self): 5 | self.items = list() 6 | 7 | def push(self, item): 8 | self.items.append(item) 9 | 10 | def pop(self): 11 | return self.items.pop() 12 | 13 | def clear(self): 14 | del self.items[:] 15 | 16 | def empty(self): 17 | return self.size() == 0 18 | 19 | def size(self): 20 | return len(self.items) 21 | 22 | def peak(self): 23 | return self.items[self.size() - 1] 24 | 25 | 26 | class ArrayStack(object): 27 | def __init__(self, initSize): 28 | if initSize < 0: 29 | raise IllegalArgmentException("The init size is less than 0!") 30 | 31 | self.items = [0] * initSize 32 | self.size = 0 33 | 34 | def push(self, item): 35 | if self.size == len(self.items): 36 | raise ArrayIndexOutOfBoundsException("The stack is full!") 37 | 38 | self.items[self.size] = item 39 | self.size += 1 40 | 41 | def pop(self): 42 | if self.size == 0: 43 | raise ArrayIndexOutOfBoundsException("The stack is empty!") 44 | 45 | self.size -= 1 46 | 47 | return self.items[self.size] 48 | 49 | def peak(self): 50 | if self.size == 0: 51 | return None 52 | 53 | return self.items[self.size - 1] 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Part1_Array/Code3_CatDogQueue.py: -------------------------------------------------------------------------------- 1 | """猫狗队列 2 | 3 | 左程云<程序员代码面试指南> 第10页 4 | """ 5 | class Pet(object): 6 | 7 | def __init__(self, typeName): 8 | self.typeName = typeName 9 | 10 | def getPetType(self): 11 | return self.typeName 12 | 13 | class Dog(Pet): 14 | 15 | def __init__(self): 16 | super(Dog, self).__init__("Dog") 17 | 18 | class Cat(Pet): 19 | 20 | def __init__(self): 21 | super(Cat, self).__init__("Cat") 22 | 23 | ######################################### 24 | """解决方法:定义一个新的类给每一个实例盖上一个时间戳""" 25 | class PetEnterQueue(object): 26 | 27 | def __init__(self, pet, count): 28 | 29 | self.pet = pet 30 | self.count = count 31 | 32 | def getPet(self): 33 | return self.pet 34 | 35 | def getCount(self): 36 | return self.count 37 | 38 | def getEnterPetType(self): 39 | return self.pet.getPetType() 40 | 41 | 42 | class CatDogQueue(object): 43 | 44 | def __init__(self): 45 | self.qCat = [] 46 | self.qDog = [] 47 | self.count = 0 48 | 49 | def add(self, pet): 50 | if pet.getPetType() == "Dog": 51 | self.count += 1 52 | self.qDog.append(PetEnterQueue(pet, self.count)) 53 | elif pet.getPetType() == "Cat": 54 | self.count += 1 55 | self.qCat.append(PetEnterQueue(pet, self.count)) 56 | else: 57 | raise TypeError("Not Cat Or Dog!") 58 | 59 | def isEmpty(self): 60 | return len(self.qCat) == 0 and len(self.qDog) == 0 61 | 62 | def isDogEmpty(self): 63 | return len(self.qDog) == 0 64 | 65 | def isCatEmpty(self): 66 | return len(self.qCat) == 0 67 | 68 | def pollAll(self): 69 | if not self.isDogEmpty() and not self.isCatEmpty(): 70 | if self.qCat[0].getCount() < self.qDog[0].getCount(): 71 | return self.qCat.pop(0).getPet() 72 | else: 73 | return self.qDog.pop(0).getPet() 74 | elif not self.isDogEmpty(): 75 | return self.qDog.pop(0).getPet() 76 | elif not self.isCatEmpty(): 77 | return self.qCat.pop(0).getPet() 78 | else: 79 | raise IndexError("The queue is empty!") 80 | 81 | def pollDog(self): 82 | if not self.isDogEmpty(): 83 | return self.qDog.pop(0).getPet() 84 | else: 85 | raise IndexError("The dog queue is empty!") 86 | 87 | def pollCat(self): 88 | if not self.isCatEmpty(): 89 | return self.qCat.pop(0).getPet() 90 | else: 91 | raise IndexError("The cat queue is empty!") 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /Part1_Array/Code3_FindNumInSortedMatrix.py: -------------------------------------------------------------------------------- 1 | """在行列都排好序的矩阵中找数""" 2 | 3 | def isContains(m, K): 4 | if m == None or len(m) == 0: 5 | return -1 6 | 7 | curR, curC = 0, len(m[0]) - 1 8 | while curR <= len(m)-1 and curC >= 0: 9 | if m[curR][curC] > K: 10 | curC -= 1 11 | elif m[curR][curC] < K: 12 | curR += 1 13 | else: 14 | return (curR, curC) 15 | return -1 16 | 17 | 18 | 19 | if __name__ == '__main__': 20 | matrix = [ 21 | [0, 1, 2, 3, 4, 5, 6], 22 | [10, 12, 13, 15, 16, 17, 18], 23 | [23, 24, 25, 26, 27, 28, 29], 24 | [44, 45, 46, 47, 48, 49, 50], 25 | [65, 66, 67, 68, 69, 70, 71], 26 | [96, 97, 98, 99, 100, 111, 122], 27 | [166, 176, 186, 187, 190, 195, 200], 28 | [233, 243, 321, 341, 356, 370, 380] 29 | ] 30 | 31 | K = 356 32 | print(isContains(matrix, K)) -------------------------------------------------------------------------------- /Part1_Array/Code3_GetMinStack.py: -------------------------------------------------------------------------------- 1 | """实现一个特殊的栈,操作:pop、push、getMin""" 2 | 3 | class Stack1(object): 4 | """实现1: 两个栈同步压入和弹出,minStack压入时稍费时间、但是弹出时操作稍省时间""" 5 | 6 | def __init__(self): 7 | 8 | self.stack = [] 9 | self.help = [] 10 | 11 | def isEmpty(self, obj): 12 | if len(obj) == 0: 13 | return True 14 | 15 | return False 16 | 17 | def push(self, item): 18 | self.stack.append(item) 19 | 20 | if len(self.help) == 0 or self.help[-1] >= item: 21 | self.help.append(item) 22 | else: 23 | self.help.append(self.help[-1]) 24 | 25 | def pop(self): 26 | if self.isEmpty(self.stack): 27 | raise ArrayIndexOutOfBoundsException("The Stack is empty!") 28 | 29 | self.help.pop(len(self.help) - 1) 30 | 31 | return self.stack.pop(len(self.stack) - 1) 32 | 33 | def getMin(self): 34 | if len(self.stack) == 0: 35 | raise ArrayIndexOutOfBoundsException("The Stack is empty!") 36 | 37 | return self.help[-1] 38 | 39 | 40 | class Stack2(object): 41 | """实现2: minStack压入时稍省空间,但是弹出操作稍费时间""" 42 | def __init__(self): 43 | 44 | self.stack = [] 45 | self.minStack = [] 46 | self.size = 0 47 | 48 | def push(self, item): 49 | self.stack.append(item) 50 | self.size += 1 51 | 52 | if len(self.minStack) == 0 or self.minStack[-1] >= item: 53 | self.minStack.append(item) 54 | 55 | 56 | def pop(self): 57 | if self.size == 0: 58 | raise ArrayIndexOutOfBoundsException("The stack is empty!") 59 | 60 | popVal = self.stack.pop() 61 | self.size -= 1 62 | 63 | if popVal == self.minStack[-1]: 64 | self.minStack.pop() 65 | 66 | return popVal 67 | 68 | 69 | def getMin(self): 70 | if self.size == 0: 71 | raise ArrayIndexOutOfBoundsException("The stack is empty!") 72 | 73 | return self.minStack[-1] 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /Part1_Array/Code3_Queue_To_Stack.py: -------------------------------------------------------------------------------- 1 | """队列结构实现堆结构""" 2 | 3 | class Queue_To_Stack(object): 4 | """两个队列实现一个栈结构 5 | """ 6 | def __init__(self): 7 | 8 | self.qData = [] 9 | self.qHelp = [] 10 | 11 | def push(self, item): 12 | self.qData.append(item) 13 | 14 | def pop(self): 15 | if len(self.qData) == 0: 16 | raise IndexError("The stack is empty!") 17 | 18 | while len(self.qData) != 1: 19 | self.qHelp.append(self.qData.pop()) 20 | 21 | res = self.qData.pop() 22 | self.qData, self.qHelp = self.qHelp, self.qData 23 | return res 24 | 25 | def peak(self): 26 | if len(self.qData) == 0: 27 | raise IndexError("The stack is empty!") 28 | 29 | while len(self.qData) != 1: 30 | self.qHelp.append(self.qData.pop()) 31 | 32 | res = self.qData.pop() 33 | self.qHelp.append(res) 34 | self.qData, self.qHelp = self.qHelp, self.qData 35 | 36 | return res 37 | 38 | 39 | -------------------------------------------------------------------------------- /Part1_Array/Code3_RandomPool.py: -------------------------------------------------------------------------------- 1 | """设计RandomPool结构 2 | 3 | 功能: 不重复插入、删除、等概率随机返回 4 | """ 5 | import random 6 | 7 | class RandomPool(object): 8 | 9 | def __init__(self): 10 | 11 | self.keyIndexMap = dict() 12 | self.indexKeyMap = dict() 13 | self.size = 0 14 | 15 | def insert(self, key): 16 | 17 | if self.keyIndexMap.get(key) == None: 18 | self.size += 1 19 | self.keyIndexMap[key] = self.size 20 | self.indexKeyMap[self.size] = key 21 | 22 | 23 | def delete(self, key): 24 | 25 | if self.keyIndexMap.get(key) != None: 26 | deleteIndex = self.keyIndexMap[key] 27 | lastKey = self.indexKeyMap[self.size] 28 | 29 | self.keyIndexMap[lastKey] = deleteIndex 30 | self.keyIndexMap.pop(key) 31 | 32 | self.indexKeyMap[deleteIndex] = lastKey 33 | self.indexKeyMap.pop(self.size) 34 | 35 | self.size -= 1 36 | 37 | 38 | def getRandom(self): 39 | if self.size == 0: 40 | raise IndexError("The structure is empty!") 41 | 42 | randNum = int(random.random() * self.size + 1) 43 | return self.indexKeyMap[randNum] 44 | 45 | 46 | -------------------------------------------------------------------------------- /Part1_Array/Code3_Stack_To_Queue.py: -------------------------------------------------------------------------------- 1 | """使用栈结构实现一个队列结构:栈转换成队列""" 2 | 3 | class Stack_To_Queue(object): 4 | """两个栈结构实现队列 5 | 6 | 栈结构:先进后出 7 | 队列结构:先进先出 8 | """ 9 | def __init__(self): 10 | self.stack = [] 11 | self.help = [] 12 | 13 | def push(self, item): 14 | 15 | self.stack.append(item) 16 | 17 | def pop(self): 18 | 19 | if len(self.stack) == 0 and len(self.help) == 0: 20 | raise Exception("The queue is empty") 21 | 22 | if len(self.help) == 0: 23 | while len(self.stack) != 0: 24 | self.help.append(self.stack.pop(-1)) 25 | 26 | return self.help.pop(-1) 27 | 28 | def peak(self): 29 | 30 | if len(self.stack) == 0 or len(self.help) == 0: 31 | raise Exception("The queue is empty") 32 | 33 | if len(self.help) == 0: 34 | while len(self.stack) != 0: 35 | self.help.append(self.stack.pop(-1)) 36 | 37 | return self.help[-1] 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Part1_Array/Code3_ZigZagPrintMatrix.py: -------------------------------------------------------------------------------- 1 | def printLevel(m, tR, tC, dR, dC, toDown): 2 | if toDown: 3 | while tR != dR + 1: 4 | print(m[tR][tC], end=' ') 5 | tR += 1 6 | tC -= 1 7 | else: 8 | while dR != tR - 1: 9 | print(m[dR][dC], end=' ') 10 | dR -= 1 11 | dC += 1 12 | 13 | 14 | def zigzagPrintMatrix(matrix): 15 | tR, tC = 0, 0 16 | dR, dC = 0, 0 17 | endR, endC = len(matrix)-1, len(matrix[0])-1 18 | toDown = False 19 | 20 | while tR != endR + 1: 21 | printLevel(matrix, tR, tC, dR, dC, toDown) 22 | tR = tR+1 if tC == endC else tR 23 | tC = tC if tC == endC else tC+1 24 | dC = dC+1 if dR == endR else dC 25 | dR = dR if dR == endR else dR+1 26 | 27 | toDown = not toDown 28 | 29 | 30 | 31 | 32 | 33 | if __name__ == '__main__': 34 | 35 | matrix = [[1,2,3,4], [5,6,7,8], [9,10,11,12]] 36 | zigzagPrintMatrix(matrix) -------------------------------------------------------------------------------- /Part1_Array/Code3_spiralOrderPrintMatrix.py: -------------------------------------------------------------------------------- 1 | """转圈打印矩阵""" 2 | 3 | def printEdge(matrix, tR, tC, dR, dC): 4 | 5 | if tR == dR: 6 | for i in range(tC, dC+1): 7 | print(matrix[tR][i]) 8 | elif tC == dC: 9 | for i in range(tR, dR+1): 10 | print(matrix[tC][i]) 11 | else: 12 | curR, curC = tR, tC 13 | while curC != dC: # 相等就不打印了,交给下一个while打印 14 | print(matrix[curR][curC], end=' ') 15 | curC += 1 16 | while curR != dR: 17 | print(matrix[curR][curC], end=' ') 18 | curR += 1 19 | while curC != tC: 20 | print(matrix[curR][curC], end=' ') 21 | curC -= 1 22 | while curR != tR: 23 | print(matrix[curR][curC], end=' ') 24 | curR -= 1 25 | 26 | 27 | def spiralOrderPrintMatrix(matrix): 28 | 29 | tR, tC = 0, 0 30 | dR, dC = len(matrix)-1, len(matrix[0]) - 1 31 | 32 | while tR <= dR and tC <= dC: 33 | printEdge(matrix, tR, tC, dR, dC) 34 | tR += 1 35 | tC += 1 36 | dR -= 1 37 | dC -= 1 38 | 39 | 40 | if __name__ == '__main__': 41 | matrix = [[1, 2, 3, 4], [5, 6, 7, 8], 42 | [9, 10, 11, 12], [13, 14, 15, 16]] 43 | 44 | spiralOrderPrintMatrix(matrix) -------------------------------------------------------------------------------- /Part1_Array/Code4_BinarySearch.py: -------------------------------------------------------------------------------- 1 | """找到有序数组中第一个大于或等于k的数""" 2 | 3 | def findNumberIndex(arr, target): 4 | """二分找数""" 5 | if arr == None or len(arr) == 0: 6 | return -1 7 | 8 | l, r = 0, len(arr) - 1 9 | res = -1 10 | while r > l: 11 | mid = l + ((r-l)>>1) 12 | if arr[mid] >= target: 13 | r = mid - 1 14 | res = mid if arr[mid] == target else res 15 | else: 16 | l = mid + 1 17 | 18 | return l if arr[l] == target else res 19 | 20 | 21 | if __name__ == '__main__': 22 | arr = [1, 3, 5, 8, 10, 10, 10, 10, 10, 10, 10, 14, 16, 19, 21, 43] 23 | k = 14 24 | 25 | ind = findNumberIndex(arr, k) 26 | print("index: %d, value: %d"%(ind, arr[ind]) if ind != -1 else None) 27 | -------------------------------------------------------------------------------- /Part1_Array/Code4_IsLands.py: -------------------------------------------------------------------------------- 1 | """岛屿问题: 给定一个矩阵,返回岛屿的个数""" 2 | 3 | def countIslands(m): 4 | """返回岛的个数 5 | """ 6 | if m == None or len(m) == 0: 7 | return 0 8 | 9 | res = 0 10 | row_Num = len(m) 11 | col_Num = len(m[0]) 12 | for i in range(row_Num): 13 | for j in range(col_Num): 14 | if m[i][j] == 1: 15 | infect(m, i, j, row_Num, col_Num) 16 | res += 1 17 | 18 | return res 19 | 20 | 21 | def infect(arr, i, j, row, col): 22 | """感染过程 23 | """ 24 | if i < 0 or i >= row or j < 0 or j >= col or arr[i][j] != 1: 25 | return None 26 | 27 | arr[i][j] = 2 28 | 29 | infect(arr, i-1, j, row, col) 30 | infect(arr, i+1, j, row, col) 31 | infect(arr, i, j-1, row, col) 32 | infect(arr, i, j+1, row, col) 33 | 34 | 35 | 36 | 37 | 38 | if __name__ == '__main__': 39 | m1 = [ 40 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 41 | [0, 1, 1, 1, 0, 1, 1, 1, 0], 42 | [0, 1, 1, 1, 0, 0, 0, 1, 0], 43 | [0, 1, 1, 0, 0, 0, 0, 0, 0], 44 | [0, 0, 0, 0, 0, 1, 1, 0, 0], 45 | [0, 0, 0, 0, 1, 1, 1, 0, 0], 46 | [0, 0, 0, 0, 0, 0, 0, 0, 0] 47 | ] 48 | 49 | 50 | print(countIslands(m1)) 51 | 52 | 53 | m2 = [ 54 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 55 | [0, 1, 1, 1, 1, 1, 1, 1, 0], 56 | [0, 1, 1, 1, 0, 0, 0, 1, 0], 57 | [0, 1, 1, 0, 0, 0, 1, 1, 0], 58 | [0, 0, 0, 0, 0, 1, 1, 0, 0], 59 | [0, 0, 0, 0, 1, 1, 1, 0, 0], 60 | [0, 0, 0, 0, 0, 0, 0, 0, 0] 61 | ] 62 | 63 | print(countIslands(m2)) -------------------------------------------------------------------------------- /Part1_Array/Code4_findLessValueIndex.py: -------------------------------------------------------------------------------- 1 | """在数组中找到一个局部最小的位置 2 | 3 | 给定一个无序数组,任意相邻两数均不相等,返回一个局部最小位置 4 | """ 5 | def getLessIndex(arr): 6 | """返回局部最小值索引 7 | """ 8 | if arr == None or len(arr) < 2: 9 | return -1 10 | 11 | if arr[0] < arr[1] or arr[len(arr)-1] < arr[len(arr)-2]: 12 | return 0 if arr[0] < arr[1] else len(arr)-1 13 | 14 | left, right = 1, len(arr) - 2 ### 15 | while left <= right: 16 | mid = left + (right - left) // 2 17 | if arr[mid] > arr[mid + 1]: 18 | left = mid + 1 19 | elif arr[mid] > arr[mid - 1]: 20 | right = mid - 1 21 | else: 22 | return mid 23 | 24 | return -1 25 | 26 | 27 | if __name__ == '__main__': 28 | arr = [6, 5, 3, 4, 6, 7, 8] 29 | print(arr) 30 | 31 | index = getLessIndex(arr) 32 | print("Index: %d, value: %d"%(index, arr[index])) 33 | -------------------------------------------------------------------------------- /Part1_Array/Code8_GetKNumsRand.py: -------------------------------------------------------------------------------- 1 | """有一个机器按自然数序列的方式吐出球(1,2,3……),你有一个袋子,袋子最多只能装下K个球。 2 | 设计一种选择方式,当吐到第N号球时,之前每个球被装进袋子的概率都是 k/N。 3 | """ 4 | import random 5 | 6 | class ReservoirSampling(object): 7 | def __init__(self, bagSize): 8 | self.bagSize = bagSize 9 | self.bag = [None] * bagSize 10 | 11 | def rand(self, max1): 12 | return int(random.random() * max1 + 1) 13 | 14 | def add(self, num): 15 | 16 | if num <= self.bagSize: 17 | self.bag[num-1] = num 18 | 19 | else: 20 | k = self.bagSize 21 | if self.rand(num) <= k: # num号球进袋子 22 | self.bag[self.rand(k) - 1] = num 23 | 24 | """算法过程 25 | 26 | 1. 处理1~k号球,直接进袋子。 27 | 2. 处理num (num>k)号球时,以k/num的概率决定是否将第i号球 28 | 决定进 -> 从袋中随机扔掉一个,num进袋子 29 | 不决定进 -> num扔掉 30 | """ 31 | 32 | if __name__ == '__main__': 33 | k = 6 34 | num = 100 35 | 36 | pool = ReservoirSampling(k) 37 | for i in range(1, num): 38 | pool.add(i) 39 | print(pool.bag) -------------------------------------------------------------------------------- /Part1_Array/Code8_MaxABS.py: -------------------------------------------------------------------------------- 1 | """给定一个长度为N的整型数组arr,可以将其划分成左右两部分arr[0···k], arr[k+1···N-1] 2 | k的取值是[0, n-2),求这些划分中方案中,左部分最大-右部分最大的绝对值中的最大值。 3 | """ 4 | def maxAbs1(arr): 5 | """预处理数组法 6 | 7 | 时间复杂度O(n),额外空间O(N) 8 | """ 9 | if arr == None or len(arr) == 0: 10 | return 0 11 | 12 | length = len(arr) 13 | 14 | lmax, rmax = [0] * length, [0] * length 15 | lmax[0] = arr[0] 16 | rmax[length-1] = arr[length-1] 17 | 18 | for i in range(1, len(arr)): 19 | lmax[i] = max(lmax[i-1], arr[i]) 20 | 21 | for j in list(range(len(arr)-1))[::-1]: 22 | rmax[j] = max(rmax[j+1], arr[j]) 23 | 24 | res = 0 25 | for i in range(length-1): 26 | res = max( 27 | res, 28 | abs(lmax[i] - rmax[i+1]) 29 | ) 30 | 31 | return res 32 | 33 | 34 | def maxAbs2(arr): 35 | """最优解 36 | 37 | 时间复杂度O(n),额外空间O(N) 38 | """ 39 | if arr == None or len(arr) == 0: 40 | return 0 41 | 42 | maxVal = float('-inf') 43 | for i in range(len(arr)): 44 | maxVal = max( 45 | maxVal, 46 | arr[i] 47 | ) 48 | 49 | return maxVal - min(arr[0], arr[-1]) 50 | 51 | 52 | if __name__ == '__main__': 53 | arr = [2, 7, 3, 1, 1] 54 | print(maxAbs1(arr)) 55 | print(maxAbs2(arr)) -------------------------------------------------------------------------------- /Part1_Array/Code8_MaxRecSize.py: -------------------------------------------------------------------------------- 1 | """给定一个整型矩阵matrix,其中的值只有0和1两种。求其中取值全为1的子矩阵中, 2 | 最大矩形1的数量? P26 3 | 4 | 时间复杂度 O(N*M) 5 | """ 6 | 7 | def maxRecSize(matrix): 8 | """最大矩形size 9 | """ 10 | if matrix == None or len(matrix) == 0 or len(matrix[0]) == 0: 11 | return None 12 | 13 | maxArea = 0 14 | row, col = len(matrix), len(matrix[0]) 15 | height = [0] * col # 以每行作为结尾时,连续1的数量 (高度数组) 16 | for i in range(row): 17 | for j in range(col): 18 | height[j] = height[j] + 1 if matrix[i][j] == 1 else 0 19 | 20 | maxArea = max( 21 | maxArea, 22 | maxAreaBasedOnHeight(height) 23 | ) 24 | 25 | return maxArea 26 | 27 | def maxAreaBasedOnHeight(height): 28 | """基于行的height数组的 maxArea 29 | """ 30 | maxArea = 0 31 | 32 | stack = [] 33 | for i in range(len(height)): 34 | cur = height[i] 35 | 36 | while len(stack) != 0 and cur <= height[stack[-1]]: 37 | maxArea = max( 38 | maxArea, 39 | popAndCalcArea(stack, height, i) 40 | ) 41 | stack.append(i) 42 | 43 | while len(stack) != 0: 44 | maxArea = max( 45 | maxArea, 46 | popAndCalcArea(stack, height, len(height)) 47 | ) 48 | 49 | return maxArea 50 | 51 | 52 | def popAndCalcArea(stack, height, i): 53 | """stack 弹出 并计算当前弹出的 area 54 | """ 55 | popIndex = stack.pop(-1) 56 | k = stack[-1] if len(stack) != 0 else -1 57 | return (i - k - 1) * height[popIndex] 58 | 59 | 60 | if __name__ == '__main__': 61 | matrix = [ 62 | [1, 0, 1, 1], 63 | [1, 1, 1, 1], 64 | [1, 1, 1, 0]] 65 | 66 | print(maxRecSize(matrix)) -------------------------------------------------------------------------------- /Part1_Array/Code8_MaxSumOfSubArray.py: -------------------------------------------------------------------------------- 1 | """给定一个数组arr,返回子数组的最大累加和""" 2 | def maxSum(arr): 3 | if arr == None or len(arr) == 0: return 0 4 | 5 | maxSum = float('-inf') 6 | sum1 = 0 7 | for i in range(len(arr)): 8 | sum1 += arr[i] 9 | maxSum = max(maxSum, sum1) 10 | sum1 = 0 if sum1 < 0 else sum1 11 | 12 | return maxSum 13 | 14 | if __name__ == '__main__': 15 | arr = [1, -2, 3, 5, -2, 6, -1] # 12 16 | print(maxSum(arr)) -------------------------------------------------------------------------------- /Part1_Array/Code8_MaxSumOfSubMatrix.py: -------------------------------------------------------------------------------- 1 | """给定一个矩阵matrix,其中的值有正、有负、有0,返回子矩阵的最大累加和。""" 2 | def maxSumOfSubMatrix(matrix): 3 | """子矩阵的最大累加和 4 | """ 5 | if matrix == None or len(matrix) == 0 or len(matrix[0]) == 0: 6 | return 0 7 | 8 | maxSum = float('-inf') 9 | 10 | row, col = len(matrix), len(matrix[0]) 11 | for beg in range(row): # 从beg行开始遍历 12 | arr = [0] * col 13 | for i in range(beg, row): 14 | for j in range(col): 15 | arr[j] += matrix[i][j] 16 | 17 | maxSum = max( 18 | maxSum, 19 | maxSumOfSubArray(arr) 20 | ) 21 | 22 | return maxSum 23 | 24 | 25 | def maxSumOfSubArray(arr): 26 | if arr == None or len(arr) == 0: 27 | return 0 28 | 29 | maxSum = float('-inf') 30 | sum1 = 0 31 | for i in range(len(arr)): 32 | sum1 += arr[i] 33 | maxSum = max(maxSum, sum1) 34 | sum1 = 0 if sum1 < 0 else sum1 35 | 36 | return maxSum 37 | 38 | if __name__ == '__main__': 39 | matrix = [ 40 | [-90, 48, 78], 41 | [64, -40, 64], 42 | [-81, -7, 66]] 43 | print(maxSumOfSubMatrix(matrix)) # 209 44 | 45 | matrix = [ 46 | [-1, -1, -1], 47 | [-1, 2, 2], 48 | [-1, -1, -1]] 49 | print(maxSumOfSubMatrix(matrix)) # 4 -------------------------------------------------------------------------------- /Part1_Array/Code8_SlidingWindowMaxArray.py: -------------------------------------------------------------------------------- 1 | """给定一个数组arr 和 一整数w代表窗口大小。窗口从数组的最左侧滑向最右侧,每次仅向右滑动一个位置, 2 | 返回一个长度为 n-w+1的数组res,res[i]表示每一种窗口状态下的最大值""" 3 | 4 | def getArrayOfMAX(arr, w): 5 | if arr == None or len(arr) == 0 or w < 1 or w > len(arr): 6 | return None 7 | 8 | res = [] 9 | qmax = [] 10 | for i in range(len(arr)): 11 | 12 | while len(qmax) != 0 and arr[qmax[-1]] <= arr[i]: 13 | qmax.pop(-1) 14 | 15 | qmax.append(i) 16 | 17 | if i - w == qmax[0]: 18 | qmax.pop(0) 19 | 20 | if i + 1 >= w: 21 | res.append(arr[qmax[0]]) 22 | 23 | return res 24 | 25 | 26 | 27 | if __name__ == '__main__': 28 | arr = [4, 3, 5, 4, 3, 3, 6, 7] 29 | w = 3 30 | print(getArrayOfMAX(arr, w)) -------------------------------------------------------------------------------- /Part1_Array/Code8_SubArrayNumber.py: -------------------------------------------------------------------------------- 1 | """给定数组arr和整数num,返回有多少个子数组满足如下情况: 2 | max(arr[i...j]) - min(arr[i...j]) <= num 3 | 4 | 要求时间复杂度: O(N) 5 | """ 6 | def getNum_1(arr, num): 7 | """普通解法 o(N^2) 8 | """ 9 | if arr == None or len(arr) == 0 or num <= 0: 10 | return None 11 | 12 | res = 0 13 | length = len(arr) 14 | for i in range(length): 15 | for j in range(i, length): 16 | tempArr = arr[i:j+1] 17 | res = res + 1 if max(tempArr) - min(tempArr) <= num else res 18 | 19 | return res 20 | 21 | 22 | def getNum_2(arr, num): 23 | """最优解法 O(N) 24 | """ 25 | if arr == None or len(arr) == 0 or num <= 0: 26 | return None 27 | 28 | l, r = 0, 0 29 | qmax, qmin = [], [] 30 | res = 0 31 | 32 | while l < len(arr): 33 | while r < len(arr): 34 | # qmax 35 | while len(qmax) != 0 and arr[qmax[-1]] <= arr[r]: 36 | qmax.pop(-1) 37 | qmax.append(r) 38 | 39 | # qmin 40 | while len(qmin) != 0 and arr[qmin[-1]] >= arr[r]: 41 | qmin.pop(-1) 42 | qmin.append(r) 43 | 44 | if arr[qmax[0]] - arr[qmin[0]] > num: 45 | break 46 | else: 47 | r += 1 48 | 49 | if len(qmax) != 0 and qmax[0] == l: 50 | qmax.pop(0) 51 | if len(qmin) != 0 and qmin[0] == l: 52 | qmin.pop(0) 53 | 54 | res += (r - l) 55 | l += 1 56 | 57 | return res 58 | 59 | """双端队列 实现 窗口最大值和最小值的更新结构 60 | """ 61 | 62 | 63 | if __name__ == '__main__': 64 | 65 | arr = [1,2,3,4,5,6,7,8,9] 66 | num = 6 67 | print(getNum_1(arr, num)) 68 | print(getNum_2(arr, num)) 69 | -------------------------------------------------------------------------------- /Part1_Array/helixWriteNumber.py: -------------------------------------------------------------------------------- 1 | def getMatrix(n): 2 | 3 | matrix = [] 4 | for _ in range(n): 5 | matrix.append([0] * n) 6 | 7 | count = 1 8 | for i in range(n//2 + 1): 9 | 10 | for j in range(i, n-i): # 上方行 11 | matrix[i][j] = count 12 | count += 1 13 | 14 | for j in range(i+1, n-i-1): # 右侧列 15 | matrix[j][n-i-1] = count 16 | count += 1 17 | 18 | for j in list(range(i+1, n-i))[::-1]: # 下方行 19 | matrix[n-i-1][j] = count 20 | count += 1 21 | 22 | for j in list(range(i+1, n-i))[::-1]: # 左侧列 23 | matrix[j][i] = count 24 | count += 1 25 | 26 | 27 | for each in matrix: 28 | print(each) 29 | 30 | 31 | getMatrix(5) 32 | 33 | 34 | """ 35 | 螺旋填数 36 | 37 | 从键盘输入一个整数(1~20) 38 | 39 | 则以该数字为矩阵的大小,把1,2,3…n*n 的数字按照顺时针螺旋的形式填入其中。例如: 40 | 41 | 输入数字2,则程序输出: 42 | 43 | 1 2 44 | 45 | 4 3 46 | 47 | 输入数字3,则程序输出: 48 | 49 | 1 2 3 50 | 51 | 8 9 4 52 | 53 | 7 6 5 54 | 55 | 输入数字4,则程序输出: 56 | 57 | 1 2 3 4 58 | 59 | 12 13 14 5 60 | 61 | 11 16 15 6 62 | 63 | 10 9 8 7 64 | """ 65 | 66 | -------------------------------------------------------------------------------- /Part1_Array/maxMulValue.py: -------------------------------------------------------------------------------- 1 | def getMaxMul(arr): 2 | 3 | if arr == None or len(arr) < 3: 4 | return None 5 | 6 | 7 | max1, max2, max3 = float('-inf'), float('-inf'), float('-inf') 8 | min1, min2 = float('inf'), float('inf') 9 | 10 | for i in range(len(arr)): 11 | 12 | if arr[i] > max1: 13 | max3 = max2 14 | max2 = max1 15 | max1 = arr[i] 16 | 17 | elif arr[i] > max2: 18 | max3 = max2 19 | max2 = arr[i] 20 | 21 | elif arr[i] > max3: 22 | max3 = arr[i] 23 | 24 | 25 | if arr[i] < min1: 26 | min2 = min1 27 | min1 = arr[i] 28 | 29 | elif arr[i] < min2: 30 | min2 = arr[i] 31 | 32 | 33 | return max( 34 | max1 * max2 * max3, 35 | max1 * min1 * min2 36 | ) 37 | 38 | 39 | """ 40 | 3个数的最大乘积 41 | 42 | 给定一个无序数组,包含正数、负数和0,要求从中找出3个数的乘积,使得乘积最大,要求时间复杂度:O(n),空间复杂度:O(1) 43 | 输入描述: 44 | 无序整数数组A[n] 45 | 46 | 输出描述: 47 | 满足条件的最大乘积 48 | 49 | 输入例子1: 50 | 3 4 1 2 51 | 52 | 输出例子1: 53 | 24 54 | 55 | 最大乘积为最大的三个数字乘积或者最大一个数字和最小两个数字乘积,负负得正。 56 | 57 | 注意此题需要用long 58 | 59 | 第一种方法是排序,取得最值 60 | 61 | 第二种方法是使用五个变量 62 | """ 63 | -------------------------------------------------------------------------------- /Part2_LinkedList/Code3_CopyListWithRandom.py: -------------------------------------------------------------------------------- 1 | class Node(object): 2 | def __init__(self, val): 3 | self.value = val 4 | self.next = None 5 | self.rand = None 6 | 7 | 8 | def copyListWithRandom2(head): 9 | """最优解法: 额外空间复杂度O(1) 10 | """ 11 | if head == None: return None 12 | 13 | # 整合 14 | cur = head 15 | tmp = None 16 | while cur != None: 17 | tmp = cur.next 18 | cur.next = Node(cur.value) 19 | cur.next.next = tmp 20 | cur = tmp 21 | 22 | # 设置copy结点的rand指针 23 | cur = head 24 | curCopy = None 25 | while cur != None: 26 | tmp = cur.next.next 27 | curCopy = cur.next 28 | curCopy.rand = cur.rand.next if cur.rand != None else None 29 | cur = tmp 30 | 31 | # 拆分 32 | copyHead = head.next 33 | cur = head 34 | while cur != None: 35 | tmp = cur.next.next 36 | curCopy = cur.next 37 | cur.next = tmp 38 | curCopy.next = tmp.next if tmp != None else None 39 | 40 | cur = tmp 41 | 42 | return copyHead 43 | 44 | 45 | 46 | 47 | def copyListWithRandom1(head): 48 | """普通解法: 额外空间复杂度O(N) 49 | """ 50 | if head == None: return None 51 | 52 | dict1 = dict() 53 | cur = head 54 | while cur != None: 55 | dict1[cur] = Node(cur.value) 56 | cur = cur.next 57 | 58 | cur = head 59 | while cur != head: 60 | dict1[cur].next = dict1[cur.next] 61 | dict1[cur].rand = dict1[cur.rand] 62 | 63 | cur = cur.next 64 | 65 | return dict1[head] -------------------------------------------------------------------------------- /Part2_LinkedList/Code3_FindFirstIntersectNode.py: -------------------------------------------------------------------------------- 1 | """寻找两个单链表相交的第一个结点的问题""" 2 | 3 | def getIntersectNode(head1, head2): 4 | """分三种情况: 5 | 1. 都无环 6 | 2. 都有有环 7 | 3. 一个有环一个无环 8 | """ 9 | if head1 == None or head2 == None: return None 10 | 11 | loop1 = getLoopNode(head1) 12 | loop2 = getLoopNode(head2) 13 | 14 | if loop1 == None and loop2 == None: 15 | return noLoop(head1, head2) 16 | 17 | if loop1 != None and loop2 != None: 18 | return bothLoop(head1, loop1, head2, loop2) 19 | 20 | return None 21 | 22 | def getLoopNode(head): 23 | """得到单链表入环的第一个结点, 无环返回 None 24 | """ 25 | if head.next == None or head.next.next == None: return None 26 | 27 | fast = head.next.next 28 | slow = head.next 29 | while fast != slow: 30 | if fast.next == None or fast.next.next == None: 31 | return None 32 | fast = fast.next.next 33 | slow = slow.next 34 | 35 | fast = head 36 | while fast != slow: 37 | fast, slow = fast.next, slow.next 38 | 39 | return fast 40 | 41 | def noLoop(head1, head2): 42 | """两个无环单链表相交的第一个结点, 不相交返回None 43 | """ 44 | # 计算两个链表的长度差值,并且暂存 两个单链表的最后一个结点 45 | cur1, cur2 = head1, head2 46 | diff = 0 47 | while cur1.next != None: 48 | diff += 1 49 | cur1 = cur1.next 50 | while cur2.next != None: 51 | diff -= 1 52 | cur2 = cur2.next 53 | 54 | # 比较最后一个结点是否相同 55 | if cur1 != cur2: 56 | return None 57 | 58 | # cur1 存 长链表头结点; cur2 存 短链表头结点 59 | cur1 = head1 if diff > 0 else head2 60 | cur2 = head1 if cur1 == head2 else head2 61 | diff = abs(diff) 62 | 63 | while diff != 0: 64 | diff -= 1 65 | cur1 = cur1.next 66 | 67 | while cur1 != cur2: 68 | cur1, cur2 = cur1.next, cur2.next 69 | 70 | return cur1 71 | 72 | def bothLoop(head1, loop1, head2, loop2): 73 | """判断两个有环单链表的第一个相交结点 74 | """ 75 | if loop1 == loop2: 76 | cur1, cur2 = head1, head2 77 | diff = 0 78 | while cur1 != loop1: ### 79 | diff += 1 80 | cur1 = cur1.next 81 | while cur2 != loop2: ### 82 | diff -= 1 83 | cur2 = cur2.next 84 | 85 | cur1 = head1 if diff > 0 else head2 # long 86 | cur2 = head1 if cur1 == head2 else head2 87 | diff = abs(diff) 88 | while diff != 0: 89 | diff -= 1 90 | cur1 = cur1.next 91 | 92 | while cur1 != cur2: 93 | cur1, cur2 = cur1.next, cur2.next 94 | 95 | return cur1 96 | 97 | else: 98 | cur1 = loop1.next 99 | while cur1 != loop1: 100 | if cur1 == loop2: 101 | return loop2 102 | cur1 = cur1.next 103 | 104 | return None 105 | 106 | 107 | class Node(object): 108 | def __init__(self, val): 109 | self.value = val 110 | self.next = None 111 | 112 | 113 | if __name__ == '__main__': 114 | # 1->2->3->4->5->6->7->null 115 | head1 = Node(1) 116 | head1.next = Node(2) 117 | head1.next.next = Node(3) 118 | head1.next.next.next = Node(4) 119 | head1.next.next.next.next = Node(5) 120 | head1.next.next.next.next.next = Node(6) 121 | head1.next.next.next.next.next.next = Node(7) 122 | 123 | # 0->9->8->6->7->null 124 | head2 = Node(0) 125 | head2.next = Node(9) 126 | head2.next.next = Node(8) 127 | head2.next.next.next = head1.next.next.next.next.next; # 8->6 128 | print(getIntersectNode(head1, head2).value) 129 | 130 | # 1->2->3->4->5->6->7->4... 131 | head1 = Node(1) 132 | head1.next = Node(2) 133 | head1.next.next = Node(3) 134 | head1.next.next.next = Node(4) 135 | head1.next.next.next.next = Node(5) 136 | head1.next.next.next.next.next = Node(6) 137 | head1.next.next.next.next.next.next = Node(7) 138 | head1.next.next.next.next.next.next = head1.next.next.next # 7->4 139 | # 0->9->8->2... 140 | head2 = Node(0) 141 | head2.next = Node(9) 142 | head2.next.next = Node(8) 143 | head2.next.next.next = head1.next # 8->2 144 | print(getIntersectNode(head1, head2).value) 145 | 146 | # 0->9->8->6->4->5->6.. 147 | head2 = Node(0) 148 | head2.next = Node(9) 149 | head2.next.next = Node(8) 150 | head2.next.next.next = head1.next.next.next.next.next # 8->6 151 | print(getIntersectNode(head1, head2).value); -------------------------------------------------------------------------------- /Part2_LinkedList/Code3_LinkedListIsPalindrome.py: -------------------------------------------------------------------------------- 1 | """判断一个链表是否为回文结构""" 2 | 3 | class Node(object): 4 | def __init__(self, data): 5 | self.value = data 6 | self.next = None 7 | 8 | 9 | class isPalindrome(object): 10 | 11 | def __init__(self, head): 12 | self.head = head 13 | 14 | 15 | # 方法一:额外空间复杂度O(N) 每个元素依次进栈 16 | def isPalindrome1(self): 17 | cur = self.head 18 | stack = [] 19 | 20 | while cur != None: 21 | stack.append(cur.value) 22 | cur = cur.next 23 | 24 | cur = self.head 25 | while cur != None: 26 | if cur.data != stack.pop(-1): 27 | return False 28 | 29 | return True 30 | 31 | 32 | # 方法二: 只有一半元素进栈,额外空间复杂度O(N/2) 33 | def isPalindome2(self): 34 | fast, slow = self.head, self.head 35 | while fast.next != None and fast.next.next != None: 36 | fast = fast.next.next 37 | slow = slow.next 38 | 39 | stack = [] 40 | while slow.next != None: 41 | slow = slow.next 42 | stack.append(slow.value) 43 | 44 | cur = self.head 45 | while len(stack) != 0: 46 | if stack.pop() != cur.value: 47 | return False 48 | cur = cur.next 49 | 50 | return True 51 | 52 | 53 | # 方法三:不需要任何额外空间,额外空间复杂度O(1) 【最优解】 54 | def isPalindome3(self): 55 | if self.head == None or self.head.next == None: 56 | return True 57 | 58 | slow, fast = self.head, self.head 59 | while fast.next != None and fast.next.next != None: 60 | slow, fast = slow.next, fast.next.next # 此时的slow指向中间结点 61 | 62 | # 反转右半部分链表 (slow指向最后一个位置) 63 | cur = slow.next 64 | slow.next = None 65 | tmp = None 66 | while cur != None: 67 | tmp = cur.next 68 | cur.next = slow 69 | slow = cur 70 | cur = tmp 71 | 72 | tmp = slow # 暂存最后一个结点(还原链表时用到) 73 | # 检测是否为回文 74 | cur = self.head 75 | res = True 76 | while cur != None and slow != None: 77 | if cur.value != slow.value: 78 | res = False 79 | break 80 | cur, slow = cur.next, slow.next 81 | 82 | # 还原链表 83 | slow = tmp 84 | cur = slow.next 85 | slow.next = None 86 | tmp = None 87 | while cur != None: 88 | tmp = cur.next 89 | cur.next = slow 90 | slow = cur 91 | cur = tmp 92 | 93 | return res -------------------------------------------------------------------------------- /Part2_LinkedList/Code3_PrintCommonPart.py: -------------------------------------------------------------------------------- 1 | """打印两个有序链表的公共部分""" 2 | 3 | class Node(object): 4 | def __init__(self, data): 5 | self.value = data 6 | self.next = None 7 | 8 | 9 | def printCommonPart(head1, head2): 10 | print("打印公共部分:") 11 | 12 | while head1 != None and head2 != None: 13 | if head1.value < head2.value: 14 | head1 = head1.next 15 | elif head1.value > head2.value: 16 | head2 = head2.next 17 | else: 18 | print(head1.value, end=' ') 19 | head1 = head1.next 20 | head2 = head2.next 21 | 22 | print() 23 | 24 | -------------------------------------------------------------------------------- /Part2_LinkedList/Code3_ReverseList.py: -------------------------------------------------------------------------------- 1 | """分别实现反转单链表和反转双链表的函数""" 2 | 3 | def reverseSingleList(head): 4 | if head == None or head.next == None: 5 | return head 6 | 7 | pre, nex = None, None 8 | while head != None: 9 | nex = head.next 10 | head.next = pre 11 | pre = head 12 | head = nex 13 | 14 | return pre 15 | 16 | def printSimpleLinkedList(head): 17 | print("The single List is : ", end=' ') 18 | if head == None: 19 | print(head) 20 | 21 | cur = head 22 | while cur != None: 23 | print(cur.value, end=' ') 24 | cur = cur.next 25 | print() 26 | 27 | class SingleNode(object): 28 | def __init__(self, val): 29 | self.value = val 30 | self.next = None 31 | 32 | 33 | ############################################# 34 | 35 | def reverseDoubleList(head): 36 | pre, nex = None, None 37 | while head != None: 38 | nex = head.next 39 | head.next = pre 40 | head.last = nex 41 | pre = head 42 | head = nex 43 | 44 | return pre 45 | 46 | 47 | def printDoubleLinkedList(head): 48 | print("The Double List is : ", end=' ') 49 | 50 | end = None 51 | while head != None: 52 | print(head.value, end=' ') 53 | end = head 54 | head = head.next 55 | 56 | print('||', end=' ') 57 | while end != None: 58 | print(end.value, end=' ') 59 | end = end.last 60 | print() 61 | 62 | class DoubleNode(object): 63 | def __init__(self, val): 64 | self.value = val 65 | self.next = None 66 | self.last = None 67 | 68 | 69 | 70 | 71 | if __name__ == '__main__': 72 | head1 = SingleNode(1) 73 | head1.next = SingleNode(2) 74 | head1.next.next = SingleNode(3) 75 | head1.next.next.next = SingleNode(4) 76 | printSimpleLinkedList(head1) 77 | printSimpleLinkedList(reverseSingleList(head1)) 78 | 79 | 80 | head2 = DoubleNode(1) 81 | head2.next = DoubleNode(2) 82 | head2.next.last = head2 83 | head2.next.next = DoubleNode(3) 84 | head2.next.next.last = head2.next 85 | head2.next.next.next = DoubleNode(4) 86 | head2.next.next.next.last = head2.next.next 87 | printDoubleLinkedList(head2) 88 | printDoubleLinkedList(reverseDoubleList(head2)) 89 | 90 | 91 | -------------------------------------------------------------------------------- /Part2_LinkedList/Code3_SmallerEqualBigger.py: -------------------------------------------------------------------------------- 1 | """将单链表按某值划分成左边小,中间相等、右边大的形式""" 2 | 3 | class Node(object): 4 | def __init__(self, val): 5 | self.value = val 6 | self.next = None 7 | 8 | 9 | 10 | def listPartition2(head, pivot): 11 | """最优解:额外空间复杂度O(1)的解法""" 12 | sH, sT = None, None # 小的头和尾 13 | eH, eT = None, None # 等的头和尾 14 | bH, bT = None, None # 大的头和尾 15 | 16 | tmp = None # 暂存下一个结点 17 | 18 | # 将每个结点分给这三个链表 19 | while head != None: 20 | tmp = head.next 21 | head.next = None 22 | if head.value < pivot: # 填到小于区 23 | if sH == None: 24 | sH, sT = head, head 25 | else: 26 | sT.next = head 27 | sT = head 28 | 29 | elif head.value > pivot: # 填到大于区 30 | if bH == None: 31 | bH, bT = head, head 32 | else: 33 | bT.next = head 34 | bT = head 35 | 36 | else: 37 | if eH == None: # 填到等于区 38 | eH, eT = head, head 39 | else: 40 | eT.next = head 41 | eT = head 42 | 43 | head = tmp 44 | 45 | # 小于尾 与 等于头 相连 46 | if sT != None: 47 | sT.next = eH 48 | eT = sT if eT == None else eT 49 | 50 | if eT != None: 51 | eT.next = bH 52 | 53 | return sH if sH != None else (eH if eH != None else bH) 54 | 55 | 56 | 57 | 58 | def listPartition1(head, pivot): 59 | """数组的划分方法应用于链表的划分 60 | """ 61 | if head == None: return head 62 | 63 | # 求链表的长度 64 | length = 0 65 | cur = head 66 | while cur != None: 67 | length += 1 68 | cur = cur.next 69 | 70 | # 将所有结点暂存在数组中 71 | arr = [None] * length 72 | cur = head 73 | for i in range(length): 74 | arr[i] = cur 75 | cur = cur.next 76 | 77 | # 数组的划分思想 78 | arrPartition(arr, pivot) 79 | 80 | # 将数组串成一个新的链表 81 | for i in range(1, length): 82 | arr[i-1].next = arr[i] 83 | 84 | arr[i].next = None 85 | 86 | return arr[0] 87 | 88 | def arrPartition(arr, pivot): 89 | """数组的划分过程 90 | """ 91 | less, more = -1, len(arr) 92 | cur = 0 93 | 94 | while cur < more: 95 | if arr[cur].value < pivot: 96 | less += 1 97 | arr[cur], arr[less] = arr[less], arr[cur] 98 | cur += 1 99 | elif arr[cur].value > pivot: 100 | more -= 1 101 | arr[more], arr[cur] = arr[cur], arr[more] 102 | else: 103 | cur += 1 104 | 105 | def generateLinkedList(arr): 106 | """由数组生成单链表 107 | """ 108 | if arr == None: 109 | raise IndexError("The array is empty!") 110 | 111 | head = Node(0) 112 | cur = head 113 | for each in arr: 114 | cur.next = Node(each) 115 | cur = cur.next 116 | 117 | cur.next = None 118 | 119 | return head.next 120 | 121 | def printLinkedList(head): 122 | """打印单链表 123 | """ 124 | if head == None: return Node 125 | 126 | cur = head 127 | print("LinkedList is: ", end=' ') 128 | while cur != None: 129 | print(cur.value, end=' ') 130 | cur = cur.next 131 | 132 | print() 133 | 134 | 135 | if __name__ == '__main__': 136 | 137 | pivot = 5 138 | arr = [7, 9, 1, 8, 5, 2, 5] 139 | head1 = generateLinkedList(arr) 140 | 141 | printLinkedList(head1) 142 | 143 | #printLinkedList(listPartition1(head1, pivot)) 144 | printLinkedList(listPartition2(head1, pivot)) 145 | 146 | 147 | -------------------------------------------------------------------------------- /Part3_Tree/Code4_GetNextNode.py: -------------------------------------------------------------------------------- 1 | """在二叉树中找到一个节点的后继节点 2 | 3 | 后继节点:中序遍历时,该节点的下一个节点 4 | """ 5 | class Node(object): 6 | """二叉树的节点结构""" 7 | def __init__(self, val): 8 | self.value = val 9 | self.left = None 10 | self.right = None 11 | self.parent = None 12 | 13 | 14 | def getNextNode(node): 15 | """得到后继节点""" 16 | if node == None: 17 | return None 18 | 19 | if node.right != None: 20 | return getLeftMost(node.right) 21 | 22 | cur = node 23 | parent = node.parent 24 | while parent != None and parent.left != node: 25 | node = parent 26 | parent = node.parent 27 | 28 | return parent 29 | 30 | 31 | def getLeftMost(node): 32 | """得到右子树最左节点""" 33 | cur = node 34 | while cur.left != None: 35 | cur = cur.left 36 | 37 | return cur 38 | 39 | 40 | 41 | if __name__ == '__main__': 42 | 43 | head = Node(6) 44 | head.parent = None 45 | head.left = Node(3) 46 | head.left.parent = head 47 | head.left.left = Node(1) 48 | head.left.left.parent = head.left 49 | head.left.left.right = Node(2) 50 | head.left.left.right.parent = head.left.left 51 | head.left.right = Node(4) 52 | head.left.right.parent = head.left; 53 | head.left.right.right = Node(5) 54 | head.left.right.right.parent = head.left.right 55 | head.right = Node(9) 56 | head.right.parent = head 57 | head.right.left = Node(8) 58 | head.right.left.parent = head.right 59 | head.right.left.left = Node(7) 60 | head.right.left.left.parent = head.right.left 61 | head.right.right = Node(10) 62 | head.right.right.parent = head.right 63 | 64 | test = head.left.left 65 | print("%d next: %d"%(test.value, getNextNode(test).value)) 66 | test = head.left.left.right; 67 | print("%d next: %d"%(test.value, getNextNode(test).value)) 68 | test = head.left 69 | print("%d next: %d"%(test.value, getNextNode(test).value)) 70 | test = head.left.right 71 | print("%d next: %d"%(test.value, getNextNode(test).value)) 72 | test = head.left.right.right 73 | print("%d next: %d"%(test.value, getNextNode(test).value)) 74 | test = head 75 | print("%d next: %d"%(test.value, getNextNode(test).value)) 76 | test = head.right.left.left 77 | print("%d next: %d"%(test.value, getNextNode(test).value)) 78 | test = head.right.left 79 | print("%d next: %d"%(test.value, getNextNode(test).value)) 80 | test = head.right 81 | print("%d next: %d"%(test.value, getNextNode(test).value)) 82 | test = head.right.right # 10's next is null 83 | print("%d next:"%(test.value), end=' ') 84 | print(getNextNode(test)) 85 | -------------------------------------------------------------------------------- /Part3_Tree/Code4_PaperFolding.py: -------------------------------------------------------------------------------- 1 | """折纸问题:给定一个输入参数N,代表纸条都从下边向上方连续对折N次,请从上到下打印所有折痕的方向。""" 2 | 3 | def printAllFolds(n): 4 | """主进程""" 5 | pocessing(1, n, True) 6 | 7 | def pocessing(start, end, dowm): 8 | """递归子进程""" 9 | if start > end: 10 | return None 11 | 12 | pocessing(start+1, end, True) 13 | print("dowm" if dowm else "up", end=' ') 14 | pocessing(start+1, end, False) 15 | 16 | if __name__ == '__main__': 17 | n = 3 18 | printAllFolds(n) 19 | print() -------------------------------------------------------------------------------- /Part3_Tree/Code4_PreInPosRecur.py: -------------------------------------------------------------------------------- 1 | """二叉树的先序、中序、后序遍历的实现 2 | (递归形式和非递归形式) 3 | """ 4 | class Node(object): 5 | """二叉树节点表示 6 | """ 7 | def __init__(self, val): 8 | self.value = val 9 | self.left = None 10 | self.right = None 11 | 12 | 13 | ### 非递归实现 14 | 15 | def preOrderUnRecur(head): 16 | """先序遍历 17 | """ 18 | if head == None: 19 | return None 20 | 21 | stack = [] 22 | stack.append(head) 23 | while len(stack) != 0: 24 | cur = stack.pop(-1) 25 | print(cur.value, end=' ') 26 | 27 | if cur.right != None: 28 | stack.append(cur.right) 29 | if cur.left != None: 30 | stack.append(cur.left) 31 | 32 | 33 | def inOrderUnRecur(head): 34 | """中序遍历 35 | """ 36 | if head == None: 37 | return None 38 | 39 | stack = [] 40 | cur = head 41 | while len(stack) != 0 or cur != None: 42 | 43 | if cur != None: 44 | stack.append(cur) 45 | cur = cur.left 46 | else: 47 | cur = stack.pop(-1) 48 | print(cur.value, end=' ') 49 | cur = cur.right 50 | 51 | 52 | def posOrderUnRecur(head): 53 | """后序遍历 54 | """ 55 | if head == None: 56 | return None 57 | 58 | help1 = [] 59 | help1.append(head) 60 | stack = [] 61 | while len(help1) != 0: 62 | head = help1.pop() 63 | stack.append(head) 64 | 65 | if head.left != None: 66 | help1.append(head.left) 67 | if head.right != None: 68 | help1.append(head.right) 69 | 70 | while len(stack) != 0: 71 | print(stack.pop().value, end=' ') 72 | 73 | 74 | 75 | ### 递归实现 76 | 77 | def preOrderRecur(head): 78 | """先序遍历 79 | """ 80 | if head == None: 81 | return None 82 | 83 | print(head.value, end=' ') 84 | preOrderRecur(head.left) 85 | preOrderRecur(head.right) 86 | 87 | 88 | def inOrderRecur(head): 89 | """中序遍历 90 | """ 91 | if head == None: 92 | return None 93 | 94 | inOrderRecur(head.left) 95 | print(head.value, end=' ') 96 | inOrderRecur(head.right) 97 | 98 | 99 | def posOrderRecur(head): 100 | """后序遍历 101 | """ 102 | if head == None: 103 | return None 104 | 105 | posOrderRecur(head.left) 106 | posOrderRecur(head.right) 107 | print(head.value, end=' ') 108 | 109 | 110 | 111 | if __name__ == '__main__': 112 | head = Node(5) 113 | head.left = Node(3) 114 | head.right = Node(8) 115 | head.left.left = Node(2) 116 | head.left.right = Node(4) 117 | head.left.left.left = Node(1) 118 | head.right.left = Node(7) 119 | head.right.left.left = Node(6) 120 | head.right.right = Node(10) 121 | head.right.right.left = Node(9) 122 | head.right.right.right = Node(11) 123 | 124 | print("pre order: ") 125 | preOrderRecur(head) 126 | print() 127 | preOrderUnRecur(head) 128 | print() 129 | 130 | print("in order: ") 131 | inOrderRecur(head) 132 | print() 133 | inOrderUnRecur(head) 134 | print() 135 | 136 | 137 | print("pos order: ") 138 | posOrderRecur(head) 139 | print() 140 | posOrderUnRecur(head) 141 | print() -------------------------------------------------------------------------------- /Part3_Tree/Code4_PrintTree.py: -------------------------------------------------------------------------------- 1 | """较为直观打印二叉树""" 2 | import sys 3 | class Node(object): 4 | """二叉树节点""" 5 | def __init__(self, val): 6 | self.value = val 7 | self.left = None 8 | self.right = None 9 | 10 | 11 | def printTree(head): 12 | """打印二叉树""" 13 | length = 16 # 每个节点打印所占位数 14 | 15 | inOrderRecur(head, 0, 'H', length) 16 | 17 | 18 | def inOrderRecur(head, deep, label, length): 19 | """中序遍历(递归)""" 20 | if head == None: 21 | return None 22 | 23 | inOrderRecur(head.right, deep+1, 'v', length) 24 | 25 | str1 = "%s%d%s"%(label, head.value, label) 26 | len_l = (length - len(str1)) // 2 27 | len_r = length - len(str1) - len_l 28 | str1 = "%s%s%s%s"%(" "*(deep*length), " "*len_l, str1, " "*len_r) 29 | print(str1) 30 | 31 | inOrderRecur(head.left, deep+1, '^', length) 32 | 33 | 34 | 35 | if __name__ == '__main__': 36 | head = Node(1) 37 | head.left = Node(-222222222) 38 | head.right = Node(3) 39 | head.left.left = Node(88) 40 | head.right.left = Node(55555555) 41 | head.right.right = Node(66) 42 | head.left.left.right = Node(777) 43 | printTree(head) 44 | 45 | head = Node(1) 46 | head.left = Node(2) 47 | head.right = Node(3) 48 | head.left.left = Node(4) 49 | head.right.left = Node(5) 50 | head.right.right = Node(6) 51 | head.left.left.right = Node(7) 52 | printTree(head) 53 | 54 | head = Node(1) 55 | head.left = Node(1) 56 | head.right = Node(1) 57 | head.left.left = Node(1) 58 | head.right.left = Node(1) 59 | head.right.right = Node(1) 60 | head.left.left.right = Node(1) 61 | printTree(head) 62 | 63 | -------------------------------------------------------------------------------- /Part3_Tree/Code5_TrieTree.py: -------------------------------------------------------------------------------- 1 | """前缀树结构(字典树) 2 | 3 | 优点: 最大限度的减少无谓的字符串比较,查词效率比哈希表高(利用字符串的公共前缀来节约存储空间) 4 | 5 | 性质: 6 | 1. 根结点不包含字符,除根结点外每个节点只包含一个字符 7 | 2. 从根结点到某一结点,路径上经过的字符连接起来为该节点对应的字符串 8 | 3. 每个节点的所有子节点的字符都不相同 9 | """ 10 | class TrieTreeNode(object): 11 | """前缀树结构 12 | """ 13 | def __init__(self): 14 | self.via = 0 # 经由数 15 | self.end = 0 # 结尾数 16 | self.nexts = [None] * 26 # 下级节点 17 | 18 | 19 | class Trie(object): 20 | """前缀树的操作 21 | """ 22 | def __init__(self): 23 | self.root = TrieTreeNode() 24 | 25 | def insert(self, str1): 26 | """添加字符串 27 | """ 28 | if str1 == None or len(str1) == 0: 29 | return None 30 | 31 | node = self.root 32 | for each in str1: 33 | index = ord(each) - ord('a') 34 | if node.nexts[index] == None: 35 | node.nexts[index] = TrieTreeNode() 36 | 37 | node = node.nexts[index] 38 | node.via += 1 39 | 40 | node.end += 1 41 | 42 | 43 | def delete(self, str1): 44 | """删除字符串 45 | """ 46 | if str1 == None or len(str1) == 0 or self.search(str1) == False: 47 | return None 48 | 49 | node = self.root 50 | for each in str1: 51 | index = ord(each) - ord('a') 52 | node.nexts[index].via -= 1 53 | if node.nexts[index].via == 0: 54 | node.nexts[index] = None 55 | return None 56 | 57 | node = node.nexts[index] 58 | 59 | node.end -= 1 60 | 61 | 62 | def search(self, str1): 63 | """查询字符串 64 | """ 65 | if str1 == None or len(str1) == None: 66 | return False 67 | 68 | node = self.root 69 | for each in str1: 70 | index = ord(each) - ord('a') 71 | if node.nexts[index] == None: 72 | return False 73 | 74 | node = node.nexts[index] 75 | 76 | return node.end != 0 77 | 78 | 79 | def prefixNumber(self, prefix): 80 | """返回前缀数量 81 | """ 82 | if prefix == None or len(prefix) == 0: 83 | return 0 84 | 85 | node = self.root 86 | for each in prefix: 87 | index = ord(each) - ord('a') 88 | if node.nexts[index] == None: 89 | return 0 90 | 91 | node = node.nexts[index] 92 | 93 | return node.via 94 | 95 | 96 | if __name__ == '__main__': 97 | trie = Trie() 98 | print(trie.search("zuo")) # False 99 | trie.insert("zuo") 100 | print(trie.search("zuo")) # True 101 | trie.delete("zuo"); 102 | print(trie.search("zuo")) # False 103 | trie.insert("zuo") 104 | trie.insert("zuo") 105 | trie.delete("zuo") 106 | print(trie.search("zuo")) # True 107 | trie.delete("zuo") 108 | print(trie.search("zuo")) # False 109 | trie.insert("zuo") 110 | trie.insert("zuoac") 111 | trie.insert("zuoab") 112 | trie.insert("zuoad") 113 | trie.insert("zuoa") 114 | print(trie.search("zuoa")) # True 115 | print(trie.prefixNumber("zuo")) # 5 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /Part3_Tree/Code8_MaxTreeOfArray.py: -------------------------------------------------------------------------------- 1 | """给定一个没有重复元素的数组arr,写出生成这个数组的MaxTree的函数 P22 2 | 3 | 要求: 时间复杂度 O(N),额外空间复杂度 O(N) 4 | 5 | MaxTree的定义: 6 | 1) 数组必须没有重复元素 7 | 2) MaxTree是一颗二叉树,数组的每一个值对应一个二叉树的节点 8 | 3) 包含MaxTree树在内且在其中的每一颗子树上,值最大的节点都是树的头 9 | """ 10 | def getMaxTree(arr): 11 | """主程序 12 | """ 13 | if arr == None or len(arr) == 0: 14 | return None 15 | 16 | nArr = [] 17 | for i in range(len(arr)): 18 | nArr.append(Node(arr[i])) 19 | 20 | stack = [] 21 | lBigMap, rBigMap = dict(), dict() # 左右两段第一大值map 22 | 23 | # 找到每个数左侧第一个比它大的数 24 | for i in range(len(nArr)): 25 | curNode = nArr[i] 26 | while len(stack) != 0 and stack[-1].value < curNode.value: 27 | popStackSetMap(stack, lBigMap) 28 | stack.append(cur) 29 | 30 | while len(stack) != 0: 31 | popStackSetMap(stack, lBigMap) 32 | 33 | # 找个每个数的右侧第一个比它大的数 34 | for i in list(range(len(nArr)))[::-1]: 35 | curNode = nArr[i] 36 | while len(stack) != None and stack[-1].value < curNode.value: 37 | popStackSetMap(stack, rBigMap) 38 | stack.append(curNode) 39 | 40 | while len(stack) != 0: 41 | popStackSetMap(stack, rBigMap) 42 | 43 | # 生成maxTree树 44 | head = None 45 | for i in range(len(nArr)): 46 | curNode = nArr[i] 47 | leftMax = lBigMap[curNode] 48 | rightMax = rBigMap[curNode] 49 | 50 | if leftMax == None and rightMax == None: 51 | head = curNode 52 | 53 | elif leftMax == None: 54 | if rightMax.left == None: 55 | rightMax.left = curNode 56 | else: 57 | rightMax.right = curNode 58 | 59 | elif rightMax == None: 60 | if leftMax.left == None: 61 | leftMax.left = curNode 62 | else: 63 | leftMax.right = curNode 64 | 65 | else: 66 | parent = leftMax if leftMax.value < rightMax.value else rightMax 67 | if parent.left == None: 68 | parent.left = curNode 69 | else: 70 | parent.right = curNode 71 | 72 | return head 73 | 74 | def popStackSetMap(stack, bigMap): 75 | """设置 大值 map 76 | """ 77 | popNode = stack.pop(-1) 78 | if len(stack) == 0: 79 | bigMap[popNode] = None 80 | else: 81 | bigMap[popNode] = stack[-1] 82 | 83 | 84 | class Node(object): 85 | """二叉树节点结构 86 | """ 87 | def __init__(self, val): 88 | self.value = val 89 | self.left = None 90 | self.right = None 91 | 92 | 93 | """建树原则 94 | 1) 每一个数的父节点是它左边第一个比它大的数和它右边第一个比它大的数中,较小的那一个。 95 | 2) 如果一个数左侧和右侧都没有比它大的数,那么这个数是maxTree的头结点 96 | """ -------------------------------------------------------------------------------- /Part3_Tree/Code8_Morris.py: -------------------------------------------------------------------------------- 1 | """ 2 | 给定一颗二叉树的头结点head,完成二叉树的先序、中序和后序遍历。 3 | 如果二叉树的节点数为N,要求时间复杂度为O(N),额外空间复杂度为O(1)。 4 | """ 5 | def morrisPre(head): 6 | """Morris先序遍历 7 | """ 8 | if head == None: return None 9 | 10 | cur = head 11 | while cur != None: 12 | tmp = cur.left 13 | if tmp != None: 14 | while tmp.right != None and tmp.right != cur: 15 | tmp = tmp.right 16 | 17 | if tmp.right == None: 18 | print(cur.value, end=' ') 19 | tmp.right = cur 20 | cur = cur.left 21 | continue 22 | 23 | if tmp.right == cur: 24 | tmp.right = None 25 | else: 26 | print(cur.value, end=' ') 27 | 28 | cur = cur.right 29 | 30 | 31 | def morrisIn(head): 32 | """Morris中序遍历 33 | """ 34 | if head == None: return None 35 | 36 | cur = head 37 | while cur != None: 38 | tmp = cur.left 39 | if tmp != None: 40 | while tmp.right != None and tmp.right != cur: 41 | tmp = tmp.right 42 | 43 | if tmp.right == None: 44 | tmp.right = cur 45 | cur = cur.left 46 | continue 47 | 48 | if tmp.right == cur: 49 | tmp.right = None 50 | 51 | print(cur.value, end=' ') 52 | cur = cur.right 53 | 54 | 55 | def morrisPos(head): 56 | """Morris后序遍历 57 | """ 58 | if head == None: return None 59 | 60 | cur = head 61 | while cur != None: 62 | tmp = cur.left 63 | if tmp != None: 64 | while tmp.right != None and tmp.right != cur: 65 | tmp = tmp.right 66 | 67 | if tmp.right == None: 68 | tmp.right = cur 69 | cur = cur.left 70 | continue 71 | 72 | if tmp.right == cur: 73 | tmp.right = None 74 | printEdge(cur.left) 75 | 76 | cur = cur.right 77 | 78 | printEdge(head) 79 | 80 | 81 | def printEdge(head): 82 | """逆序打印右边界 83 | """ 84 | tail = reverseEdge(head) 85 | 86 | cur = tail 87 | while cur != None: 88 | print(cur.value, end=' ') 89 | cur = cur.right 90 | 91 | reverseEdge(tail) 92 | 93 | 94 | def reverseEdge(cur): 95 | """逆序操作 96 | """ 97 | pre = None 98 | nex = None 99 | while cur != None: 100 | nex = cur.right 101 | cur.right = pre 102 | pre = cur 103 | cur = nex 104 | 105 | return pre 106 | 107 | 108 | class Node(object): 109 | """二叉树的节点结构 110 | """ 111 | def __init__(self, val): 112 | self.value = val 113 | self.left = None 114 | self.right = None 115 | 116 | """Morris遍历 117 | 118 | 实质: 通过底层节点(叶子节点)指向None的空闲指针,指回上层的某个节点 119 | 120 | 过程: 121 | 1. 假设头结点为head,让head的《左子树中最右节点》的right指针指向head。 122 | 然后在其左子树中重复该步骤,直到遇到叶子结点(无左子树),记为node,进入步骤2 123 | 124 | 2. 从node开始通过每个节点的right指针进行移动,并以此打印。 假设当前移动到的节点 125 | 记为cur 126 | 1) cur《左子树中最右节点》的right指针指向cur(说明第二次到达cur) 127 | 令cur《左子树中最右节点》的right指针指向None; 128 | 通过右指针移动 cur = cur.right 129 | 130 | 2) cur《左子树中最右节点》的right指针指向None(说明第一次到达cur) 131 | 重复1步骤,即: 132 | 令cur《左子树中最右节点》的right指针指向cur 133 | 通过左指针移动 cur = cur.left 134 | 135 | 3. cur移动到空,整个过程结束 136 | """ 137 | 138 | if __name__ == '__main__': 139 | head = Node(5) 140 | head.left = Node(3) 141 | head.right = Node(8) 142 | head.left.left = Node(2) 143 | head.left.right = Node(4) 144 | head.left.left.left = Node(1) 145 | head.right.left = Node(7) 146 | head.right.left.left = Node(6) 147 | head.right.right = Node(10) 148 | head.right.right.left = Node(9) 149 | head.right.right.right = Node(11) 150 | 151 | print("pre order: ") 152 | morrisPre(head) 153 | print() 154 | 155 | print("in order: ") 156 | morrisIn(head) 157 | print() 158 | 159 | print("pos order: ") 160 | morrisPos(head) 161 | print() -------------------------------------------------------------------------------- /Part3_Tree/Code9_BSTMaxTopoSize.py: -------------------------------------------------------------------------------- 1 | """给定一棵二叉树的头结点head,已知所有节点的值都不一样, 2 | 返回其中最大的且符合搜索二叉树条件的最大拓扑结构的大小P119""" 3 | 4 | ####################《递归》######################## 5 | def bstTopoSize1(head): 6 | """时间复杂度 O(N^2) 7 | 8 | 给定头结点,返回该头节点下的最大拓扑大小 9 | """ 10 | if head == None: 11 | return 0 12 | 13 | max1 = maxTopo(head, head) 14 | max1 = max(bstTopoSize1(head.left), max1) 15 | max1 = max(bstTopoSize1(head.right), max1) 16 | return max1 17 | 18 | def maxTopo(head, node): 19 | """node及其子树可以为 以head为头的BST 提供多少节点拓扑 20 | """ 21 | 22 | if head != None and node != None and isBSTNode(head, node, node.value): 23 | return maxTopo(head, node.left) + maxTopo(head, node.right) + 1 24 | 25 | return 0 26 | 27 | def isBSTNode(head, node, value): 28 | """判断node是否可以构成 以head为头的BST 的拓扑 29 | """ 30 | if head == None: 31 | return False 32 | 33 | if head == node: 34 | return True 35 | 36 | return isBSTNode(head.left if head.value > value else head.right 37 | , node, value) 38 | 39 | 40 | 41 | class Node(object): 42 | """二叉树的节点结构 43 | """ 44 | def __init__(self, value): 45 | self.value = value 46 | self.left = None 47 | self.right = None -------------------------------------------------------------------------------- /Part3_Tree/Code9_FindMaxBST.py: -------------------------------------------------------------------------------- 1 | """给定一颗二叉树的头结点head,已知其中所有节点的值都不一样,找到含有节点数最多的搜索二叉树, 2 | 并返回这颗子树的头结点。 3 | 4 | 要求: 时间复杂度 O(N),额外空间复杂度O(h)""" 5 | 6 | def biggestSubBST(head): 7 | return posOrder(head)[0] 8 | 9 | 10 | def posOrder(head): 11 | """返回四个信息 12 | 13 | 最大搜索二叉树:头结点、 节点数、 最小值、 最大值 14 | """ 15 | if head == None: 16 | return None, 0, float('inf'), float('-inf') 17 | 18 | lBST, lSize, lMin, lMax = posOrder(head.left) 19 | rBST, rSize, rMin, rMax = posOrder(head.right) 20 | 21 | minVal = min(lMin, head.value) 22 | maxVal = max(rMax, head.value) 23 | 24 | if lBST == head.left and rBST == head.right and lMax < head.value and rMin > head.value: 25 | return head, (lSize + rSize + 1), minVal, maxVal 26 | 27 | if lSize > rSize: 28 | return lBST, lSize, lMin, lMax 29 | 30 | return rBST, rSize, rMin, rMax 31 | 32 | 33 | class Node(object): 34 | """二叉树的节点结构 35 | """ 36 | def __init__(self, value): 37 | self.value = value 38 | self.left = None 39 | self.right = None 40 | 41 | """对二叉树后序遍历的改写""" -------------------------------------------------------------------------------- /Part3_Tree/Code9_IsBalance.py: -------------------------------------------------------------------------------- 1 | """给定二叉树的头结点head,判断这棵二叉树是否为平衡二叉树 2 | 3 | 平衡二叉树的性质: 4 | 要么是空树 5 | 要么任何一个节点的左右子树高度差的绝对值不超过1 6 | """ 7 | 8 | def isBalance(head): 9 | """判断以head为头的树是否为平衡二叉树 10 | """ 11 | if head == None: return True 12 | 13 | isB, height = posOrder(head, 1) 14 | return isB 15 | 16 | 17 | def posOrder(node, level): 18 | """返回两个信息 是否是平衡二叉树、最深到哪一层 19 | 20 | node 表示 头结点; level 表示 当前头结点所在的层数 21 | """ 22 | if node == None: 23 | return True, level 24 | 25 | lIsB, lH = posOrder(node.left, level+1) 26 | if not lIsB: 27 | return False, lH 28 | 29 | rIsB, rH = posOrder(node.right, level+1) 30 | if not rIsB: 31 | return False, rH 32 | 33 | if abs(lH - rH) > 1: 34 | return False, max(lH, rH) 35 | 36 | return True, max(lH, rH) -------------------------------------------------------------------------------- /Part3_Tree/Code9_SkipList.py: -------------------------------------------------------------------------------- 1 | """跳表结构(空间换时间 链表+二分法的结合) 2 | 3 | 跳表的由来: 链表的插入和删除操作时间复杂度是O(1),但是查询操作时间复杂度O(N), 4 | 为了提高计算速度,就有了跳表的概念 5 | 6 | 跳表的性质: 7 | 1) 有很多层结构组成 8 | 2) 每一层都是一个有序的链表 9 | 3) 最底层的链表包含所有元素 10 | 4) 如果一个元素出现在leve i的链表中,则它在level i之下的链表中也都会出现 11 | 5)每个节点包含两个指针 a.指向同一链表中下一个元素的指针 b.指向下面一层的元素的指针 12 | 13 | 注意: 一个数能够到第几层是通过概率决定的 14 | 15 | 16 | 代码未完成!!!!!!!!!!!!! 17 | """ 18 | class SkipListNode(object): 19 | """跳表的节点结构 20 | """ 21 | def __init__(self, value): 22 | self.value = value 23 | self.nextNodes = [] 24 | 25 | 26 | class SkipList(object): 27 | """跳表 28 | """ 29 | global PROBABILITY 30 | PROBABILITY = 0.5 31 | 32 | def __init__(self): 33 | self.size = 0 34 | self.maxLevel = 0 35 | self.head = SkipListNode(None) 36 | self.head.nextNodes.append(None) 37 | 38 | def getHead(self): 39 | return self.head 40 | 41 | def add(self, newValue): 42 | """添加新的元素 43 | """ 44 | if not self.contains(newValue): 45 | self.size += 1 46 | 47 | level = 0 48 | while random.random() < PROBABILITY: 49 | level += 1 50 | 51 | while level > self.maxLevel: # 包含level 52 | self.head.nextNodes.append(None) 53 | self.maxLevel += 1 54 | 55 | newNode = SkipListNode(newValue) 56 | current = self.head 57 | while level >= 0: 58 | current = self.findNext(newValue, current, level) 59 | newNode.nextNodes.append() 60 | level -= 1 61 | 62 | 63 | 64 | 65 | def contains(self, value): 66 | node = self.find(value) 67 | return node != None and node.value != None and self.equal(node.value, value) 68 | 69 | def equalTo(self, a, b): 70 | return a == b 71 | 72 | 73 | 74 | """跳表与红黑树的比较 75 | 76 | 1. skiplist的复杂度和红黑树一样,但是实现起来更加简单 77 | 2. 在并发环境下,红黑树进行插入和删除操作的时候,需要一些rebalance操作,需要大量的锁 78 | skiplist需要锁相对较少 79 | """ -------------------------------------------------------------------------------- /Part3_Tree/lowestAncestor.py: -------------------------------------------------------------------------------- 1 | class Node(object): 2 | def __init__(self, val): 3 | self.value = val 4 | self.left = None 5 | self.right = None 6 | 7 | 8 | 9 | """返回二叉树两个节点的最近公共祖先""" 10 | def lowestAncestor(head, o1, o2): 11 | if head == None or head == o1 or head == o2: 12 | return head 13 | 14 | left = lowestAncestor(head.left, o1, o2) 15 | right = lowestAncestor(head.right, o1, o2) 16 | 17 | if left != None and right != None: 18 | return head 19 | 20 | return left if left != None else right 21 | -------------------------------------------------------------------------------- /Part4_HeapStructure/Code4_IPO.py: -------------------------------------------------------------------------------- 1 | """ 2 | 输入: 3 | 正数数组costs - costs[i]表示i号项目的花费 4 | 正数数组profits - profits[i]表示i号项目的纯利润 5 | 正数k - 表示你不能并行、只能串行的最多做k个项目 6 | 整数m - 表示你的初始资金 7 | 8 | 输出: 9 | 你最后获得的最大钱数 10 | 11 | 说明: 12 | 你每做完一个项目,马上获得的收益,可以支持你去做下一个项目 13 | """ 14 | class MyHeap(object): 15 | """公共类""" 16 | 17 | def __init__(self): 18 | self.heap = [] 19 | self.size = 0 20 | 21 | def push(self, pro): 22 | if self.size == 0: 23 | self.heap.append(pro) 24 | else: 25 | self.heap.append(pro) 26 | self.insertHeap() 27 | 28 | self.size += 1 29 | 30 | def pop(self): 31 | self.size -= 1 32 | self.heap[0], self.heap[self.size] = self.heap[self.size], self.heap[0] 33 | tmp = self.heap.pop(-1) 34 | self.heapify() 35 | return tmp 36 | 37 | def peak(self): 38 | return self.heap[0] 39 | 40 | def getSize(self): 41 | return self.size 42 | 43 | 44 | class MaxHeapForProfits(MyHeap): 45 | """利润大根堆 46 | """ 47 | def __init__(self): 48 | super(MaxHeapForProfits, self).__init__() 49 | 50 | def insertHeap(self): 51 | """插入堆""" 52 | arr = self.heap 53 | index = self.size 54 | 55 | par_i = (index-1) // 2 56 | while par_i >= 0 and arr[index].p > arr[par_i].p: 57 | arr[index], arr[par_i] = arr[par_i], arr[index] 58 | index = par_i 59 | par_i = (index - 1) // 2 60 | 61 | def heapify(self): 62 | """堆化""" 63 | arr = self.heap 64 | length = self.size 65 | index = 0 66 | 67 | left = 2 * index + 1 68 | while left < length: 69 | largest = left+1 if left+1 < length and arr[left+1].p > arr[left].p else left 70 | largest = index if arr[index].p >= arr[left].p else largest 71 | 72 | if largest == index: 73 | break 74 | 75 | arr[largest], arr[index] = arr[index], arr[largest] 76 | index = largest 77 | left = 2 * index + 1 78 | 79 | 80 | class MinHeapForCosts(MyHeap): 81 | """花费小根堆 82 | """ 83 | def __init__(self): 84 | super(MinHeapForCosts, self).__init__() 85 | 86 | def insertHeap(self): 87 | """插入堆""" 88 | arr = self.heap 89 | index = self.size 90 | 91 | par_i = (index-1) // 2 92 | while par_i >= 0 and arr[index].c < arr[par_i].c: 93 | arr[index], arr[par_i] = arr[par_i], arr[index] 94 | index = par_i 95 | par_i = (index - 1) // 2 96 | 97 | 98 | def heapify(self): 99 | """堆化""" 100 | arr = self.heap 101 | length = self.size 102 | index = 0 103 | 104 | left = 2 * index + 1 105 | while left < length: 106 | largest = left+1 if left+1 < length and arr[left+1].c < arr[left].c else left 107 | largest = index if arr[index].c <= arr[left].c else largest 108 | 109 | if largest == index: 110 | break 111 | 112 | arr[largest], arr[index] = arr[index], arr[largest] 113 | index = largest 114 | left = 2 * index + 1 115 | 116 | 117 | 118 | class Project(object): 119 | """项目(花费和利润) 120 | """ 121 | def __init__(self, cost, profit): 122 | self.c = cost 123 | self.p = profit 124 | 125 | 126 | def findMaxIncome(costs, profit, k, m): 127 | """找寻最大收入的解决方案 128 | """ 129 | project = [] 130 | for i in range(len(costs)): 131 | project.append(Project(costs[i], profit[i])) 132 | 133 | maxProfitQ, minCostQ = MaxHeapForProfits(), MinHeapForCosts() 134 | # 将项目都放进代价 小根堆 135 | for i in range(len(project)): 136 | minCostQ.push(project[i]) 137 | 138 | # 最多执行k次 139 | for _ in range(k): 140 | while (minCostQ.getSize != 0 and minCostQ.peak().c <= m): 141 | maxProfitQ.push(minCostQ.pop()) 142 | 143 | if maxProfitQ.getSize() == 0: 144 | return m 145 | 146 | m += maxProfitQ.pop().p 147 | 148 | return m 149 | 150 | 151 | if __name__ == '__main__': 152 | costs = [100, 200, 300, 400, 500, 10000] 153 | profit = [100, 120, 170, 200, 60, 100] 154 | k = 4 155 | m = 200 156 | 157 | print(findMaxIncome(costs, profit, k, m)) -------------------------------------------------------------------------------- /Part4_HeapStructure/Code4_LessMoney.py: -------------------------------------------------------------------------------- 1 | """切金条问题: 最小分割代价(哈夫曼树) 2 | 3 | 贪心问题 4 | """ 5 | import heapq 6 | 7 | class MinHeap(object): 8 | """小根堆接口""" 9 | def __init__(self): 10 | self.heap = [] 11 | self.size = 0 12 | 13 | def push(self, val): 14 | self.size += 1 15 | heapq.heappush(self.heap, val) 16 | 17 | def pop(self): 18 | self.size -= 1 19 | return heapq.heappop(self.heap) 20 | 21 | def getSize(self): 22 | return self.size 23 | 24 | 25 | def lessMoney(arr): 26 | if len(arr) == 1: 27 | return arr[0] 28 | 29 | heap = MinHeap() 30 | for i in arr: 31 | heap.push(i) 32 | 33 | sum1 = 0 34 | while heap.getSize() > 1: 35 | tmp = heap.pop() + heap.pop() 36 | sum1 += tmp 37 | heap.push(tmp) 38 | 39 | return sum1 40 | 41 | if __name__ == '__main__': 42 | arr = [3, 5, 2, 7, 0, 1, 6, 4] 43 | print(lessMoney(arr)) -------------------------------------------------------------------------------- /Part4_HeapStructure/Code4_MedianHolder.py: -------------------------------------------------------------------------------- 1 | """有一个源源不断地吐出整数的数据流,假设你有足够的空间 2 | 来保存吐出的数。请设计一个名叫 MedianHolder 的结构,该 3 | 结构可以随时取得之前吐出所有数的中位数。 4 | """ 5 | import heapq 6 | import random 7 | import copy 8 | 9 | class MedianHolder(object): 10 | def __init__(self): 11 | self.min_heap, self.max_heap = MinHeap(), MaxHeap() 12 | 13 | def __modifyTwoHeapSize(self): 14 | """调整两个堆的大小""" 15 | if self.min_heap.size - self.max_heap.size == 2: 16 | self.max_heap.push(self.min_heap.pop()) 17 | 18 | elif self.max_heap.size - self.min_heap.size == 2: 19 | self.min_heap.push(self.max_heap.pop()) 20 | 21 | else: 22 | pass 23 | 24 | 25 | def addNumber(self, val): ### ** 26 | """向结构中添加元素""" 27 | 28 | if self.max_heap.size == 0: 29 | self.max_heap.push(val) 30 | return None 31 | 32 | if self.max_heap.peak() >= val: 33 | self.max_heap.push(val) 34 | else: 35 | self.min_heap.push(val) 36 | 37 | self.__modifyTwoHeapSize() 38 | 39 | 40 | def getMedian(self): 41 | """得到吐出的所有数的中值""" 42 | 43 | max_size, min_size = self.max_heap.size, self.min_heap.size 44 | 45 | if max_size + min_size == 0: 46 | return None 47 | 48 | if max_size + min_size == 1: # ** 49 | return self.max_heap.peak() if max_size == 1 else self.min_heap.peak() 50 | 51 | max_top, min_top = self.max_heap.peak(), self.min_heap.peak() 52 | 53 | if (max_size + min_size) % 2 == 0: 54 | return (max_top + min_top) / 2 55 | 56 | return max_top if max_size > min_size else min_top 57 | 58 | 59 | class MinHeap(object): 60 | """使用heapq模块 实现小根堆""" 61 | def __init__(self): 62 | self.heap = [] 63 | self.size = 0 64 | 65 | def push(self, value): 66 | self.size += 1 67 | heapq.heappush(self.heap, value) 68 | 69 | def pop(self): 70 | self.size -= 1 71 | return heapq.heappop(self.heap) 72 | 73 | def peak(self): 74 | return self.heap[0] 75 | 76 | 77 | class MaxHeap(object): 78 | """使用heapq模块 实现大根堆""" 79 | def __init__(self): 80 | self.heap = [] 81 | self.size = 0 82 | 83 | def push(self, value): 84 | heapq.heappush(self.heap, -value) # 压入相反数 85 | self.size += 1 86 | 87 | def pop(self): 88 | self.size -= 1 89 | return -heapq.heappop(self.heap) # 弹出相反数 90 | 91 | def peak(self): 92 | return -self.heap[0] # 返回相反数 93 | 94 | ####################################################### 95 | """下面部分为对数器部分 96 | """ 97 | def generateRandomArray(max_len, max_val): 98 | length = int(random.random() * max_len + 1) 99 | 100 | return [int(random.random() * max_val + 1) for i in range(length)] 101 | 102 | 103 | def getMedianForArray(arr): 104 | new_arr = copy.copy(arr) 105 | new_arr.sort() 106 | length = len(new_arr) 107 | mid = (length - 1) // 2 108 | 109 | if length % 2 == 0: 110 | return (new_arr[mid] + new_arr[mid+1]) / 2 111 | else: 112 | return new_arr[mid] 113 | 114 | 115 | if __name__ == '__main__': 116 | 117 | 118 | max_len = 50 119 | max_val = 100 120 | iter_num = 50000 121 | succeed = True 122 | 123 | while iter_num > 0: 124 | iter_num -= 1 125 | 126 | median_holder = MedianHolder() 127 | 128 | arr = generateRandomArray(max_len, max_val) 129 | for i in arr: 130 | median_holder.addNumber(i) 131 | 132 | if median_holder.getMedian() != getMedianForArray(arr): 133 | succeed = False 134 | break 135 | 136 | print("today is a beatiful day!" if succeed else "What's the Fuck!") 137 | print(arr) 138 | arr.sort() 139 | print(arr) 140 | print(median_holder.getMedian()) 141 | print(getMedianForArray(arr)) -------------------------------------------------------------------------------- /Part5_Graph/Code5_BFS.py: -------------------------------------------------------------------------------- 1 | """图的宽度优先遍历 2 | 3 | (通过距离组织,离我近的先打印,离我远的后打印,但是不能重复打印) 4 | """ 5 | 6 | def bfs(node): 7 | 8 | if node == None: return None 9 | 10 | queue, qSet = list(), set() 11 | queue.append(node) 12 | 13 | while len(queue) != 0: 14 | cur = queue.pop(0) 15 | print(cur.value) 16 | 17 | if cur not in qSet: 18 | qSet.add(cur) 19 | for nex in cur.nexts: 20 | queue.append(nex) 21 | 22 | -------------------------------------------------------------------------------- /Part5_Graph/Code5_DFS.py: -------------------------------------------------------------------------------- 1 | """图的深度优先遍历 2 | 3 | (一个节点的某条路,走到不能再走,退回上级再走)一条路走到黑 4 | """ 5 | def dfs(node): 6 | """迭代实现 7 | """ 8 | if node == None: return None 9 | 10 | stack, sSet = list(), set() 11 | stack.append(node) 12 | while len(stack) != 0: 13 | cur = stack.pop(-1) 14 | 15 | if cur not in sSet: 16 | sSet.add(cur) 17 | for each in cur.nexts: 18 | stack.append(each) 19 | 20 | 21 | 22 | def dfs(node): 23 | """课程代码 24 | """ 25 | if node == None: return None 26 | 27 | stack, h_set = list(), set() 28 | stack.append(node) 29 | h_set.add(node) 30 | print(node.value) 31 | while len(stack) != 0: 32 | cur = stack.pop(-1) 33 | 34 | for each in cur.nexts: 35 | if each not in h_set: 36 | stack.append(cur) 37 | stack.append(each) 38 | h_set.add(each) 39 | 40 | print(each.value) 41 | 42 | break 43 | 44 | 45 | -------------------------------------------------------------------------------- /Part5_Graph/Code5_DefineGraph.py: -------------------------------------------------------------------------------- 1 | """程序设计中图的表示(类表示)""" 2 | 3 | 4 | ################ 图的程序表示(如下) ################ 5 | 6 | class Graph(object): 7 | """定义图 8 | """ 9 | def __init__(self): 10 | self.nodes = dict() # 点集 11 | self.edges = set() # 边集 12 | 13 | 14 | class Node(object): 15 | """图的节点表示 16 | """ 17 | def __init__(self, value): 18 | self.value = value # 节点值 19 | self.in_degree = 0 # 入度 20 | self.out_degree = 0 # 出度 21 | self.nexts = [] # 下级节点集合 22 | self.edges = [] # 该节点出发的所有边集合 23 | 24 | 25 | class Edge(object): 26 | """图中边的表示 27 | """ 28 | def __init__(self, weight, start, end): 29 | self.weight = weight 30 | self.start = start 31 | self.end = end 32 | 33 | 34 | 35 | ################ 图的生成(见下) ################ 36 | 37 | class GraphGenerator(object): 38 | """图的生成:给定一个图的矩阵表示 39 | [ 40 | [权重,从哪来,到哪去], 41 | [权重,从哪来,到哪去], 42 | …… 43 | 44 | ] 45 | """ 46 | def generateGraph(self, matrix): 47 | graph = Graph() 48 | for weight, beg_node, end_node in matrix: 49 | 50 | if graph.nodes.get(beg_node) == None: 51 | graph.nodes[beg_node] = Node(beg_node) 52 | if graph.nodes.get(end_node) == None: 53 | graph.nodes[end_node] = Node(end_node) 54 | 55 | beg_node = graph.nodes[beg_node] 56 | end_node = graph.nodes[end_node] 57 | edge = Edge(weight, beg_node, end_node) 58 | 59 | beg_node.out_degree += 1 60 | beg_node.edges.append(edge) 61 | beg_node.nodes.append(end_node) 62 | end_node.in_degree += 1 63 | 64 | graph.edges.add(edge) 65 | 66 | return graph -------------------------------------------------------------------------------- /Part5_Graph/Code5_Dijkstra.py: -------------------------------------------------------------------------------- 1 | """Dijkstra算法(适用于:没有负权值的边) 2 | 3 | Dijkstra算法是一种单源最短路径,针对的是非负权边。所谓的 4 | 单源最短路径: 指定一个出发顶点,计算从该源顶点出发到其他 5 | 所有顶点的最短路径 6 | """ 7 | import sys 8 | def dijkstra1(node): 9 | 10 | distanceMap = dict() 11 | distanceMap[node] = 0 12 | selectedNodes = set() 13 | 14 | minNode = getMinDistanceAndUnselectedNode(distanceMap, selectedNodes) 15 | while minNode != None: 16 | distance = distanceMap.get(minNode) 17 | for edge in minNode.edges: 18 | toNode = edge.end 19 | if distanceMap.get(toNode) == None: 20 | distanceMap[toNode] = distance + edge.weight 21 | 22 | distanceMap[toNode] = min(distanceMap[toNode], distance + edge.weight) 23 | 24 | selectedNodes.add(minNode) 25 | minNode = getMinDistanceAndUnselectedNode(distanceMap, selectedNodes) 26 | 27 | return distanceMap 28 | 29 | def getMinDistanceAndUnselectedNode(distanceMap, selectedNodes): 30 | """得到距离最近并且没有选过的节点 31 | """ 32 | minNode = None 33 | minDistance = sys.maxSize 34 | for node, distance in distanceMap.items(): 35 | if node not in selectedNodes and distance < minDistance: 36 | minNode = node 37 | minDistance = distance 38 | 39 | return minNode -------------------------------------------------------------------------------- /Part5_Graph/Code5_Kruskal.py: -------------------------------------------------------------------------------- 1 | """Kruskal算法: 加边法 (实现:并查集+堆结构) 2 | 3 | 初始最小生成树边数为0,每迭代一次就选择一条满足不成环的最小代价边, 4 | 加入到最小生成树的边集合里,知道选取n-1条边。 5 | """ 6 | def kruskalMSI(graph): 7 | """算法程序 8 | """ 9 | union_find = UnionFindSet() 10 | union_find.preprocessing(graph.nodes.values()) 11 | 12 | min_heap = MinHeap() 13 | for edge in graph.edges: 14 | min_heap.push(edge) 15 | 16 | result = set() 17 | while min_heap.getSize() != 0: 18 | edge = min_heap.pop() 19 | if not union_find.isSameSet(edge.start, edge.end): 20 | result.add(edge) 21 | union_find.union(edge.start, edge.end) 22 | 23 | return result 24 | 25 | 26 | 27 | class MinHeap(object): 28 | """小根堆结构: 比较信息 - 边的权重 29 | """ 30 | def __init__(self): 31 | self.heap, self.size = [], 0 32 | 33 | def push(self, edge): 34 | self.heap.append(edge) 35 | if self.size != 0: 36 | self.insertHeap() 37 | self.size += 1 38 | 39 | def pop(self): 40 | self.heap[0], self.heap[-1] = self.heap[-1], self.heap[0] 41 | tmp = self.heap.pop(-1) 42 | self.size -= 1 43 | self.heapify() 44 | return tmp 45 | 46 | def peak(self): 47 | return self.heap[0] 48 | 49 | def getSize(self): 50 | return self.size 51 | 52 | def insertHeap(self): 53 | """插入堆 54 | """ 55 | index = self.size 56 | parent = (index - 1) >> 1 57 | while parent >= 0 and self.heap[parent].weight > self.heap[index].weight: 58 | self.heap[parent], self.heap[index] = self.heap[index], self.heap[parent] 59 | index = parent 60 | parent = (index - 1) >> 1 61 | 62 | def heapify(self): 63 | """堆化 64 | """ 65 | arr = self.heap 66 | length = self.size 67 | index = 0 68 | 69 | left = index * 2 + 1 70 | while left < length: 71 | mini_est = left + 1 if left+1 < length and arr[left+1].weight < arr[left].weight else left 72 | mini_est = index if arr[index].weight <= arr[mini_est].weight else mini_est 73 | 74 | if mini_est == index: 75 | break 76 | 77 | arr[mini_est], arr[index] = arr[index], arr[mini_est] 78 | index = mini_est 79 | left = 2 * index + 1 80 | 81 | 82 | class UnionFindSet(object): 83 | """并查集结构 84 | """ 85 | def __init__(self): 86 | self.fatherMap = dict() 87 | self.sizeMap = dict() 88 | 89 | def preprocessing(self, edges): 90 | self.fatherMap.clear() 91 | self.sizeMap.clear() 92 | 93 | for each in edges: 94 | self.fatherMap[each] = each 95 | self.sizeMap[each] = 1 96 | 97 | def findFather(self, edge): 98 | father = self.fatherMap[edge] 99 | 100 | if father != edge: 101 | father = self.findFather(father) 102 | 103 | self.fatherMap[edge] = father 104 | return father 105 | 106 | def union(self, a, b): 107 | if a == None or b == None: 108 | return None 109 | 110 | aFather = self.fatherMap[a] 111 | bFather = self.fatherMap[b] 112 | 113 | if aFather != bFather: 114 | aSize = self.sizeMap[aFather] 115 | bSize = self.sizeMap[bFather] 116 | if aSize > bSize: 117 | self.fatherMap[bFather] = aFather 118 | self.sizeMap[aFather] = aSize + bSize 119 | else: 120 | self.fatherMap[aFather] = bFather 121 | self.sizeMap[bFather] = aSize + bSize 122 | 123 | def isSameSet(self, a, b): 124 | return self.findFather(a) == self.findFather(b) 125 | -------------------------------------------------------------------------------- /Part5_Graph/Code5_Prim.py: -------------------------------------------------------------------------------- 1 | """Prim算法(加点法) 2 | 3 | 以任意一个顶点开始,选最小的代价边,解锁新的顶点,重复该过程,直到所有顶点都解锁 4 | """ 5 | def primMSI(graph): 6 | """算法过程 7 | """ 8 | result = set() 9 | 10 | node_set = set() 11 | min_heap = MinHeap() 12 | 13 | node = graph.nodes.values()[0] # 从一个顶点开始 14 | node_set.add(node) 15 | for edge in node.edges: 16 | min_heap.push(edge) 17 | 18 | while min_heap.getSize() != 0: 19 | edge = min_heap.pop() 20 | toNode = edge.end 21 | 22 | if toNode not in node_set: 23 | node_set.add(toNode) 24 | result.add(edge) 25 | 26 | for edge in toNode.edges: 27 | min_heap.push(each) 28 | 29 | 30 | 31 | 32 | class MinHeap(object): 33 | 34 | def __init__(self): 35 | self.heap = [] 36 | self.size = 0 37 | 38 | def push(self, edge): 39 | self.heap.append(edge) 40 | if self.size != 0: 41 | self.__insertHeap() 42 | 43 | self.size += 1 44 | 45 | 46 | def pop(self): 47 | self.size -= 1 48 | self.heap[0], self.heap[self.size] = self.heap[self.size], self.heap[0] 49 | tmp = self.heap.pop(-1) 50 | self.__heapify() 51 | return tmp 52 | 53 | 54 | def getSize(self): 55 | return self.size 56 | 57 | 58 | def __insertHeap(self): 59 | """插入堆 60 | """ 61 | arr = self.heap 62 | index = self.size 63 | 64 | par_i = (index - 1) >> 1 65 | while par_i >= 0 and arr[par_i].weight > arr[index].weight: 66 | arr[par_i], arr[index] = arr[index], arr[par_i] 67 | index = par_i 68 | par_i = (index - 1) >> 1 69 | 70 | 71 | def __heapify(self): 72 | """堆化 73 | """ 74 | arr = self.heap 75 | index = 0 76 | length = self.size 77 | 78 | left = 2 * index + 1 79 | while left < length: 80 | mini_est = left + 1 if (left+1) < length and arr[left+1].weight < arr[left].weight else left 81 | mini_est = index if arr[index].weight <= arr[mini_est] else mini_est 82 | 83 | if mini_est == index: 84 | break 85 | 86 | arr[index], arr[mini_est] = arr[mini_est], arr[index] 87 | index = mini_est 88 | left = 2 * index + 1 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /Part5_Graph/Code5_TopologySort.py: -------------------------------------------------------------------------------- 1 | """拓扑排序算法 2 | 定义:将有向图中的顶点以线性的方式进行排序 3 | 适用范围:有向无环图 4 | """ 5 | def topologySort(graph): 6 | 7 | inMap = dict() # 节点与其入度hashmap 8 | zeroInQueue = [] # 0 入度节点 9 | 10 | for node in graph.nodes.values(): 11 | inMap[node] = node.in_degree 12 | if node.in_degree == 0: 13 | zeroInQueue.append(node) 14 | 15 | result = [] 16 | while len(zeroInQueue) != 0: 17 | cur = zeroInQueue.pop(0) 18 | result.append(cur) 19 | 20 | for each in cur.nexts: 21 | inMap[each] -= 1 22 | if inMap[each] == 0: 23 | zeroInQueue.append(each) 24 | 25 | 26 | return result -------------------------------------------------------------------------------- /Part6_Recursion_DP/Code7_CoinMethodNum.py: -------------------------------------------------------------------------------- 1 | """给定数组 arr, arr中所有的值都为正数且不重复。每个值代表一种面值的货币, 2 | 每种面值的货币可以使用任意张,再给定一个整数aim代表要找的钱数,求换钱的有多少种方法?""" 3 | 4 | def methodNum_1(arr, aim): 5 | """暴力递归 6 | """ 7 | if arr == None or len(arr) == 0 or aim < 0: 8 | return -1 9 | 10 | return process(arr, len(arr) - 1, aim) 11 | 12 | 13 | def process(arr, index, aim): 14 | if aim < 0 or index < 0: 15 | return 0 16 | 17 | if aim == 0: 18 | return 1 19 | 20 | if index == 0: 21 | return 1 if aim % arr[0] == 0 else 0 22 | 23 | return process(arr, index-1, aim) + process(arr, index, aim - arr[index]) 24 | 25 | 26 | def methodNum_2(arr, aim): 27 | """动态规划 28 | """ 29 | if arr == None or len(arr) == 0 or aim < 0: 30 | return -1 31 | 32 | row, col = len(arr), aim+1 33 | 34 | dp = [] 35 | for _ in range(row): 36 | dp.append([0] * col) 37 | 38 | # 初始化第一行 39 | dp[0][0] = 1 # aim == 0 -> return 1 40 | for i in range(1, col): 41 | dp[0][i] = 1 if i % arr[0] == 0 else 0 42 | 43 | # 其他位置 44 | for i in range(1, row): 45 | dp[i][0] = 1 # aim == 0 -> return 1 46 | for j in range(1, col): 47 | tmp = dp[i][j-arr[i]] if j - arr[i] >= 0 else 0 48 | dp[i][j] = tmp + dp[i-1][j] 49 | 50 | return dp[row-1][col-1] 51 | 52 | 53 | 54 | def methodNum_3(arr, aim): 55 | """动态规划(空间压缩) 56 | """ 57 | if arr == None or len(arr) == 0 or aim < 0: 58 | return 0 59 | 60 | row, col = len(arr), aim + 1 61 | dp = [0] * col 62 | dp[0] = 1 63 | for i in range(1, col): 64 | dp[i] = 1 if i%arr[0] == 0 else 0 65 | 66 | for i in range(1, row): 67 | for j in range(1, col): 68 | 69 | dp[j] = dp[j] + (dp[j-arr[i]] if j-arr[i] >= 0 else 0) 70 | 71 | return dp[-1] 72 | 73 | 74 | if __name__ == '__main__': 75 | arr = [5, 10, 25, 1] 76 | aim = 500 77 | 78 | print(methodNum_1(arr, aim)) 79 | print(methodNum_2(arr, aim)) 80 | print(methodNum_3(arr, aim)) 81 | -------------------------------------------------------------------------------- /Part6_Recursion_DP/Code7_Fibonacci.py: -------------------------------------------------------------------------------- 1 | """问题1: 2 | 3 | 给定一个整数N,返回斐波那契数列的第N项? 4 | """ 5 | 6 | def fibonacci_1(n): 7 | """暴力递归 时间复杂度 O(2^n) 8 | """ 9 | if n < 0: 10 | raise ValueError("The n is illegal!") 11 | 12 | if n < 3: 13 | return 1 14 | 15 | return fibonacci_1(n - 1) + fibonacci_1(n - 2) 16 | 17 | 18 | def fibonacci_2(n): 19 | """动态规划 时间复杂度 O(n) 20 | """ 21 | if n < 0: 22 | raise ValueError("The n is illegal!") 23 | 24 | if n < 3: 25 | return 1 26 | 27 | a, b = 1, 1 28 | for _ in range(3, n+1): 29 | tmp = a + b 30 | a = b 31 | b = tmp 32 | 33 | return tmp 34 | 35 | 36 | def fibonacci_3(n): 37 | """矩阵乘法 时间复杂度 O(logn) P184 38 | """ 39 | pass 40 | 41 | 42 | """问题2: 43 | 44 | 给定整数N,代表台阶数,一次可以跨2个或者1个台阶,返回有多少种走法? 45 | """ 46 | 47 | def treppe_1(n): 48 | """暴力递归 49 | """ 50 | if n < 1: 51 | raise ValueError("The input is illegal! ") 52 | 53 | if n < 3 : 54 | return n 55 | 56 | return treppe_1(n-1) + treppe_1(n-2) 57 | 58 | 59 | def treppe_2(n): 60 | """动态规划 61 | """ 62 | if n < 1: 63 | raise ValueError("The input is illegal! ") 64 | 65 | if n < 3 : 66 | return n 67 | 68 | a, b = 1, 2 69 | for _ in range(3, n+1): 70 | tmp = a + b 71 | a = b 72 | b = tmp 73 | 74 | return tmp 75 | 76 | 77 | """问题3: 78 | 79 | 假设农场中成熟的母牛每年只会生1头小母牛,并且永远不会死。 第一年农场有一只成熟的母牛, 80 | 从第二年开始,母牛开始生小母牛。每只小母牛3年之后成熟又可以生小母牛。给定整数N,求N年 81 | 后牛的数量? 82 | """ 83 | def cow_1(n): 84 | """暴力递归 85 | """ 86 | if n < 1: 87 | raise ValueError("The input is illegal!") 88 | 89 | if n <= 3: return n 90 | 91 | return cow_1(n-1) + cow_1(n-3) 92 | 93 | 94 | def cow_2(n): 95 | """动态规划 96 | """ 97 | if n < 1: 98 | raise ValueError("The input is illegal!") 99 | 100 | if n <= 3: return n 101 | 102 | prepre = 1 103 | pre = 2 104 | res = 3 105 | for i in range(4, n+1): 106 | tmp = res 107 | res = res + prepre 108 | prepre = pre 109 | pre = tmp 110 | 111 | return res 112 | 113 | if __name__ == '__main__': 114 | n = 13 115 | print(fibonacci_1(n)) 116 | print(fibonacci_2(n)) 117 | print("-------") 118 | print(treppe_1(n)) 119 | print(treppe_2(n)) 120 | print("-------") 121 | print(cow_1(n)) 122 | print(cow_2(n)) 123 | -------------------------------------------------------------------------------- /Part6_Recursion_DP/Code7_Knapsack.py: -------------------------------------------------------------------------------- 1 | """给定两个数组w和v,两个数组长度相等,w[i]表示第i件商品的重量,v[i]表示第i见商品的价值。 2 | 再给定一个整数bag,要求你挑选商品的重量加起来一定不能超过bag,返回满足这个条件下,你能获 3 | 得的最大价值!""" 4 | def maxValue1(w, v, bag): 5 | """暴力递归 6 | """ 7 | if w == None or len(w) == 0 or v == None or len(v) == 0 or bag < 0: 8 | return None 9 | 10 | return process1(w, v, 0, 0, bag) 11 | 12 | def process1(w, v, i, already, bag): 13 | if already > bag: 14 | return float('-inf') 15 | 16 | if i == len(w): #### 17 | return 0 18 | 19 | return max( 20 | process1(w, v, i+1, already, bag), 21 | v[i] + process1(w, v, i+1, already+w[i], bag), 22 | ) 23 | 24 | 25 | def maxValue2(w, v, bag): 26 | """动态规划 27 | """ 28 | if w == None or len(w) == 0 or v == None or len(v) == 0 or bag < 0: 29 | return None 30 | 31 | row, col = len(w) + 1, bag + 1 32 | dp = [] 33 | for _ in range(row): 34 | dp.append([0] * col) 35 | 36 | # 其他位置 37 | for i in list(range(row-1))[::-1]: # 从后向前 38 | for j in range(col): 39 | dp[i][j] = dp[i+1][j] 40 | if j + w[i] <= bag: 41 | dp[i][j] = max( 42 | dp[i][j], 43 | v[i] + dp[i+1][j+w[i]] 44 | ) 45 | 46 | return dp[0][0] 47 | 48 | 49 | def maxValue3(w, v, bag): 50 | """空间压缩技术""" 51 | 52 | if w == None or len(w) == 0 or v == None or len(v) == 0 or bag < 0: 53 | return None 54 | 55 | row, col = len(w) + 1, bag + 1 56 | dp = [0] * col 57 | 58 | for i in list(range(row-1))[::-1]: 59 | for j in range(col): 60 | 61 | dp[j] = max( 62 | dp[j], 63 | v[i] + (dp[j+w[i]] if j + w[i] <= bag else -float('inf')) 64 | ) 65 | 66 | return dp[0] 67 | 68 | 69 | 70 | 71 | 72 | ############### 73 | 74 | 75 | if __name__ == '__main__': 76 | w = [3, 2, 4, 7] 77 | v = [5, 6, 3, 19] 78 | bag = 0 79 | while bag <= sum(w): 80 | bag += 1 81 | print(maxValue1(w, v, bag), end=' ') 82 | print(maxValue2(w, v, bag), end=' ') 83 | print(maxValue3(w, v, bag)) 84 | -------------------------------------------------------------------------------- /Part6_Recursion_DP/Code7_MinCoinNum.py: -------------------------------------------------------------------------------- 1 | """给定数组arr,arr中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张, 2 | 再给定一个整数aim代表要找的钱数,求组成aim的最少货币数?""" 3 | 4 | def minCoinNum_1(arr, aim): 5 | """暴力递归 6 | """ 7 | if arr == None or len(arr) == 0 or aim < 0: 8 | return -1 9 | 10 | #return process_1(arr,0,aim) 11 | return process(arr, len(arr)-1, aim) 12 | 13 | def process(arr, index, aim): # arr[0 - index] 这些货币,得到aim的最小货币数 14 | 15 | # 当目标钱数aim=0时,返回0张钱 16 | if aim == 0: 17 | return 0 18 | 19 | # 当目标钱数aim<0时,表示换不开,返回无穷大 20 | if aim < 0: 21 | return float('inf') 22 | 23 | # 当只用 arr[0] 面值的钱时, aim是arr[0]整数倍时 - 可以换开; aim不是arr[0]整数倍时 - 换不开(返回无穷大) 24 | if index == 0: 25 | return aim // arr[index] if (aim % arr[index] == 0) else float('inf') 26 | 27 | """ 28 | process(arr, index, aim) 表示用 arr[0], arr[1], ..., arr[index] 这些面值的钱 可以 换取 aim 的最小货币数 29 | 它的值来源于下面两种情况: 30 | 1. process(arr, index-1, aim) 表示 不用 arr[index], 只用 arr[0] 到 arr[index-1]这些面值的钱 31 | 可以 换取 aim 的最小货币数 32 | 2. process(arr, index, aim - arr[index]) 表示用 arr[index],也就是用 arr[0] 到 arr[index]这些面值的钱 33 | 可以 换取 aim-arr[index] 的最小货币数 34 | 所以 35 | process(arr, index, aim)的值 等于 36 | min( 37 | process(arr, index-1, aim), 38 | 1 + process(arr, index, aim - arr[index]) 39 | ) 40 | """ 41 | return min( 42 | process(arr, index-1, aim), 43 | 1 + process(arr, index, aim - arr[index]) 44 | ) 45 | 46 | 47 | def process_1(arr, index, aim): # arr[index:] 这些货币,得到aim的最小货币数 48 | if index == len(arr): 49 | return float('inf') 50 | 51 | tmp = float('inf') 52 | for i in range(index, len(arr)): 53 | if aim == arr[i]: 54 | return 1 55 | elif aim < arr[i]: 56 | continue 57 | else: 58 | tmp = min(tmp, 1 + process_1(arr, i, aim-arr[i])) 59 | 60 | return tmp 61 | 62 | 63 | 64 | def minCoinNum_2(arr, aim): 65 | """动态规划 P192 核心: dp[i][j] = min( dp[i-1][j], dp[i][j-arr[i]] + 1) 66 | """ 67 | if arr == None or len(arr) == 0 or aim < 0: 68 | return -1 69 | 70 | row, col = len(arr), aim + 1 71 | dp = [] 72 | for _ in range(row): 73 | dp.append([0] * col) 74 | 75 | # 第一行 76 | for i in range(1, col): 77 | dp[0][i] = i//arr[0] if i%arr[0] == 0 else float('inf') 78 | 79 | for i in range(1, row): 80 | for j in range(1, col): 81 | dp[i][j] = min( 82 | dp[i-1][j], 83 | 1 + dp[i][j-arr[i]] 84 | ) if j - arr[i] >= 0 else float('inf') 85 | 86 | 87 | return dp[row - 1][col - 1] if dp[row-1][col-1] != float('inf') else -1 88 | 89 | def minCoinNum_3(arr, aim): 90 | """动态规划(空间压缩)P193 91 | """ 92 | if arr == None or len(arr) == 0 or aim < 0: 93 | return -1 94 | 95 | row, col = len(arr), aim + 1 96 | dp = [0] * col 97 | 98 | # 第一行 99 | for i in range(1, col): 100 | dp[i] = i // arr[0] if i%arr[0] == 0 else float('inf') 101 | 102 | for i in range(1, row): 103 | for j in range(1, col): 104 | 105 | dp[j] = min( 106 | dp[j], 107 | 1 + dp[j - arr[i]] 108 | ) if j-arr[i] >= 0 else float('inf') 109 | 110 | return dp[-1] 111 | 112 | 113 | if __name__ == '__main__': 114 | arr = [5, 4, 3, 2] 115 | aim = 23 116 | print(minCoinNum_1(arr, aim)) 117 | print(minCoinNum_2(arr, aim)) 118 | print(minCoinNum_3(arr, aim)) 119 | -------------------------------------------------------------------------------- /Part6_Recursion_DP/Code7_MinCoinNum_2.py: -------------------------------------------------------------------------------- 1 | """ 2 | 补充问题: 给定一个数组arr, arr中所有的值都为正数。《每个值仅代表一张钱的面值》, 3 | 再给定一个整数aim代表要找的钱数,求组成aim的最少货币数。 4 | """ 5 | def minCoinNum_1(arr, aim): 6 | """暴力递归 7 | """ 8 | if arr == None or len(arr) == 0 or aim < 0: 9 | return -1 10 | 11 | return process(arr, len(arr)-1, aim) 12 | 13 | 14 | def process(arr, index, aim): # arr[0 - index] 合成 aim 的最少货币数 15 | if aim < 0 or index < 0: 16 | return float('inf') 17 | 18 | if aim == 0: 19 | return 0 20 | 21 | if index == 0: 22 | return 1 if aim == arr[0] else float('inf') 23 | 24 | tmp = min( 25 | process(arr, index-1, aim), 26 | 1 + process(arr, index-1, aim - arr[index]) 27 | ) 28 | 29 | return tmp 30 | 31 | 32 | def minCoinNum_2(arr, aim): 33 | """动态规划 34 | """ 35 | if arr == None or len(arr) == 0 or aim < 0: 36 | return -1 37 | 38 | row, col = len(arr), aim + 1 39 | 40 | dp = [] 41 | for _ in range(row): 42 | dp.append([0] * col) 43 | 44 | # 第一行初始化 45 | for i in range(1, col): 46 | dp[0][i] = 1 if i == arr[0] else float('inf') 47 | 48 | # 其他位置 49 | for i in range(1, row): 50 | for j in range(1, col): 51 | tmp = dp[i-1][j-arr[i]] + 1 if j - arr[i] >= 0 else float('inf') 52 | dp[i][j] = min(dp[i-1][j], tmp) 53 | 54 | return dp[row-1][col-1] 55 | 56 | 57 | def minCoinNum_3(arr, aim): 58 | """动态规划(空间压缩) 59 | """ 60 | if arr == None or len(arr) == 0 or aim < 0: 61 | return -1 62 | 63 | row, col = len(arr), aim+1 64 | 65 | dp = [float('inf')] * col 66 | dp[0] = 0 67 | if arr[0] <= aim: # 初始化第一行 68 | dp[arr[0]] = 1 69 | 70 | # 其他位置 71 | for i in range(1, row): 72 | dp[0] = 0 73 | for j in list(range(1, col))[::-1]: 74 | tmp = dp[j-arr[i]] + 1 if j-arr[i] >= 0 else float('inf') 75 | dp[j] = min(dp[j], tmp) 76 | 77 | return dp[col-1] 78 | 79 | 80 | if __name__ == '__main__': 81 | arr = [5, 2, 3, 5] 82 | aim = 10 83 | print(minCoinNum_1(arr, aim)) 84 | print(minCoinNum_2(arr, aim)) 85 | print(minCoinNum_3(arr, aim)) -------------------------------------------------------------------------------- /Part6_Recursion_DP/Code7_MinPathSum.py: -------------------------------------------------------------------------------- 1 | """给定一个矩阵m, 从左上角开始每次只能向右或者向下走, 2 | 最终到达右下角位置,路径上所有的数字累加起来就是路径和, 3 | 返回所有的路径中最小的路径和。""" 4 | 5 | def minPathSum_1(matrix): 6 | """暴力递归 7 | """ 8 | if matrix == None: 9 | return None 10 | 11 | return process_1(matrix, 0, 0) 12 | 13 | def process_1(arr, i, j): 14 | if i == len(arr) - 1 and j == len(arr[0]) - 1: 15 | return arr[i][j] 16 | 17 | if i == len(arr) - 1: 18 | return arr[i][j] + process_1(arr, i, j+1) 19 | elif j == len(arr[0]) - 1: 20 | return arr[i][j] + process_1(arr, i+1, j) 21 | else: 22 | return arr[i][j] + min( 23 | process_1(arr, i, j+1), 24 | process_1(arr, i+1, j)) 25 | 26 | 27 | def minPathSum_2(matrix): 28 | """动态规划 (从下往上递推) 29 | 30 | i,j 到 右下角的最小路径和 31 | """ 32 | if matrix == None: 33 | return None 34 | 35 | row = len(matrix) 36 | col = len(matrix[0]) 37 | 38 | bp = [] # 初始化 bp数组 39 | for _ in range(row): 40 | bp.append([0] * col) 41 | 42 | bp[row-1][col-1] = matrix[row-1][col-1] 43 | 44 | # 最后一列赋值 45 | for i in list(range(row-1))[::-1]: 46 | bp[i][col-1] = matrix[i][col-1] + bp[i+1][col-1] 47 | # 最后一行赋值 48 | for j in list(range(col-1))[::-1]: 49 | bp[row-1][j] = matrix[row-1][j] + bp[row-1][j+1] 50 | 51 | #其他位置赋值 52 | for i in list(range(row-1))[::-1]: 53 | for j in list(range(col-1))[::-1]: 54 | bp[i][j] = matrix[i][j] + min(bp[i+1][j], bp[i][j+1]) 55 | 56 | return bp[0][0] 57 | 58 | 59 | def minPathSum_3(matrix): 60 | """动态规划 (从上往下递推) 61 | 62 | 0,0 到 i,j的最小路径和 63 | """ 64 | if matrix == None: 65 | return None 66 | 67 | row = len(matrix) 68 | col = len(matrix[0]) 69 | 70 | bp = [] 71 | for i in range(row): 72 | bp.append([0] * col) 73 | 74 | bp[0][0] = matrix[0][0] 75 | # 第一列赋值 76 | for i in range(1, row): 77 | bp[i][0] = matrix[i][0] + bp[i-1][0] 78 | # 第一行赋值 79 | for j in range(1, col): 80 | bp[0][j] = matrix[0][j] + bp[0][j-1] 81 | 82 | # 其他位置 83 | for i in range(1, row): 84 | for j in range(1, col): 85 | bp[i][j] = matrix[i][j] + min( 86 | bp[i-1][j], 87 | bp[i][j-1]) 88 | 89 | return bp[row-1][col-1] 90 | 91 | def minPathSum_3_plus(matrix): 92 | """动态规划(空间压缩技术) 93 | """ 94 | if matrix == None or len(matrix) == 0 or matrix[0] == None or len(matrix[0]) == 0: 95 | return None 96 | 97 | more = max(len(matrix), len(matrix[0])) # 行列数最大的那个为 more, 小的为less 98 | less = min(len(matrix), len(matrix[0])) 99 | 100 | rowMore = (more == len(matrix)) 101 | bp = [0] * less 102 | bp[0] = matrix[0][0] 103 | for i in range(1, less): 104 | bp[i] = bp[i-1] + ( 105 | matrix[0][i] if rowMore else matrix[i][0] 106 | ) 107 | 108 | for i in range(1, more): 109 | bp[0] += ( 110 | matrix[i][0] if rowMore else matrix[0][i] 111 | ) 112 | 113 | for j in range(1, less): 114 | bp[j] = min(bp[j-1], bp[j]) + ( 115 | matrix[i][j] if rowMore else matrix[j][i] 116 | ) 117 | 118 | return bp[less-1] 119 | 120 | 121 | """ 122 | 注意: 123 | 1. 最终目的是想求最优解的《具体路经》,空间压缩方法是不能用的(这时需要完整的动态规划表) 124 | 2. 最终目的是像求最优解的《值》,则可以使用空间压缩方法! 125 | """ 126 | 127 | 128 | if __name__ == '__main__': 129 | matrix = [ 130 | [1, 3, 5, 9], 131 | [8, 1, 3, 4], 132 | [5, 0, 6, 1], 133 | [8, 8, 4, 0]] 134 | 135 | print(minPathSum_1(matrix)) 136 | print(minPathSum_2(matrix)) 137 | print(minPathSum_3(matrix)) 138 | print(minPathSum_3_plus(matrix)) -------------------------------------------------------------------------------- /Part6_Recursion_DP/Code7_r_Factorial.py: -------------------------------------------------------------------------------- 1 | def factorial(n): 2 | """递归求阶乘 3 | """ 4 | if n == 1: 5 | return n 6 | 7 | return n * factorial(n-1) 8 | 9 | 10 | def factorial1(n): 11 | """非递归 12 | """ 13 | result = 1 14 | for i in range(1, n+1): 15 | result *= i 16 | 17 | return result 18 | 19 | if __name__ == '__main__': 20 | n = 6 21 | print(factorial(n)) 22 | print(factorial1(n)) 23 | 24 | -------------------------------------------------------------------------------- /Part6_Recursion_DP/Code7_r_Hanio.py: -------------------------------------------------------------------------------- 1 | """汉诺塔问题""" 2 | def hanio(n): 3 | if n > 0: 4 | process(n, 'left', 'mid', 'right') 5 | 6 | def process(n, start, help1, end): 7 | if n == 1: 8 | print("%d from %s to %s"%(n, start, end)) 9 | return None 10 | 11 | process(n-1, start, end, help1) 12 | print("%d from %s to %s"%(n, start, end)) 13 | process(n-1, help1, start, end) 14 | 15 | if __name__ == '__main__': 16 | n = 5 17 | hanio(n) 18 | -------------------------------------------------------------------------------- /Part6_Recursion_DP/Code7_r_PrintAllPermutation.py: -------------------------------------------------------------------------------- 1 | """全排列问题 """ 2 | def printAllPermutation_1(string): 3 | if string == None: 4 | return None 5 | 6 | arr = list(map(lambda i: i, string)) 7 | process_1(arr, 0) 8 | 9 | 10 | def process_1(arr, index): 11 | if index == len(arr): 12 | print("".join(arr)) 13 | return None 14 | 15 | for i in range(index, len(arr)): 16 | arr[i], arr[index] = arr[index], arr[i] 17 | process_1(arr, index + 1) 18 | arr[i], arr[index] = arr[index], arr[i] 19 | 20 | 21 | 22 | def printAllPermutation_2(string): 23 | """去重 24 | """ 25 | if string == None: 26 | return None 27 | 28 | arr = list(map(lambda i:i, string)) 29 | process_2(arr, 0) 30 | 31 | 32 | def process_2(arr, index): 33 | if index == len(arr): 34 | print("".join(arr)) 35 | return None 36 | 37 | hset = set() 38 | for i in range(index, len(arr)): 39 | if arr[i] not in hset: 40 | hset.add(arr[i]) 41 | 42 | arr[i], arr[index] = arr[index], arr[i] 43 | process_2(arr, index+1) 44 | arr[i], arr[index] = arr[index], arr[i] 45 | 46 | 47 | 48 | if __name__ == '__main__': 49 | string = 'abc' 50 | printAllPermutation_1(string) 51 | print("#########") 52 | printAllPermutation_2(string) 53 | 54 | print() 55 | print('--------------') 56 | print() 57 | 58 | 59 | string = 'acc' 60 | printAllPermutation_1(string) 61 | print("#########") 62 | printAllPermutation_2(string) -------------------------------------------------------------------------------- /Part6_Recursion_DP/Code7_r_PrintAllSubSequence.py: -------------------------------------------------------------------------------- 1 | """打印一个字符串所有子序列(不改变次序)""" 2 | 3 | def printAllSubSequence(string): 4 | if string == None: 5 | return None 6 | 7 | process(string, 0, "") 8 | 9 | 10 | def process(string, index, pre): 11 | if index == len(string): 12 | if pre != "": 13 | print(pre) 14 | return None 15 | 16 | process(string, index + 1, pre + string[index]) 17 | process(string, index + 1, pre) 18 | 19 | 20 | if __name__ == '__main__': 21 | 22 | string = '123' 23 | printAllSubSequence(string) -------------------------------------------------------------------------------- /Part6_Recursion_DP/Code7_r_reverseStack.py: -------------------------------------------------------------------------------- 1 | """给你一个栈,请你逆序这个栈,不能申请额外的数据结构,只能使用递归函数。如何实现?""" 2 | 3 | def reverseStack(stack): 4 | """栈的逆序 5 | """ 6 | if len(stack) == 0: # 栈空了 7 | return None 8 | 9 | i = findAndPopStackLow(stack) 10 | reverseStack(stack) 11 | stack.append(i) # 压栈 12 | 13 | def findAndPopStackLow(stack): 14 | """找到并弹出栈中最后一个元素 15 | """ 16 | i = stack.pop(-1) 17 | if len(stack) == 0: 18 | return i 19 | 20 | res = findAndPopStackLow(stack) 21 | stack.append(i) 22 | return res 23 | 24 | 25 | if __name__ == '__main__': 26 | stack = [1, 2, 3, 4, 5, 6] 27 | reverseStack(stack) 28 | print(stack) 29 | -------------------------------------------------------------------------------- /Part6_Recursion_DP/Code8_MinDistance.py: -------------------------------------------------------------------------------- 1 | """一条直线上有居民点,邮局只能建在居民点上。给定一个有序数组arr,每个值表示居民点的一维坐标, 2 | 在给定一个整数num,表示邮局的数量。选择num个居民点建立num个邮局,使所有的居民点到邮局的总距离最短 3 | ,返回最短距离。 4 | 5 | 例:arr=[1, 2, 3, 4, 5, 1000], num = 2 6 | 邮局建在3, 1000上, 最短距离6 7 | """ 8 | def minDistance(arr, num): 9 | """ 动态规划 P509 10 | """ 11 | if arr == None or len(arr) == 0 or num < 1 or len(arr) < num: 12 | return 0 13 | 14 | w = [] 15 | for _ in range(len(arr)+1): w.append([0] * (len(arr)+1)) 16 | 17 | for i in range(len(arr)): 18 | for j in range(i+1, len(arr)): 19 | w[i][j] = w[i][j-1] + arr[j] - arr[(i+j)//2] 20 | 21 | dp = [] 22 | for _ in range(num): dp.append([0] * len(arr)) 23 | 24 | for j in range(1, len(arr)): 25 | dp[0][j] = w[0][j] 26 | 27 | for i in range(1, num): 28 | for j in range(i+1, len(arr)): 29 | dp[i][j] = float('inf') 30 | for k in range(j+1): 31 | dp[i][j] = min( 32 | dp[i][j], 33 | dp[i-1][k] + w[k+1][j] 34 | ) 35 | 36 | return dp[num-1][len(arr)-1] 37 | 38 | 39 | 40 | if __name__ == '__main__': 41 | arr = [1, 2, 3, 4, 5, 1000] # 6 42 | num = 2 43 | print(minDistance(arr, num)) -------------------------------------------------------------------------------- /Part7_StringQuestion/Code8_IsDeformation.py: -------------------------------------------------------------------------------- 1 | """给定两个字符串str1和str2,判断两个字符串是否互为变形词 2 | 3 | 变形词: 字符种类一样,字符出现的次数也一样 4 | """ 5 | def isDeformation(str1, str2): 6 | 7 | if str1 == None or str2 == None or len(str1) != len(str2): 8 | return False 9 | 10 | # 假设出现的字符编码值在0-255之间 11 | helpArr = [0] * 256 12 | for i in str1: 13 | helpArr[ord(i)] += 1 14 | 15 | for i in str2: 16 | helpArr[ord(i)] -= 1 17 | if helpArr[ord(i)] < 0: # 18 | return False 19 | 20 | return True 21 | 22 | 23 | if __name__ == '__main__': 24 | str1 = '123' 25 | str2 = '231' 26 | print(isDeformation(str1, str2)) 27 | 28 | str1 = '123' 29 | str2 = '238' 30 | print(isDeformation(str1, str2)) -------------------------------------------------------------------------------- /Part7_StringQuestion/Code8_IsRatation.py: -------------------------------------------------------------------------------- 1 | """判断两个字符串是否互为旋转词""" 2 | 3 | def isRatation(a, b): 4 | if a == None or b == None or len(a) != len(b): 5 | return False 6 | 7 | a2 = a + a 8 | return getIndexOf(a2, b) != -1 9 | 10 | 11 | def getIndexOf(str1, match): 12 | """KMP算法 13 | """ 14 | nextArr = getNextArr(match) 15 | 16 | i1, i2 = 0, 0 17 | while i1 < len(str1) and i2 < len(match): 18 | if str1[i1] == match[i2]: 19 | i1 += 1; i2 += 1 20 | elif nextArr[i2] == -1: 21 | i1 += 1 22 | else: 23 | i2 = nextArr[i2] 24 | 25 | return i1 - len(match) if i2 == len(match) else -1 26 | 27 | 28 | 29 | def getNextArr(match): 30 | """得到next数组 31 | """ 32 | if len(match) == 1: 33 | return [-1] 34 | 35 | nextArr = [-1, 0] 36 | cn = 0 # cn 表示前一个字符最长匹配前缀的下一个字符位置 37 | while len(nextArr) < len(match): 38 | if match[len(nextArr)-1] == match[cn]: 39 | cn += 1 40 | nextArr.append(cn) 41 | 42 | elif cn > 0: 43 | cn = nexArr[cn] 44 | 45 | else: 46 | nextArr.append(0) 47 | 48 | return nextArr 49 | 50 | 51 | if __name__ == '__main__': 52 | a, b = 'cdab', 'abcd' # true 53 | print(isRatation(a, b)) 54 | print('-----') 55 | 56 | a, b = '1ab2', 'ab12' # false 57 | print(isRatation(a, b)) 58 | print('-----') 59 | 60 | a, b = '2ab1', 'ab12' # true 61 | print(isRatation(a, b)) 62 | print('-----') -------------------------------------------------------------------------------- /Part7_StringQuestion/Code8_rotateWord.py: -------------------------------------------------------------------------------- 1 | """给定一个字符串,请在单词之间做逆序调整""" 2 | def reverseWord(str1): 3 | if str1 == None or len(str1) == 0: 4 | return None 5 | 6 | arr = list(str1) 7 | reverse(arr, 0, len(arr) - 1) 8 | 9 | l, r = -1, -1 10 | for i in range(len(arr)): 11 | if arr[i] != ' ': 12 | l = i if i == 0 or arr[i-1] == ' ' else l 13 | r = i if i == len(arr) - 1 or arr[i+1] == ' ' else r 14 | 15 | if l != -1 and r != -1: 16 | reverse(arr, l, r) 17 | l, r = -1, -1 18 | 19 | return arr 20 | 21 | 22 | def reverse(arr, l, r): 23 | """数组反转 24 | """ 25 | while l <= r: 26 | arr[l], arr[r] = arr[r], arr[l] 27 | l += 1 28 | r -= 1 29 | 30 | 31 | 32 | if __name__ == '__main__': 33 | str1 = "I am a student" # -> student a am I 34 | print("%s\n\t-> %s"%( 35 | str1, 36 | ''.join(reverseWord(str1)) 37 | ) 38 | ) -------------------------------------------------------------------------------- /Part7_StringQuestion/maxUnique.py: -------------------------------------------------------------------------------- 1 | """最长无重复子串的长度""" 2 | 3 | def maxUnique(string): 4 | 5 | if string == None or string == "": 6 | return 0 7 | 8 | arr = list(string) 9 | hMap = [-1] * 256 # 字符编码范围 10 | 11 | maxLen = 0 12 | pre = -1 13 | for i in range(len(arr)): 14 | pre = max( 15 | pre, 16 | hMap[ord(arr[i])] 17 | ) 18 | 19 | maxLen = max( 20 | maxLen, 21 | i - pre 22 | ) 23 | 24 | hMap[ord(arr[i])] = i 25 | 26 | return maxLen 27 | 28 | string = "aabcb" 29 | print(maxUnique(string)) 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 数据结构与算法 之 python实现 2 | --- 3 | ## 基础篇 4 | ### 1. 基本排序算法 5 | * [冒泡排序](https://github.com/lianyingteng/algorithm_practice/blob/master/Part0_Sort/Code1_BubbleSort.py "Code1_BubbleSort.py") 6 | * [选择排序](https://github.com/lianyingteng/algorithm_practice/blob/master/Part0_Sort/Code1_SelectionSort.py "Code1_SelectionSort.py") 7 | * [插入排序](https://github.com/lianyingteng/algorithm_practice/blob/master/Part0_Sort/Code1_InsertionSort.py "Code1_InsertionSort.py") 8 | * [随机快排](https://github.com/lianyingteng/algorithm_practice/blob/master/Part0_Sort/Code1_QuickSort.py "Code1_QuickSort.py") 9 | * [归并排序](https://github.com/lianyingteng/algorithm_practice/blob/master/Part0_Sort/Code1_MergeSort.py "Code1_MergeSort.py") 10 | * [堆排序](https://github.com/lianyingteng/algorithm_practice/blob/master/Part0_Sort/Code1_HeapSort.py "Code1_HeapSort.py") 11 | * [桶排序](https://github.com/lianyingteng/algorithm_practice/blob/master/Part0_Sort/Code1_BucketSort.py "Code1_BucketSort.py") 12 | 13 | #### 应用 14 | * [最大间隔问题](https://github.com/lianyingteng/algorithm_practice/blob/master/Part0_Sort/Code11_MaxGap.py) 求无序数组排序之后 相邻两数的最大差值?`【桶排序思想的应用】 ` 15 | * [小和问题](https://github.com/lianyingteng/algorithm_practice/blob/master/Part0_Sort/Code11_MinSum.py) 给定一个数组,计算所有小和`【归并排序思想的应用】` 16 | * [**荷兰国旗问题**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part0_Sort/Code11_NetherlandsFlag.py) 小于的放在左边、等于的放在中间、大于的放在右边`【快排划分的应用】` 17 | * [**查找无序数组前k个最小的数**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part0_Sort/Code11_heapSort.py) 该程序基于堆排序思想,建立大小为k的大根堆。`注: 该问题的最优解是下节中的BFPRT算法` 18 | 19 | ### 2. KMP、Manacher、BFPRT 20 | * [**KMP算法**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part0_Sort/Code2_KMP.py) `解决字符串匹配问题` 21 | * [**Manacher算法**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part0_Sort/Code2_Manacher.py) `解决最长回文子串问题` 22 | * [**BFPRT算法**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part0_Sort/Code2_BFPRT.py) `查找无序数组中第k小的数` 23 | #### 应用 24 | * [最短扩增序列(包含两个输入序列)](https://github.com/lianyingteng/algorithm_practice/blob/master/Part0_Sort/Code21_KMP_ShortestHaveTwice.py) `【基于KMP的next数组构建】` 25 | 26 | ### 3. 数据结构 27 | 28 | **数组结构**
29 | 30 | * [使用数组实现栈结构](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code3_Array_To_Stack.py) 31 | * [使用数组实现队列结构](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code3_Array_To_Queue.py) 32 | * [实现可以输出栈中最小值的栈结构](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code3_GetMinStack.py) 33 | * [两个栈实现队列结构](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code3_Stack_To_Queue.py) 34 | * [**两个队列实现栈结构**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code3_Queue_To_Stack.py) 35 | * [**猫狗队列**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code3_CatDogQueue.py) 36 | * [**设计RandomPool结构**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code3_RandomPool.py) 37 | * [转圈打印矩阵](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code3_spiralOrderPrintMatrix.py) 38 | * [螺旋填数](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/helixWriteNumber.py) 39 | * [Z字形打印矩阵](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code3_ZigZagPrintMatrix.py) 40 | * [行列排好序的矩阵中找数](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code3_FindNumInSortedMatrix.py) 41 | * [岛屿问题](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code4_IsLands.py) 42 | * [**找到无序数组局部最小位置**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code4_findLessValueIndex.py) `二分也可用于数组无序的情况` 43 | * [找到有序数组中第一个大于或等于k的数](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code4_BinarySearch.py) `二分` 44 | * [子数组的最大累加和](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code8_MaxSumOfSubArray.py) 45 | * [子矩阵的最大累加和](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code8_MaxSumOfSubMatrix.py) 46 | * [最大的leftMax与rightMax之差的绝对值](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code8_MaxABS.py) 47 | * [无序数组中3数相乘的最大值](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/maxMulValue.py) 48 | 49 | **链表结构**
50 | 51 | * [打印两个有序链表的公共部分](https://github.com/lianyingteng/algorithm_practice/blob/master/Part2_LinkedList/Code3_PrintCommonPart.py) `注: Node类中, value和next依附于实例` 52 | * [链表是回文结构?](https://github.com/lianyingteng/algorithm_practice/blob/master/Part2_LinkedList/Code3_LinkedListIsPalindrome.py) 53 | * [**链表的Partition过程**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part2_LinkedList/Code3_SmallerEqualBigger.py) 54 | * [复制含有随机指针节点的链表](https://github.com/lianyingteng/algorithm_practice/blob/master/Part2_LinkedList/Code3_CopyListWithRandom.py) 55 | * [**寻找两个单链表第一个相交的结点**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part2_LinkedList/Code3_FindFirstIntersectNode.py) 56 | * [反转单(双)向链表](https://github.com/lianyingteng/algorithm_practice/blob/master/Part2_LinkedList/Code3_ReverseList.py) 57 | 58 | 59 | 60 | **树结构**
61 | 62 | * [折纸问题](https://github.com/lianyingteng/algorithm_practice/blob/master/Part3_Tree/Code4_PaperFolding.py) 63 | * [**二叉树的先序、中序、后序遍历**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part3_Tree/Code4_PreInPosRecur.py) `重点是非递归实现` 64 | * [较为直观打印二叉树](https://github.com/lianyingteng/algorithm_practice/blob/master/Part3_Tree/Code4_PrintTree.py) 65 | * [在二叉树中找到一个节点的后继节点](https://github.com/lianyingteng/algorithm_practice/blob/master/Part3_Tree/Code4_GetNextNode.py) 66 | * [**前缀树**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part3_Tree/Code5_TrieTree.py) `处理字符串常用的数据结构` 67 | * [**Morris遍历**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part3_Tree/Code8_Morris.py) `遍历二叉树的神级方法` 68 | * [跳表结构](https://github.com/lianyingteng/algorithm_practice/blob/master/Part3_Tree/Code9_SkipList.py) 69 | * [找到二叉树中的最大搜索二叉子树](https://github.com/lianyingteng/algorithm_practice/blob/master/Part3_Tree/Code9_FindMaxBST.py) `后序遍历的改写` 70 | * [**找到二叉树中符合搜索二叉树条件的最大拓扑结构**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part3_Tree/Code9_BSTMaxTopoSize.py) `后序遍历的改写` 71 | * [判断一颗二叉树是否是平衡二叉树](https://github.com/lianyingteng/algorithm_practice/blob/master/Part3_Tree/Code9_IsBalance.py) `后序遍历的改写` 72 | * [在二叉树中找到两个节点的最近公共祖先](https://github.com/lianyingteng/algorithm_practice/blob/master/Part3_Tree/lowestAncestor.py) 73 | 74 | 75 | 76 | **堆结构**
77 | 78 | * [**随时找到数据流的中位数**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part4_HeapStructure/Code4_MedianHolder.py) `P462` 79 | * [切金条问题:**最小分割代价**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part4_HeapStructure/Code4_LessMoney.py) 80 | * [**如何使得项目获得收益最大化**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part4_HeapStructure/Code4_IPO.py) `涉及python的类的继承` 81 | 82 | 83 | 84 | **图结构**
85 | 86 | * [图的定义](https://github.com/lianyingteng/algorithm_practice/blob/master/Part5_Graph/Code5_DefineGraph.py) 87 | * [图的宽度优先遍历](https://github.com/lianyingteng/algorithm_practice/blob/master/Part5_Graph/Code5_BFS.py) 88 | * [图的深度优先遍历](https://github.com/lianyingteng/algorithm_practice/blob/master/Part5_Graph/Code5_DFS.py) 89 | * [拓扑排序算法](https://github.com/lianyingteng/algorithm_practice/blob/master/Part5_Graph/Code5_TopologySort.py) 90 | * [最小生成树 - Kruskal算法](https://github.com/lianyingteng/algorithm_practice/blob/master/Part5_Graph/Code5_Kruskal.py) `加边法` 91 | * [最小生成树 - Prim算法](https://github.com/lianyingteng/algorithm_practice/blob/master/Part5_Graph/Code5_Prim.py) `加点法` 92 | * [求单源最短路径 - Dijkstra算法](https://github.com/lianyingteng/algorithm_practice/blob/master/Part5_Graph/Code5_Dijkstra.py) 93 | 94 | 95 | **其他重要知识**
96 | 97 | * [**并查集结构**](https://github.com/lianyingteng/algorithm_practice/blob/master/Code4_UnionFindSet.py) 98 | * [**窗口最大值和最小值的更新结构**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code8_SlidingWindowMaxArray.py) 99 | * [最大值减去最小值小于或等于num的子数组数量](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code8_SubArrayNumber.py) 100 | 101 | * [构建数组的MaxTree](https://github.com/lianyingteng/algorithm_practice/blob/master/Part3_Tree/Code8_MaxTreeOfArray.py) 102 | * [**最大子矩阵的的大小**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code8_MaxRecSize.py) 103 | * [**蓄水池算法**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part1_Array/Code8_GetKNumsRand.py) 104 | * [位运算-快速N次方](https://github.com/lianyingteng/algorithm_practice/blob/master/getPower.py) 105 | 106 | 107 | **字符串问题**
108 | 109 | * [判断两个字符串是否互为变形词](https://github.com/lianyingteng/algorithm_practice/blob/master/Part7_StringQuestion/Code8_IsDeformation.py) 110 | * [判断两个字符串是否互为旋转词](https://github.com/lianyingteng/algorithm_practice/blob/master/Part7_StringQuestion/Code8_IsRatation.py) 111 | * [**反转字符串**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part7_StringQuestion/Code8_rotateWord.py) 112 | * [**最长无重复子串的长度**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part7_StringQuestion/maxUnique.py) 113 | 114 | ### 4. 算法基础 115 | 116 | **递归**
117 | 118 | `函数的递归过程是函数自己调用自己的过程。 基本思想:把一个规模大的问题,转化成若干个规模小的子问题,并且大问题和其子问题的解决策略是一致的(同一种方法)。 递归函数必须有明确的结束条件!` 119 | 120 | * [求阶乘](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_r_Factorial.py) 121 | * [汉诺塔问题](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_r_Hanio.py) 122 | * [**打印一个字符串所有子序列**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_r_PrintAllSubSequence.py) 123 | * [**全排列**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_r_PrintAllPermutation.py) 124 | * [斐波那契系列问题](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_Fibonacci.py) 125 | * [最小路径和](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_MinPathSum.py) 126 | 127 | * **换钱问题** 128 | * [**换钱的最少货币数1**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_MinCoinNum.py) 129 | * [**换钱的最少货币数2**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_MinCoinNum_2.py) 130 | * [**换钱的方法数**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_CoinMethodNum.py) 131 | 132 | * [**完全背包问题**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_Knapsack.py) 133 | * [**用递归函数逆序栈**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_r_reverseStack.py) 134 | 135 | **动态规划**
136 | 137 | `动态规划是一种分阶段求解决策问题的数学思想。 三个重要的概念: 最优子结构、 边界、 状态转移公式。 动态规划利用自底向上的递推方式,实现时间和空间上的额最优化。` 138 | 139 | * [斐波那契系列问题](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_Fibonacci.py) 140 | * [**最小路径和**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_MinPathSum.py) 141 | 142 | * **换钱问题** 143 | * [**换钱的最少货币数1**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_MinCoinNum.py) 144 | * [**换钱的最少货币数2**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_MinCoinNum_2.py) 145 | * [**换钱的方法数**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_CoinMethodNum.py) 146 | 147 | * [**完全背包问题**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code7_Knapsack.py) 148 | * [**邮局选址问题**](https://github.com/lianyingteng/algorithm_practice/blob/master/Part6_Recursion_DP/Code8_MinDistance.py) 149 | -------------------------------------------------------------------------------- /getPower.py: -------------------------------------------------------------------------------- 1 | def getResult(k, N): # k ** N 2 | 3 | res = 1 4 | tmp = k 5 | 6 | while N > 0: 7 | if (N & 1) != 0: 8 | res = res * tmp 9 | N >>= 1 10 | 11 | tmp = tmp * tmp 12 | 13 | return res 14 | 15 | k = 5 16 | N = 7 17 | print(getResult(k, N)) 18 | print(k ** N) 19 | --------------------------------------------------------------------------------