├── 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 |
--------------------------------------------------------------------------------