├── Coding Interviews ├── 11_Power │ ├── Power.cpp │ ├── Power.py │ └── README.md ├── InterviewQuestions.rar ├── 09_Fibonacci │ ├── Fibonacci.cpp │ ├── Fibonacci.py │ ├── Fibonacci.md │ └── README.md ├── 21_MinInStack │ ├── MinInStack.cpp │ ├── MinInStack.py │ └── README.md ├── 46_Accumulate │ ├── Accumulate.cpp │ ├── Accumulate.py │ └── README.md ├── 04_ReplaceBlank │ ├── ReplaceBlank.cpp │ ├── ReplaceBlank.py │ └── README.md ├── 14_ReorderArray │ ├── ReorderArray.cpp │ ├── ReorderArray.py │ └── README.md ├── 16_ReverseList │ ├── ReverseList.cpp │ ├── ReverseList.png │ ├── ReverseList.py │ └── README.md ├── 20_PrintMatrix │ ├── PrintMatrix.cpp │ ├── PrintMatrix.png │ ├── PrintMatrix.py │ └── README.md ├── 24_SquenceOfBST │ ├── SquenceOfBST.cpp │ ├── BinarySearchTree.md │ ├── README.md │ └── SquenceOfBST.py ├── 15_KthNodeFromEnd │ ├── KthNodeFromEnd.cpp │ ├── KthNodeFromEnd.py │ └── README.md ├── 10_NumberOf1InBinary │ ├── NumberOf1InBinary.cpp │ ├── NumberOf1InBinary.py │ └── README.md ├── 17_MergeSortedLists │ ├── MergeSortedLists.cpp │ ├── MergeSortedLists.py │ └── README.md ├── 22_StackPushPopOrder │ ├── StackPushPopOrder.cpp │ ├── StackPushPopOrder.py │ └── README.md ├── 07_QueueWithTwoStacks │ ├── QueueWithTwoStacks.cpp │ ├── QueueWithTwoStacks.py │ ├── README.md │ └── QueueStack.md ├── 18_SubstructureInTree │ ├── SubstructureInTree.cpp │ ├── SubstructureInTree.py │ └── README.md ├── 19_MirrorOfBinaryTree │ ├── MirrorOfBinaryTree.cpp │ ├── MirrorOfBinaryTree.png │ ├── MirrorOfBinaryTree.py │ └── README.md ├── 06_ConstructBinaryTree │ ├── ConstructBinaryTree.cpp │ ├── ConstructBinaryTree.py │ ├── README.md │ └── Binarytree.md ├── 08_MinNumberInRotatedArray │ ├── MinNumberInRotatedArray.cpp │ ├── MinNumberInRotatedArray.py │ └── README.md ├── 23_PrintTreeFromTopToBottom │ ├── PrintTreeFromTopToBottom.cpp │ ├── PrintTreeFromTopToBottom.py │ └── README.md ├── 03_FindInPartiallySortedMatrix │ ├── FindInPartiallySortedMatrix.cpp │ ├── FindInPartiallySortedMatrix.png │ ├── FindInPartiallySortedMatrix.py │ └── README.md ├── 05_PrintListInReversedOrder │ ├── PrintListlnReversedOrder.cpp │ ├── PrintListlnReversedOrder.py │ ├── README.md │ └── Linkedlist.md └── README.md ├── Data Structures and Algorithms ├── sort │ ├── images │ │ ├── heap.png │ │ ├── heap2.png │ │ ├── heap_p1.png │ │ ├── heap_p2.png │ │ ├── heap_p3.png │ │ ├── heap_p4.png │ │ ├── heap_p5.png │ │ ├── heap_p6.png │ │ ├── heap_p7.png │ │ ├── heap_p8.png │ │ ├── heap_sort.gif │ │ ├── quick_sort.gif │ │ ├── quick_sort.png │ │ ├── bubble_sort.gif │ │ ├── bubble_sort_1.jpg │ │ ├── shell_sort01.gif │ │ ├── shell_sort02.png │ │ ├── shell_sort03.jpg │ │ ├── insertion_sort.gif │ │ ├── insertion_sort.png │ │ ├── selection_sort.gif │ │ ├── sort_algorithms_1.png │ │ └── sort_algorithms_2.png │ ├── code │ │ ├── quick_sort.cpp │ │ ├── shell_sort.cpp │ │ ├── bubble_sort.cpp │ │ ├── insertion_sort.cpp │ │ ├── selection_sort.cpp │ │ ├── bubble_sort.py │ │ ├── selection_sort.py │ │ ├── shell_sort.py │ │ ├── insertion_sort.py │ │ └── quick_sort.py │ ├── quick_sort.py │ └── README.md ├── README.md └── search │ ├── binary_search.py │ └── README.md ├── README.md └── LeetCode ├── code ├── 0026_RemoveDuplicatesFromSortedArray.py ├── 0001_TwoSum.cpp ├── 0026_RemoveDuplicatesFromSortedArray.cpp ├── 0001_TwoSum.py └── 0004_.MedianofTwoSortedArrays.cpp └── README.md /Coding Interviews/11_Power/Power.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/11_Power/Power.cpp -------------------------------------------------------------------------------- /Coding Interviews/InterviewQuestions.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/InterviewQuestions.rar -------------------------------------------------------------------------------- /Coding Interviews/09_Fibonacci/Fibonacci.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/09_Fibonacci/Fibonacci.cpp -------------------------------------------------------------------------------- /Coding Interviews/21_MinInStack/MinInStack.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/21_MinInStack/MinInStack.cpp -------------------------------------------------------------------------------- /Coding Interviews/46_Accumulate/Accumulate.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/46_Accumulate/Accumulate.cpp -------------------------------------------------------------------------------- /Coding Interviews/04_ReplaceBlank/ReplaceBlank.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/04_ReplaceBlank/ReplaceBlank.cpp -------------------------------------------------------------------------------- /Coding Interviews/14_ReorderArray/ReorderArray.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/14_ReorderArray/ReorderArray.cpp -------------------------------------------------------------------------------- /Coding Interviews/16_ReverseList/ReverseList.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/16_ReverseList/ReverseList.cpp -------------------------------------------------------------------------------- /Coding Interviews/16_ReverseList/ReverseList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/16_ReverseList/ReverseList.png -------------------------------------------------------------------------------- /Coding Interviews/20_PrintMatrix/PrintMatrix.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/20_PrintMatrix/PrintMatrix.cpp -------------------------------------------------------------------------------- /Coding Interviews/20_PrintMatrix/PrintMatrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/20_PrintMatrix/PrintMatrix.png -------------------------------------------------------------------------------- /Coding Interviews/24_SquenceOfBST/SquenceOfBST.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/24_SquenceOfBST/SquenceOfBST.cpp -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/heap.png -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/heap2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/heap2.png -------------------------------------------------------------------------------- /Coding Interviews/15_KthNodeFromEnd/KthNodeFromEnd.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/15_KthNodeFromEnd/KthNodeFromEnd.cpp -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/code/quick_sort.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/code/quick_sort.cpp -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/code/shell_sort.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/code/shell_sort.cpp -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/heap_p1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/heap_p1.png -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/heap_p2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/heap_p2.png -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/heap_p3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/heap_p3.png -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/heap_p4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/heap_p4.png -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/heap_p5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/heap_p5.png -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/heap_p6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/heap_p6.png -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/heap_p7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/heap_p7.png -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/heap_p8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/heap_p8.png -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/code/bubble_sort.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/code/bubble_sort.cpp -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/heap_sort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/heap_sort.gif -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/quick_sort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/quick_sort.gif -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/quick_sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/quick_sort.png -------------------------------------------------------------------------------- /Coding Interviews/10_NumberOf1InBinary/NumberOf1InBinary.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/10_NumberOf1InBinary/NumberOf1InBinary.cpp -------------------------------------------------------------------------------- /Coding Interviews/17_MergeSortedLists/MergeSortedLists.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/17_MergeSortedLists/MergeSortedLists.cpp -------------------------------------------------------------------------------- /Coding Interviews/22_StackPushPopOrder/StackPushPopOrder.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/22_StackPushPopOrder/StackPushPopOrder.cpp -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/code/insertion_sort.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/code/insertion_sort.cpp -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/code/selection_sort.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/code/selection_sort.cpp -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/bubble_sort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/bubble_sort.gif -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/bubble_sort_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/bubble_sort_1.jpg -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/shell_sort01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/shell_sort01.gif -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/shell_sort02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/shell_sort02.png -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/shell_sort03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/shell_sort03.jpg -------------------------------------------------------------------------------- /Coding Interviews/07_QueueWithTwoStacks/QueueWithTwoStacks.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/07_QueueWithTwoStacks/QueueWithTwoStacks.cpp -------------------------------------------------------------------------------- /Coding Interviews/18_SubstructureInTree/SubstructureInTree.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/18_SubstructureInTree/SubstructureInTree.cpp -------------------------------------------------------------------------------- /Coding Interviews/19_MirrorOfBinaryTree/MirrorOfBinaryTree.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/19_MirrorOfBinaryTree/MirrorOfBinaryTree.cpp -------------------------------------------------------------------------------- /Coding Interviews/19_MirrorOfBinaryTree/MirrorOfBinaryTree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/19_MirrorOfBinaryTree/MirrorOfBinaryTree.png -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/insertion_sort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/insertion_sort.gif -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/insertion_sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/insertion_sort.png -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/selection_sort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/selection_sort.gif -------------------------------------------------------------------------------- /Coding Interviews/06_ConstructBinaryTree/ConstructBinaryTree.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/06_ConstructBinaryTree/ConstructBinaryTree.cpp -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/sort_algorithms_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/sort_algorithms_1.png -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/images/sort_algorithms_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Data Structures and Algorithms/sort/images/sort_algorithms_2.png -------------------------------------------------------------------------------- /Coding Interviews/08_MinNumberInRotatedArray/MinNumberInRotatedArray.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/08_MinNumberInRotatedArray/MinNumberInRotatedArray.cpp -------------------------------------------------------------------------------- /Coding Interviews/23_PrintTreeFromTopToBottom/PrintTreeFromTopToBottom.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/23_PrintTreeFromTopToBottom/PrintTreeFromTopToBottom.cpp -------------------------------------------------------------------------------- /Coding Interviews/03_FindInPartiallySortedMatrix/FindInPartiallySortedMatrix.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/03_FindInPartiallySortedMatrix/FindInPartiallySortedMatrix.cpp -------------------------------------------------------------------------------- /Coding Interviews/03_FindInPartiallySortedMatrix/FindInPartiallySortedMatrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amusi/coding-note/HEAD/Coding Interviews/03_FindInPartiallySortedMatrix/FindInPartiallySortedMatrix.png -------------------------------------------------------------------------------- /Coding Interviews/14_ReorderArray/ReorderArray.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-06-20 5 | 6 | 题目描述 7 | 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对顺序不变。 8 | 9 | 10 | ''' 11 | 12 | -------------------------------------------------------------------------------- /Coding Interviews/24_SquenceOfBST/BinarySearchTree.md: -------------------------------------------------------------------------------- 1 | # 数据结构—二叉搜索树 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | # 参考 10 | 11 | [百度百科:二叉搜索树](https://baike.baidu.com/item/%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91/7077855) 12 | 13 | [二叉搜索树详解及实现代码(BST)](https://blog.csdn.net/a1414345/article/details/70186719) 14 | 15 | -------------------------------------------------------------------------------- /Coding Interviews/46_Accumulate/Accumulate.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-09-06 5 | 6 | 题目描述 7 | 求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。 8 | 9 | ''' 10 | 11 | # -*- coding:utf-8 -*- 12 | class Solution: 13 | def Sum_Solution(self, n): 14 | # write code here 15 | # 短路法 16 | ans = n 17 | temp = ans and self.Sum_Solution(n-1) 18 | ans += temp 19 | return ans -------------------------------------------------------------------------------- /Data Structures and Algorithms/README.md: -------------------------------------------------------------------------------- 1 | # 数据结构与算法 2 | 3 | [排序算法](sort) 4 | 5 | [查找算法](search) 6 | 7 | 8 | 9 | 10 | # 参考 11 | 12 | **(在学中**)[algorithms](https://github.com/xtaci/algorithms): Algorithms & Data structures in C++ 13 | 14 | **(在学中**)[python_data_structures_and_algorithms](https://github.com/PegasusWang/python_data_structures_and_algorithms): Algorithms & Data structures in Python 15 | 16 | [数据结构和算法可视化(Chinese)](https://visualgo.net/zh) 17 | 18 | [DATA STRUCTURES](http://btechsmartclass.com/DS/U1_T1.html) -------------------------------------------------------------------------------- /Coding Interviews/24_SquenceOfBST/README.md: -------------------------------------------------------------------------------- 1 | # 二叉搜索树的后序遍历序列 2 | 3 | # 题目描述 4 | 5 | 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。 6 | 7 | # 解题思路 8 | 9 | 考查知识点: 10 | 11 | - [二叉搜索树BST](BinarySearchTree.md) 12 | 13 | 14 | 15 | # 代码 16 | 17 | [C++](SquenceOfBST.cpp) 递归法 18 | 19 | ```c++ 20 | 21 | ``` 22 | 23 | [Python](SquenceOfBST.py) 24 | 25 | ```python 26 | 27 | ``` 28 | 29 | # 参考 30 | 31 | https://www.nowcoder.com/questionTerminal/a861533d45854474ac791d90e447bafd 32 | 33 | https://blog.csdn.net/lzuacm/article/details/51317617 -------------------------------------------------------------------------------- /Data Structures and Algorithms/search/binary_search.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def BinarySearch(arr, key): 4 | left = 0 5 | right = len(arr)-1 6 | 7 | while left <= right: 8 | mid = math.ceil((left+right)/2) 9 | if arr[mid] == key: 10 | return 1 11 | elif arr[mid]39) or (n<0): 18 | return 0 19 | if(n==1 or n==2): 20 | return 1 21 | fn_2 = 1 22 | fn_1 = 1 23 | fn = 0 24 | i = 3 25 | while(i<=n): 26 | fn = fn_2 + fn_1 27 | fn_2 = fn_1 28 | fn_1 = fn 29 | i = i+1 30 | return fn -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # coding-note 2 | 刷题笔记:Leetcode和剑指Offer等 3 | 4 | 语言: 5 | 6 | - C++(为主) 7 | 8 | - Python 9 | 10 | ​ 11 | 12 | ## 项目 13 | 14 | [数据结构与算法](https://github.com/amusi/coding-note/tree/master/Data%20Structures%20and%20Algorithms) 15 | 16 | [剑指Offer](https://github.com/amusi/coding-note/tree/master/Coding%20Interviews) 17 | 18 | [LeetCode](LeetCode/README.md) 19 | 20 | [GeeksforGeeks](https://www.geeksforgeeks.org/) 21 | 22 | LintCode 23 | 24 | ## 参考资料 25 | 26 | [Interview-Notebook](https://github.com/CyC2018/Interview-Notebook): 含剑指Offer题解、Leetcode题解、算法等内容 27 | 28 | [coding-interview-univerity](https://github.com/jwasham/coding-interview-university): 含算法与数据结构、C++/ JAVA /Python面试经验等 29 | 30 | -------------------------------------------------------------------------------- /Coding Interviews/10_NumberOf1InBinary/NumberOf1InBinary.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-06-20 5 | 6 | 题目描述 7 | 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示 8 | 9 | 10 | ''' 11 | 12 | # -*- coding:utf-8 -*- 13 | class Solution: 14 | # 把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0。那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。 15 | def NumberOf1(self, n): 16 | # write code here 17 | count, bit = 0, 1 18 | INT_BITS = 32 19 | MAX_INT = (1 << (INT_BITS - 1)) - 1 # Maximum Integer for INT_BITS 20 | while n and bit <= MAX_INT + 1: 21 | if bit & n: 22 | count += 1 23 | n -= bit 24 | bit = bit << 1 25 | return count -------------------------------------------------------------------------------- /Coding Interviews/16_ReverseList/ReverseList.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-06-26 5 | 6 | 题目描述 7 | 输入一个链表,反转链表后,输出新链表的表头。 8 | 9 | 10 | ''' 11 | 12 | # -*- coding:utf-8 -*- 13 | # class ListNode: 14 | # def __init__(self, x): 15 | # self.val = x 16 | # self.next = None 17 | class Solution: 18 | # 返回ListNode 19 | # 思路: 即将链表进行反转 20 | def ReverseList(self, pHead): 21 | # write code here 22 | # 输入判断 23 | if pHead == None or pHead.next == None: 24 | return pHead 25 | pre = None 26 | cur = pHead 27 | while cur: 28 | post = cur.next 29 | cur.next = pre 30 | pre = cur 31 | cur = post 32 | return pre -------------------------------------------------------------------------------- /Coding Interviews/17_MergeSortedLists/MergeSortedLists.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-06-26 5 | 6 | 题目描述 7 | 输入一个链表,反转链表后,输出新链表的表头。 8 | 9 | 10 | ''' 11 | 12 | # -*- coding:utf-8 -*- 13 | # class ListNode: 14 | # def __init__(self, x): 15 | # self.val = x 16 | # self.next = None 17 | class Solution: 18 | # 返回ListNode 19 | # 思路: 即将链表进行反转 20 | def ReverseList(self, pHead): 21 | # write code here 22 | # 输入判断 23 | if pHead == None or pHead.next == None: 24 | return pHead 25 | pre = None 26 | cur = pHead 27 | while cur: 28 | post = cur.next 29 | cur.next = pre 30 | pre = cur 31 | cur = post 32 | return pre -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/code/bubble_sort.py: -------------------------------------------------------------------------------- 1 | ''' Summary: 冒泡排序 2 | * Author: Amusi 3 | * Date: 208-05-27 4 | * 5 | * Reference: 6 | * http://en.wikipedia.org/wiki/Bubble_sort 7 | * https://github.com/xtaci/algorithms/blob/master/include/bubble_sort.h 8 | * https://zhuanlan.zhihu.com/p/37077924 9 | * 10 | * 冒泡排序说明:比较相邻的两个元素,将值大的元素交换到右边(降序则相反) 11 | * 12 | ''' 13 | 14 | def BubbleSort(array): 15 | lengths = len(array) 16 | for i in range(lengths-1): 17 | for j in range(lengths-1-i): 18 | if array[j] > array[j+1]: 19 | array[j+1], array[j] = array[j], array[j+1] 20 | 21 | return array 22 | 23 | 24 | array = [1,3,8,5,2,10,7,16,7,4,5] 25 | print("Original array: ", array) 26 | array = BubbleSort(array) 27 | print("BubbleSort: ", array) 28 | -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/code/selection_sort.py: -------------------------------------------------------------------------------- 1 | ''' Summary: 选择排序 2 | * Author: Amusi 3 | * Date: 208-06-22 4 | * 5 | * Reference: 6 | * https://en.wikipedia.org/wiki/Selection_sort 7 | * 8 | * 选择排序说明:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。 9 | * 10 | ''' 11 | 12 | def SelectionSort(array): 13 | lengths = len(array) 14 | for i in range(lengths-1): 15 | min_index = i 16 | for j in range(i, lengths): 17 | if array[j] < array[min_index]: 18 | min_index = j 19 | array[i], array[min_index] = array[min_index], array[i] 20 | 21 | return array 22 | 23 | 24 | array = [1,3,8,5,2,10,7,16,7,4,5] 25 | print("Original array: ", array) 26 | array = SelectionSort(array) 27 | print("SelectionSort: ", array) 28 | -------------------------------------------------------------------------------- /Coding Interviews/08_MinNumberInRotatedArray/MinNumberInRotatedArray.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-06-18 5 | 6 | 题目描述 7 | 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。重建二叉树并返回。 8 | 9 | 10 | ''' 11 | 12 | # -*- coding:utf-8 -*- 13 | class Solution: 14 | # 思路: 非递减排序数组呈规律,经过旋转后,还是呈一定规律,前面一段数组是非递减排序的,后面一段数组也是非递减排序的。 15 | # 但这两段数组间不存在非递减排序规律。如{3,4,5,1,2}中的5和1。因此根据这一特性,找到两段数组相交的位置,输出后一段数组的首元素即可。 16 | def minNumberInRotateArray(self, rotateArray): 17 | # write code here 18 | nums = len(rotateArray); 19 | if nums == 0: 20 | return 0 21 | for i in range(nums): 22 | if rotateArray[i] > rotateArray[i+1]: 23 | return rotateArray[i+1] 24 | return rotateArray[0] -------------------------------------------------------------------------------- /Coding Interviews/07_QueueWithTwoStacks/QueueWithTwoStacks.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-06-17 5 | 6 | 题目描述 7 | 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。 8 | 9 | 10 | ''' 11 | 12 | # -*- coding:utf-8 -*- 13 | # <分析>:利用两个栈,实现两次进栈出栈(先入后出x2)即可实现队列(先入先出)。 14 | class Solution: 15 | def __init__(self): 16 | self.stack1 = [] # 栈A 17 | self.stack2 = [] # 栈B 18 | def push(self, node): 19 | # write code here 20 | self.stack1.append(node) # 向栈顶添加元素 21 | def pop(self): 22 | # return xx 23 | if len(self.stack2) > 0: 24 | return self.stack2.pop() 25 | # 将栈A的所有元素pop并push至栈B中, 26 | while len(self.stack1)>0: # 或者 while self.stack1 27 | self.stack2.append(self.stack1.pop()) 28 | if len(self.stack2) > 0: 29 | return self.stack2.pop() -------------------------------------------------------------------------------- /Data Structures and Algorithms/search/README.md: -------------------------------------------------------------------------------- 1 | # 二分查找 2 | 3 | 二分查找(Binary Search)是将查找的键和子数组的中间键作比较,如果被查找的键小于中间键,就在左子数组继续查找;如果大于中间键,就在右子数组中查找,否则中间键就是要找的元素。 4 | 5 | [Python代码](binary_search.py): 6 | 7 | ```python 8 | import math 9 | 10 | def BinarySearch(arr, key): 11 | left = 0 12 | right = len(arr)-1 13 | 14 | while left <= right: 15 | mid = math.ceil((left+right)/2) 16 | if arr[mid] == key: 17 | return 1 18 | elif arr[mid] 0: 28 | node = q.pop(0) 29 | result_list.append(node.val) 30 | if node.left: 31 | q.append(node.left) 32 | if node.right: 33 | q.append(node.right) 34 | 35 | return result_list -------------------------------------------------------------------------------- /Coding Interviews/06_ConstructBinaryTree/ConstructBinaryTree.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-06-14 5 | 6 | 题目描述 7 | 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。 8 | 9 | 10 | ''' 11 | # -*- coding:utf-8 -*- 12 | # class TreeNode: 13 | # def __init__(self, x): 14 | # self.val = x 15 | # self.left = None 16 | # self.right = None 17 | class Solution: 18 | # 返回构造的TreeNode根节点 19 | def reConstructBinaryTree(self, pre, tin): 20 | # write code here 21 | if len(pre)==0 or len(tin)==0: 22 | return None 23 | root = TreeNode(pre[0]) 24 | root_index_in_tin = tin.index(root.val) 25 | root.left = self.reConstructBinaryTree(pre[1:root_index_in_tin+1],tin[:root_index_in_tin]) 26 | root.right = self.reConstructBinaryTree(pre[root_index_in_tin+1:],tin[root_index_in_tin+1:]) 27 | return root -------------------------------------------------------------------------------- /Coding Interviews/23_PrintTreeFromTopToBottom/PrintTreeFromTopToBottom.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-07-30 5 | 6 | 题目描述 7 | 从上往下打印出二叉树的每个节点,同层节点从左至右打印。 8 | 9 | ''' 10 | 11 | # -*- coding:utf-8 -*- 12 | # class TreeNode: 13 | # def __init__(self, x): 14 | # self.val = x 15 | # self.left = None 16 | # self.right = None 17 | class Solution: 18 | # 返回从上到下每个节点值列表,例:[1,2,3] 19 | # 广度优先搜索 BFS, 借助一个队列就可以实现 20 | def PrintFromTopToBottom(self, root): 21 | # write code here 22 | result_list = [] 23 | if root==None: 24 | return result_list 25 | q = [] 26 | q.append(root) 27 | while len(q) > 0: 28 | node = q.pop(0) 29 | result_list.append(node.val) 30 | if node.left: 31 | q.append(node.left) 32 | if node.right: 33 | q.append(node.right) 34 | 35 | return result_list -------------------------------------------------------------------------------- /Coding Interviews/15_KthNodeFromEnd/KthNodeFromEnd.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-06-22 5 | 6 | 题目描述 7 | 输入一个链表,输出该链表中倒数第k个结点。 8 | 9 | 10 | ''' 11 | 12 | # -*- coding:utf-8 -*- 13 | # class ListNode: 14 | # def __init__(self, x): 15 | # self.val = x 16 | # self.next = None 17 | 18 | class Solution: 19 | def FindKthToTail(self, head, k): 20 | # write code here 21 | # 输入判断 22 | if(head==None or k==0): 23 | return None 24 | 25 | pHead = head; 26 | pTail = head; 27 | # pHead先走 k-1步 28 | for i in range(1, k): 29 | if pHead.next!=None: 30 | pHead = pHead.next 31 | else: 32 | return None; 33 | # pHead和pTail同时走,最后pTail还差k-1步才能走到最后,即pTail当前是倒数第k个结点。 34 | while(pHead.next!=None): 35 | pHead = pHead.next 36 | pTail = pTail.next 37 | 38 | return pTail -------------------------------------------------------------------------------- /Coding Interviews/21_MinInStack/MinInStack.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-07-11 5 | 6 | 题目描述 7 | 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数。在该栈中,调用min、push及pop的时间复杂度都是O(1)。 8 | 9 | ''' 10 | 11 | # -*- coding:utf-8 -*- 12 | class Solution: 13 | 14 | def __init__(self): 15 | self.data_stack = [] 16 | self.help_stack = [] 17 | # 压入新元素 18 | def push(self, node): 19 | self.data_stack.append(node) 20 | if len(self.help_stack)==0: 21 | self.help_stack.append(node) 22 | else: 23 | if node < self.help_stack[-1]: 24 | self.help_stack.append(node) 25 | else: 26 | self.help_stack.append(self.help_stack[-1]) 27 | # 弹出栈顶元素 28 | def pop(self): 29 | self.data_stack.pop() 30 | self.help_stack.pop() 31 | 32 | # 返回栈顶元素 33 | def top(self): 34 | return self.data_stack[-1] 35 | 36 | # 返回当前栈中最小元素 37 | def min(self): 38 | return self.help_stack[-1] -------------------------------------------------------------------------------- /Coding Interviews/20_PrintMatrix/PrintMatrix.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-07-09 5 | 6 | 题目描述 7 | 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10. 8 | 9 | ''' 10 | 11 | # -*- coding:utf-8 -*- 12 | class Solution: 13 | # matrix类型为二维列表,需要返回列表 14 | def printMatrix(self, matrix): 15 | # write code here 16 | result = [] 17 | while(matrix): 18 | result+=matrix.pop(0) 19 | if not matrix or not matrix[0]: 20 | break 21 | matrix = self.turn(matrix) 22 | return result 23 | def turn(self,matrix): 24 | num_r = len(matrix) # 矩阵行数 25 | num_c = len(matrix[0]) # 矩阵列数 26 | newmat = [] 27 | for i in range(num_c): 28 | newmat2 = [] 29 | for j in range(num_r): 30 | newmat2.append(matrix[j][i]) 31 | newmat.append(newmat2) 32 | newmat.reverse() 33 | return newmat -------------------------------------------------------------------------------- /Coding Interviews/22_StackPushPopOrder/StackPushPopOrder.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-07-11 5 | 6 | 题目描述 7 | 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数。在该栈中,调用min、push及pop的时间复杂度都是O(1)。 8 | 9 | ''' 10 | 11 | # -*- coding:utf-8 -*- 12 | class Solution: 13 | 14 | def __init__(self): 15 | self.data_stack = [] 16 | self.help_stack = [] 17 | # 压入新元素 18 | def push(self, node): 19 | self.data_stack.append(node) 20 | if len(self.help_stack)==0: 21 | self.help_stack.append(node) 22 | else: 23 | if node < self.help_stack[-1]: 24 | self.help_stack.append(node) 25 | else: 26 | self.help_stack.append(self.help_stack[-1]) 27 | # 弹出栈顶元素 28 | def pop(self): 29 | self.data_stack.pop() 30 | self.help_stack.pop() 31 | 32 | # 返回栈顶元素 33 | def top(self): 34 | return self.data_stack[-1] 35 | 36 | # 返回当前栈中最小元素 37 | def min(self): 38 | return self.help_stack[-1] -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/code/shell_sort.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * Summary: 希尔排序(Shell Sort) 3 | * Author: Amusi 4 | * Date: 2018-09-23 5 | * 6 | * Reference: 7 | * https://en.wikipedia.org/wiki/Shellsort 8 | * https://www.geeksforgeeks.org/shellsort/ 9 | * 希尔排序(shell sort):设待排序元素序列有n个元素,首先取一个整数increment(小于n)作为间隔将全部元素分为increment个子序列,所有距离为increment的元素放在同一个子序列中,在每一个子序列中分别实行直接插入。 10 | * 11 | * 12 | ''' 13 | 14 | def ShellSort(array): 15 | lengths = len(array) 16 | # 初始化gap 17 | gap = lengths//2 18 | # 减少增量,遍历子序列进行插入排序 19 | while(gap > 0): 20 | for i in range(gap, lengths): 21 | # 22 | temp = array[i] 23 | j = i 24 | # 子序列插入排序 25 | while j>=gap and array[j-gap]>temp: 26 | array[j] = array[j-gap] 27 | j -= gap 28 | 29 | array[j] = temp 30 | 31 | gap = gap//2 32 | 33 | return array 34 | 35 | 36 | array = [1,3,8,5,2,10,7,16,7,4,5] 37 | print("Original array: ", array) 38 | array = ShellSort(array) 39 | print("InsertionnSort: ", array) 40 | -------------------------------------------------------------------------------- /Coding Interviews/19_MirrorOfBinaryTree/MirrorOfBinaryTree.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-07-03 5 | 6 | 题目描述 7 | 操作给定的二叉树,将其变换为源二叉树的镜像。 8 | 9 | 输入描述: 10 | 二叉树的镜像定义:源二叉树 11 | 8 12 | / \ 13 | 6 10 14 | / \ / \ 15 | 5 7 9 11 16 | 镜像二叉树 17 | 8 18 | / \ 19 | 10 6 20 | / \ / \ 21 | 11 9 7 5 22 | 23 | ''' 24 | 25 | # -*- coding:utf-8 -*- 26 | # class TreeNode: 27 | # def __init__(self, x): 28 | # self.val = x 29 | # self.left = None 30 | # self.right = None 31 | class Solution: 32 | # 返回镜像树的根节点 33 | def Mirror(self, root): 34 | # write code here 35 | if root==None: 36 | return 37 | #(可选) 判断是不是叶子结点 38 | if root.left==None and root.right==None: 39 | return 40 | # 交换非叶子结点 41 | temp = root.left 42 | root.left = root.right 43 | root.right = temp 44 | # 如果不是非叶子结点,继续递归 45 | if root.left!=None: 46 | self.Mirror(root.left) 47 | if root.right!=None: 48 | self.Mirror(root.right) -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/code/insertion_sort.py: -------------------------------------------------------------------------------- 1 | ''' Summary: 插入排序(Insertion Sort) 2 | * Author: Amusi 3 | * Date: 208-07-16 4 | * 5 | * Reference: 6 | * https://en.wikipedia.org/wiki/Insertion_sort 7 | * https://www.cnblogs.com/wujingqiao/articles/8961890.html 8 | * 9 | * 插入排序(insertion sort)又称直接插入排序(staright insertion sort),其是将未排序元素一个个插入到已排序列表中。对于未排序元素,在已排序序列中从后向前扫描,找到相应位置把它插进去;在从后向前扫描过程中,需要反复把已排序元素逐步向后挪,为新元素提供插入空间。 10 | * 11 | ''' 12 | 13 | def InsertionnSort(array): 14 | lengths = len(array) 15 | # 从索引位置1开始 16 | for i in range(1, lengths): 17 | currentValue = array[i] # 当前索引对应的元素数值 18 | preIndex = i-1 # 前一个索引位置 19 | # 循环条件: 前一个索引对应元素值大于当前值,前一个索引值大于等于0 20 | while array[preIndex] > currentValue and preIndex>=0: 21 | array[preIndex+1] = array[preIndex] # 前一个索引对应元素值赋值给当前值 22 | preIndex -= 1 # 前一个索引位置-1 23 | # preIndex+1,实现元素交换 24 | array[preIndex+1] = currentValue 25 | 26 | return array 27 | 28 | 29 | array = [1,3,8,5,2,10,7,16,7,4,5] 30 | print("Original array: ", array) 31 | array = InsertionnSort(array) 32 | print("InsertionnSort: ", array) 33 | -------------------------------------------------------------------------------- /Coding Interviews/11_Power/Power.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-06-20 5 | 6 | 题目描述 7 | 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 8 | 9 | 10 | ''' 11 | 12 | # -*- coding:utf-8 -*- 13 | class Solution: 14 | def Power(self, base, exponent): 15 | # write code here 16 | baseSmallFlag = False 17 | pow = 0 18 | baseSmallFlag = self.JudgeSmall(base) 19 | if baseSmallFlag and exponent==0: 20 | return 0 21 | if exponent ==0: 22 | return 1 23 | if exponent > 0: 24 | pow = self.PowerUnsigned(base, exponent) 25 | else: 26 | exponent = abs(exponent) 27 | pow = 1/self.PowerUnsigned(base, exponent) 28 | 29 | return pow 30 | # 计算exponent为正数的情况 31 | def PowerUnsigned(self, base, exponent): 32 | pow = 1 33 | for i in range(exponent): 34 | pow = base*pow 35 | return pow 36 | # 判断base是否很小 37 | def JudgeSmall(self, base): 38 | if(abs(base-0.0)<0.0000001): 39 | return True 40 | else: 41 | return False -------------------------------------------------------------------------------- /LeetCode/code/0026_RemoveDuplicatesFromSortedArray.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-07-29 5 | Reference: https://leetcode.com/problems/remove-duplicates-from-sorted-array/ 6 | https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array 7 | 8 | 题目描述 9 | 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 10 | 11 | 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 12 | 13 | 示例 1: 14 | 15 | 给定数组 nums = [1,1,2], 16 | 17 | 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 18 | 19 | 你不需要考虑数组中超出新长度后面的元素。 20 | 21 | 示例 2: 22 | 23 | 给定 nums = [0,0,1,1,1,2,2,3,3,4], 24 | 25 | 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 26 | 27 | 你不需要考虑数组中超出新长度后面的元素。 28 | 29 | ''' 30 | 31 | 32 | class Solution: 33 | def removeDuplicates(self, nums): 34 | """ 35 | :type nums: List[int] 36 | :rtype: int 37 | """ 38 | length = 0 39 | if(len(nums)<=0): 40 | return length 41 | length+=1 42 | for i in range(1, len(nums)): 43 | if(nums[i-1]!=nums[i]): 44 | length+=1 45 | nums[length-1]=nums[i] 46 | return length 47 | -------------------------------------------------------------------------------- /LeetCode/code/0001_TwoSum.cpp: -------------------------------------------------------------------------------- 1 | /***************************************** 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-08-20 5 | Reference: https://leetcode-cn.com/problems/two-sum/solution/ 6 | https://leetcode.com/problems/two-sum/solution/ 7 | 8 | 题目描述 9 | 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。 10 | 11 | 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。 12 | 13 | 示例 1: 14 | 15 | 给定 nums = [2, 7, 11, 15], target = 9 16 | 17 | 因为 nums[0] + nums[1] = 2 + 7 = 9 18 | 所以返回 [0, 1] 19 | 20 | *****************************************/ 21 | 22 | // 方法1:暴力法 23 | // a+b=sum,转换成b=sum-a问题,即已经a和sum,再去找到b=sum-a。 24 | // 两次for循环,最外层是a,范围是0~n-2;内层是b,范围是1~n-1,因此时间复杂度为O(n^2),而空间复杂度为O(1)。 25 | class Solution { 26 | public: 27 | vector twoSum(vector& nums, int target) { 28 | vector result; 29 | for(int i=0; i& nums) { 35 | int length = 0; 36 | if(nums.size() == 0) 37 | return length; 38 | length++; 39 | vector indexs; 40 | for(int i=1; i>1; 42 | 43 | // way2: 构造函数求解法 44 | Temp::Reset(); 45 | Temp *a = new Temp[n]; // 循环调用构造函数n次,实现1+2+...+n 46 | delete []a; 47 | a = NULL; 48 | return Temp::GetSum(); 49 | } 50 | }; 51 | ``` 52 | 53 | [Python](Accumulate.py) 递归法 54 | 55 | ```python 56 | # -*- coding:utf-8 -*- 57 | class Solution: 58 | def Sum_Solution(self, n): 59 | # write code here 60 | # 短路法 61 | ans = n 62 | temp = ans and self.Sum_Solution(n-1) 63 | ans += temp 64 | return ans 65 | ``` 66 | 67 | -------------------------------------------------------------------------------- /Coding Interviews/18_SubstructureInTree/SubstructureInTree.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-07-01 5 | 6 | 题目描述 7 | 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构) 8 | 9 | 10 | ''' 11 | 12 | # -*- coding:utf-8 -*- 13 | # class TreeNode: 14 | # def __init__(self, x): 15 | # self.val = x 16 | # self.left = None 17 | # self.right = None 18 | class Solution: 19 | # 递归法 20 | def HasSubtree(self, pRoot1, pRoot2): 21 | '''判断pRoot2是不是pRoot1的子树''' 22 | result = False 23 | if pRoot1!=None and pRoot2!=None: 24 | if pRoot1.val==pRoot2.val: 25 | result = self.DoesTree1HaveTree2(pRoot1, pRoot2) 26 | if result == False: 27 | result = self.HasSubtree(pRoot1.left, pRoot2) # 判断左子树 28 | if result == False: 29 | result = self.HasSubtree(pRoot1.right, pRoot2) # 判断右子树 30 | 31 | return result 32 | 33 | def DoesTree1HaveTree2(self, pRoot1, pRoot2): 34 | '''判断pRoot2是不是pRoot1的子树''' 35 | if pRoot2==None: 36 | return True 37 | if pRoot1==None: 38 | return False 39 | if pRoot1.val != pRoot2.val: 40 | return False 41 | 42 | return self.DoesTree1HaveTree2(pRoot1.left,pRoot2.left) and self.DoesTree1HaveTree2(pRoot1.right,pRoot2.right) -------------------------------------------------------------------------------- /LeetCode/code/0001_TwoSum.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-08-20 5 | Reference: https://leetcode-cn.com/problems/two-sum/solution/ 6 | https://leetcode.com/problems/two-sum/solution/ 7 | 8 | 题目描述 9 | 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。 10 | 11 | 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。 12 | 13 | 示例 1: 14 | 15 | 给定 nums = [2, 7, 11, 15], target = 9 16 | 17 | 因为 nums[0] + nums[1] = 2 + 7 = 9 18 | 所以返回 [0, 1]。 19 | 20 | ''' 21 | 22 | # 方法1:暴力法(Python版本不一定会通过) 23 | # a+b=sum,转换成b=sum-a问题,即已经a和sum,再去找到b=sum-a。 24 | # 两次for循环,最外层是a,范围是0~n-2;内层是b,范围是1~n-1,因此时间复杂度为O(n^2),而空间复杂度为O(1)。 25 | class Solution: 26 | def twoSum(self, nums, target): 27 | """ 28 | :type nums: List[int] 29 | :type target: int 30 | :rtype: List[int] 31 | """ 32 | for i in range(len(nums)-1): 33 | for j in range(i+1, len(nums)): 34 | if target == nums[i]+nums[j]: 35 | return [i,j] 36 | 37 | 38 | 39 | 40 | # 方法2:Python字典法(其实和哈希表原理一致) 41 | class Solution: 42 | def twoSum(self, nums, target): 43 | """ 44 | :type nums: List[int] 45 | :type target: int 46 | :rtype: List[int] 47 | """ 48 | l = {} 49 | for i in range(len(nums)): 50 | if nums[i] in l: 51 | return [l[nums[i]],i] 52 | else: 53 | l[target-nums[i]] = i -------------------------------------------------------------------------------- /Coding Interviews/08_MinNumberInRotatedArray/README.md: -------------------------------------------------------------------------------- 1 | # 题目描述 2 | 3 | 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。 4 | 5 | # 解题思路 6 | 7 | 非递减排序数组呈规律,经过旋转后,还是呈一定规律,前面一段数组是非递减排序的,后面一段数组也是非递减排序的。但这两段数组间不存在非递减排序规律。如{3,4,5,1,2}中的5和1。因此根据这一特性,找到两段数组相交的位置,输出后一段数组的首元素即可。 8 | 9 | # 代码 10 | 11 | [C++](QueueWithTwoStacks.cpp) 12 | 13 | ```c++ 14 | class Solution { 15 | public: 16 | // 思路: 非递减排序数组呈规律,经过旋转后,还是呈一定规律,前面一段数组是非递减排序的,后面一段数组也是非递减排序的。 17 | // 但这两段数组间不存在非递减排序规律。如{3,4,5,1,2}中的5和1。因此根据这一特性,找到两段数组相交的位置,输出后一段数组的首元素即可。 18 | int minNumberInRotateArray(vector rotateArray) { 19 | int nums = rotateArray.size(); 20 | if(nums == 0) 21 | return 0; 22 | for(int i=0; i rotateArray[i+1]) 24 | return rotateArray[i+1]; 25 | } 26 | return rotateArray[0]; 27 | } 28 | }; 29 | ``` 30 | 31 | [Python](QueueWithTwoStacks.py) 32 | 33 | ```python 34 | # -*- coding:utf-8 -*- 35 | class Solution: 36 | # 思路: 非递减排序数组呈规律,经过旋转后,还是呈一定规律,前面一段数组是非递减排序的,后面一段数组也是非递减排序的。 37 | # 但这两段数组间不存在非递减排序规律。如{3,4,5,1,2}中的5和1。因此根据这一特性,找到两段数组相交的位置,输出后一段数组的首元素即可。 38 | def minNumberInRotateArray(self, rotateArray): 39 | # write code here 40 | nums = len(rotateArray); 41 | if nums == 0: 42 | return 0 43 | for i in range(nums): 44 | if rotateArray[i] > rotateArray[i+1]: 45 | return rotateArray[i+1] 46 | return rotateArray[0] 47 | ``` 48 | 49 | -------------------------------------------------------------------------------- /Coding Interviews/05_PrintListInReversedOrder/PrintListlnReversedOrder.cpp: -------------------------------------------------------------------------------- 1 | /***************************************** 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-06-013 5 | 6 | 题目描述 7 | 输入一个链表,从尾到头打印链表每个节点的值。 8 | *****************************************/ 9 | 10 | 11 | /** 12 | * struct ListNode { 13 | * int val; 14 | * struct ListNode *next; 15 | * ListNode(int x) : 16 | * val(x), next(NULL) { 17 | * } 18 | * }; 19 | */ 20 | class Solution { 21 | public: 22 | vector printListFromTailToHead(ListNode* head){ 23 | vector temp; 24 | vector temp2; 25 | //while(head != NULL){ 26 | // temp.push_back(head->val); 27 | // head = head->next; 28 | //} 29 | // 逆序方法1: for循环 30 | //for(int i=temp.size()-1; i>=0; --i){ 31 | // temp2.push_back(temp[i]); 32 | //} 33 | 34 | // 逆序方法2: vector迭代器 35 | //for (vector::reverse_iterator it = temp.rbegin(); it!= temp.rend(); it++){ 36 | // temp2.push_back(*it); 37 | //} 38 | // 逆序方法3: C++ < algorithm > 中定义的reverse函数 39 | //reverse(temp.begin(), temp.end()); 40 | // 逆序方法4: 栈 41 | std::stack nodes; 42 | ListNode *pNode = head; 43 | while(pNode!=NULL){ 44 | nodes.push(pNode); 45 | pNode = pNode->next; 46 | } 47 | while(!nodes.empty()){ 48 | pNode = nodes.top(); 49 | temp.push_back(pNode->val); 50 | nodes.pop(); 51 | } 52 | return temp; 53 | } 54 | }; -------------------------------------------------------------------------------- /Coding Interviews/09_Fibonacci/README.md: -------------------------------------------------------------------------------- 1 | # 题目描述 2 | 3 | 大家都知道斐波那契数列(Fibonacci sequence),现在要求输入一个整数n,请你输出斐波那契数列的第n项。 4 | 5 | n<=39 6 | 7 | # 解题思路 8 | 9 | 此题考查斐波那契数列知识点。请参考[斐波那契数列](Fibonacci.md) 10 | 11 | 斐波那契数列的特征在于前两个数之后的数是前两个数之和(即当前项是前两项的和)。 12 | 13 | ​ ![{\displaystyle 1,\;1,\;2,\;3,\;5,\;8,\;13,\;21,\;34,\;55,\;89,\;144,\;\ldots }](https://wikimedia.org/api/rest_v1/media/math/render/svg/0e5d998b257a8bd5307563ca4c7b96edcb5924a2). 14 | 15 | 根据定义,Fibonacci序列中的前两个数字是1和1(默认),或0和1,具体取决于所选序列的起始点,并且每个后续数字都是前两个数字的和。 16 | 17 | 这里,我们使用网上大多数人默认使用1和1作为数列的前两个数值,然后根据斐波那契数列公式进行求解: 18 | 19 | ![{\displaystyle F_{n}=F_{n-1}+F_{n-2},}](https://wikimedia.org/api/rest_v1/media/math/render/svg/0fff1a1716fcc169546079870357f92757ade5fa) 20 | 21 | # 代码 22 | 23 | [C++](QueueWithTwoStacks.cpp) 24 | 25 | ```c++ 26 | class Solution { 27 | public: 28 | int Fibonacci(int n) { 29 | // 斐波那契数列从1开始,如1,1,2,3,5,8... 30 | if(n > 39 || n < 0) 31 | return 0; 32 | if(n == 1 || n == 2) 33 | return 1; 34 | int i=3; 35 | int fn_2=1; 36 | int fn_1=1; 37 | int fn=0; 38 | while(i <= n){ 39 | fn = fn_1 + fn_2; 40 | fn_2 = fn_1; 41 | fn_1 = fn; 42 | ++i; 43 | } 44 | return fn; 45 | } 46 | }; 47 | ``` 48 | 49 | [Python](QueueWithTwoStacks.py) 50 | 51 | ```python 52 | # -*- coding:utf-8 -*- 53 | class Solution: 54 | def Fibonacci(self, n): 55 | # write code here 56 | if(n>39) or (n<0): 57 | return 0 58 | if(n==1 or n==2): 59 | return 1 60 | fn_2 = 1 61 | fn_1 = 1 62 | fn = 0 63 | i = 3 64 | while(i<=n): 65 | fn = fn_2 + fn_1 66 | fn_2 = fn_1 67 | fn_1 = fn 68 | i = i+1 69 | return fn 70 | ``` 71 | -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/quick_sort.py: -------------------------------------------------------------------------------- 1 | ''' Summary: 快速排序(Quick Sort) 2 | * Author: Amusi 3 | * Date: 208-07-28 4 | * 5 | * Reference: 6 | * https://en.wikipedia.org/wiki/Quicksort 7 | * https://www.cnblogs.com/wujingqiao/articles/8961890.html 8 | * https://github.com/apachecn/LeetCode/blob/master/src/py3.x/sort/QuickSort.py 9 | * 快速排序(quick sort):通过一趟排序将待排列表分隔成独立的两部分,其中一部分的所有元素均比另一部分的所有元素小,则可分别对这两部分继续重复进行此操作,以达到整个序列有序。(这个过程,我们可以使用递归快速实现) 10 | * 11 | ''' 12 | 13 | def QuickSort(array, start, end): 14 | lengths = len(array) 15 | i = start 16 | j = end 17 | # 结束排序(左右两索引值见面,即相等,或者左索引>右索引) 18 | if i >= j: 19 | return # 返回空即可 20 | # 保存首个数值(以首个数值作为基准) 21 | # 这个位置很重要,一定要在if i>=j判断语句之后,否则就索引溢出了 22 | pivot = array[i] 23 | # 一次排序,i和j的值不断的靠拢,然后最终停止,结束一次排序 24 | while i < j: 25 | # 一层循环实现从左边起大于基准的值替换基准的位置,右边起小于基准的值位置替换从左起大于基准值的索引 26 | # (从右往左)和最右边的比较,如果>=pivot,即满足要求,不需要交换,然后j-1,慢慢左移,即拿基准值与前一个值比较; 如果值pivot,那么就交换位置 32 | while i < j and pivot >= array[i]: 33 | # print(pivot, array[i], '*' * 30) 34 | i += 1 35 | array[j] = array[i] 36 | # 列表中索引i的位置为基准值,i左边序列都是小于基准值的,i右边序列都是大于基准值的,当前基准值的索引为i,之后不变 37 | array[i] = pivot 38 | # 左边排序 39 | QuickSort(array, start, i-1) 40 | # 右边排序 41 | QuickSort(array, i+1, end) 42 | 43 | #return array 44 | 45 | if __name__ == "__main__": 46 | array = [1,3,8,5,2,10,7,16,7,4,5] 47 | print("Original array: ", array) 48 | #array = QuickSort(array, 0, len(array)-1) 49 | # 因为python中的list对象是可变对象,所以在函数做"形参"时,是相当于按引用传递 50 | # 所以不写成返回值的形式,也是OK的 51 | QuickSort(array, 0, len(array)-1) 52 | print("QuickSort: ", array) 53 | -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/code/quick_sort.py: -------------------------------------------------------------------------------- 1 | ''' Summary: 快速排序(Quick Sort) 2 | * Author: Amusi 3 | * Date: 208-07-28 4 | * 5 | * Reference: 6 | * https://en.wikipedia.org/wiki/Quicksort 7 | * https://www.cnblogs.com/wujingqiao/articles/8961890.html 8 | * https://github.com/apachecn/LeetCode/blob/master/src/py3.x/sort/QuickSort.py 9 | * 快速排序(quick sort):通过一趟排序将待排列表分隔成独立的两部分,其中一部分的所有元素均比另一部分的所有元素小,则可分别对这两部分继续重复进行此操作,以达到整个序列有序。(这个过程,我们可以使用递归快速实现) 10 | * 11 | ''' 12 | 13 | def QuickSort(array, start, end): 14 | lengths = len(array) 15 | i = start 16 | j = end 17 | # 结束排序(左右两索引值见面,即相等,或者左索引>右索引) 18 | if i >= j: 19 | return # 返回空即可 20 | # 保存首个数值(以首个数值作为基准) 21 | # 这个位置很重要,一定要在if i>=j判断语句之后,否则就索引溢出了 22 | pivot = array[i] 23 | # 一次排序,i和j的值不断的靠拢,然后最终停止,结束一次排序 24 | while i < j: 25 | # 一层循环实现从左边起大于基准的值替换基准的位置,右边起小于基准的值位置替换从左起大于基准值的索引 26 | # (从右往左)和最右边的比较,如果>=pivot,即满足要求,不需要交换,然后j-1,慢慢左移,即拿基准值与前一个值比较; 如果值pivot,那么就交换位置 32 | while i < j and pivot >= array[i]: 33 | # print(pivot, array[i], '*' * 30) 34 | i += 1 35 | array[j] = array[i] 36 | # 列表中索引i的位置为基准值,i左边序列都是小于基准值的,i右边序列都是大于基准值的,当前基准值的索引为i,之后不变 37 | array[i] = pivot 38 | # 左边排序 39 | QuickSort(array, start, i-1) 40 | # 右边排序 41 | QuickSort(array, i+1, end) 42 | 43 | #return array 44 | 45 | if __name__ == "__main__": 46 | array = [1,3,8,5,2,10,7,16,7,4,5] 47 | print("Original array: ", array) 48 | #array = QuickSort(array, 0, len(array)-1) 49 | # 因为python中的list对象是可变对象,所以在函数做"形参"时,是相当于按引用传递 50 | # 所以不写成返回值的形式,也是OK的 51 | QuickSort(array, 0, len(array)-1) 52 | print("QuickSort: ", array) 53 | -------------------------------------------------------------------------------- /LeetCode/code/0004_.MedianofTwoSortedArrays.cpp: -------------------------------------------------------------------------------- 1 | /***************************************** 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-08-30 5 | Reference: https://leetcode.com/problems/median-of-two-sorted-arrays/description/ 6 | https://leetcode-cn.com/problems/median-of-two-sorted-arrays/description/ 7 | https://www.cnblogs.com/dreamer123/p/9159499.html 8 | 9 | 题目描述: 10 | 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 。 11 | 12 | 请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。 13 | 14 | 你可以假设 nums1 和 nums2 不同时为空。 15 | 16 | 示例 1: 17 | 18 | nums1 = [1, 3] 19 | nums2 = [2] 20 | 21 | 中位数是 2.0 22 | 23 | 示例 2: 24 | 25 | nums1 = [1, 2] 26 | nums2 = [3, 4] 27 | 28 | 中位数是 (2 + 3)/2 = 2.5 29 | 30 | *****************************************/ 31 | 32 | // 方法1:暴力求解法:先合并两个数组,然后根据下标索引返回相应的中位数 33 | 34 | class Solution { 35 | public: 36 | double findMedianSortedArrays(vector& nums1, vector& nums2) { 37 | int i=0; 38 | int j=0; 39 | int size = nums1.size()+nums2.size(); 40 | vector mergeNums; 41 | double result; 42 | //mergeNums.resize(size); 43 | for(int a=0;a((mergeNums[size/2 - 1]+mergeNums[size/2])/2.0); 65 | } 66 | else 67 | result = mergeNums[size/2]; 68 | return result; 69 | } 70 | }; 71 | 72 | // TODO:分割法 73 | 74 | -------------------------------------------------------------------------------- /Coding Interviews/03_FindInPartiallySortedMatrix/FindInPartiallySortedMatrix.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright: Amusi 3 | Author: Amusi 4 | Date: 2018-06-08 5 | 6 | 题目描述 7 | 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。 8 | 请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 9 | 10 | 输入: 二维数组和待查询的整数 11 | 输出: 待查询整数是否在二维数组(True, False) 12 | 13 | 14 | 思路: 15 | 二维数组matrix, 二维数组行数: rows,二维数组列数: cols, 待查询数值num 16 | 1.先将二维数组转换成一维数组进行处理 17 | 2.定义判断初始值为左下角元素matrix[row][col],其中row=rows-1, col=0 18 | 3.将二维数组的左下角元素matrix[row][col](或者右上角元素)值与带查询num进行比较, 19 | 如果matrix[row][col] > num,则--row;如果matrix[row][col] < num,则++col。 20 | 4.重复第3步,直到遍历完所有可以遍历的数组元素。 21 | 22 | ''' 23 | 24 | ''' 25 | 版本1 26 | ''' 27 | def judge_inter_in_array(matrix, rows, cols, search_num): 28 | ''' 判断数组中是否含有该整数''' 29 | row = rows-1 30 | col = 0 31 | 32 | if rows==0 or cols==0: 33 | return False 34 | 35 | while rows>=0 and col search_num: 37 | row = row-1 38 | elif matrix[row][col] < search_num: 39 | col = col+1 40 | else: 41 | return True 42 | 43 | return False 44 | 45 | ''' 46 | 版本2 47 | ''' 48 | # -*- coding:utf-8 -*- 49 | class Solution: 50 | # array 二维列表 51 | def Find(self, target, array): 52 | # write code here 53 | # 计算数组的行列 54 | rows = len(array) # 计算行数 55 | cols = len(array[0]) # 计算列数 56 | 57 | if rows<=0 or cols<=0: 58 | return False 59 | 60 | row = rows-1 61 | col = 0 62 | 63 | while row >=0 and col target: 67 | row = row-1 68 | else: 69 | return True 70 | 71 | return False 72 | 73 | 74 | if __name__ == '__main__': 75 | matrix = [ 76 | [1, 2, 8, 9], 77 | [2, 4, 9, 12], 78 | [4, 7, 10, 13], 79 | [6, 8, 11, 15] 80 | ] 81 | 82 | # 版本1 83 | print(judge_inter_in_array(matrix, 4, 4, 11)) 84 | 85 | ss = Solution() 86 | print(ss.Find(11, matrix)) 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /Coding Interviews/16_ReverseList/README.md: -------------------------------------------------------------------------------- 1 | # 题目描述 2 | 3 | 输入一个链表,反转链表后,输出新链表的表头。 4 | 5 | # 解题思路 6 | 7 | 此题考查[链表](https://github.com/amusi/coding-note/blob/master/Coding%20Interviews/05_PrintListInReversedOrder/Linkedlist.md)知识点。 8 | 9 | 链表一般是由多个结点组成,除了首结点和尾结点外,所有的结点都有前后相连的结点。那么如何将一个链表进行反转呢?我们可以利用链表自身特性来解决。 10 | 11 | 我们定义pre、cur和post三个结点来求解此题,分别表示前结点,当前结点和后结点。输入的顺序是:pre->cur->post。因为是反转,所以我们应该将cur指向pre,然后将cur作为新的pre,而post作为新的cur。此时,新的pre是原pre、cur反转后的结果。经过多次迭代,直到cur==NULL时,输出pre即可。 12 | 13 | **举个栗子:** 14 | 15 | 如下图所示,哈哈,虽然画风很奇怪,但我想不用赘述,结合上述解释、图示和代码,相信你可以理解。 16 | 17 | 注: 18 | 19 | - 反转时,pre和cur、post是断开的,这个最好画图来理解。 20 | 21 | 22 | - while循环的判断语句要注意,一定要遍历完所有结点。 23 | 24 | ![](ReverseList.png) 25 | 26 | 27 | 28 | # 代码 29 | 30 | [C++](KthNodeFromEnd.cpp) 31 | 32 | ```c++ 33 | /* 34 | struct ListNode { 35 | int val; 36 | struct ListNode *next; 37 | ListNode(int x) : 38 | val(x), next(NULL) { 39 | } 40 | };*/ 41 | class Solution { 42 | public: 43 | // 思路: 将列表进行反转 44 | ListNode* ReverseList(ListNode* pHead) { 45 | if(pHead==NULL || pHead->next==NULL) 46 | return pHead; 47 | 48 | ListNode* cur = pHead; 49 | ListNode* pre = NULL; // ListNode* pre = NULL; 50 | ListNode* post = NULL; // ListNode* post = pHead->next; 51 | while (cur!=NULL){ 52 | post = cur->next; 53 | cur->next = pre; 54 | pre = cur; 55 | cur = post; 56 | } 57 | pHead = pre; 58 | return pHead; 59 | } 60 | }; 61 | ``` 62 | 63 | [Python](KthNodeFromEnd.py) 64 | 65 | ```python 66 | # -*- coding:utf-8 -*- 67 | # class ListNode: 68 | # def __init__(self, x): 69 | # self.val = x 70 | # self.next = None 71 | class Solution: 72 | # 返回ListNode 73 | # 思路: 即将链表进行反转 74 | def ReverseList(self, pHead): 75 | # write code here 76 | # 输入判断 77 | if pHead == None or pHead.next == None: 78 | return pHead 79 | pre = None 80 | cur = pHead 81 | while cur: 82 | post = cur.next 83 | cur.next = pre 84 | pre = cur 85 | cur = post 86 | return pre 87 | ``` 88 | 89 | # 参考 90 | 91 | https://blog.csdn.net/u013271921/article/details/46382345 -------------------------------------------------------------------------------- /Coding Interviews/07_QueueWithTwoStacks/README.md: -------------------------------------------------------------------------------- 1 | # 题目描述 2 | 3 | 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。 4 | 5 | (推荐阅读):[队列和栈(Queue and stack)](QueueStack.md) 6 | 7 | # 解题思路 8 | 9 | 此题考查**队列和栈**的知识点,个人觉得题目不难,但理解数据结构【队列】和【栈】反倒是一件困难的事情。 10 | 11 | <分析>:利用两个栈,实现两次进栈出栈(先入后出x2)即可实现队列(先入先出)。 12 | 13 | 如1,2,3,4,5依次入栈A(此时top为5),出栈并入栈B为:5,4,3,2,1(此时top为1)。此时的栈B即相当于一个队列。 14 | 15 | 入队:将元素进栈A 16 | 17 | 出队:判断栈B是否为空,如果为空,则将栈A中所有元素pop,并push进栈B,栈B出栈; 18 | 19 | 如果不为空,栈B直接出栈。 20 | 21 | 22 | 23 | # 代码 24 | 25 | [C++](QueueWithTwoStacks.cpp) 26 | 27 | ```c++ 28 | class Solution 29 | { 30 | /* 解题思路 31 | <分析>:利用两个栈,实现两次进栈出栈(先入后出x2)即可实现队列(先入先出)。 32 | 如1,2,3,4,5依次入栈A(此时top为5),出栈并入栈B为:5,4,3,2,1(此时top为1)。此时的栈B即相当于一个队列。 33 | 入队:将元素进栈A 34 | 出队:判断栈B是否为空,如果为空,则将栈A中所有元素pop,并push进栈B,栈B出栈; 35 | 如果不为空,栈B直接出栈 36 | */ 37 | public: 38 | void push(int node) { 39 | stack1.push(node); 40 | } 41 | 42 | int pop() { 43 | if(stack2.empty()){ 44 | // 将stack1中的所有元素pop,并push到stack2中 45 | while(!stack1.empty()){ 46 | temp = stack1.top(); 47 | stack2.push(temp); 48 | stack1.pop(); 49 | } 50 | } 51 | // 取栈2的队头元素 52 | temp = stack2.top(); 53 | stack2.pop(); 54 | return temp;; 55 | } 56 | 57 | private: 58 | // 使用C++ STL: stack 59 | int temp; 60 | stack stack1; // 队列元素 61 | stack stack2; // 62 | }; 63 | ``` 64 | 65 | [Python](QueueWithTwoStacks.py) 66 | 67 | ```python 68 | # -*- coding:utf-8 -*- 69 | # <分析>:利用两个栈,实现两次进栈出栈(先入后出x2)即可实现队列(先入先出)。 70 | class Solution: 71 | def __init__(self): 72 | self.stack1 = [] # 栈A 73 | self.stack2 = [] # 栈B 74 | def push(self, node): 75 | # write code here 76 | self.stack1.append(node) # 向栈顶添加元素 77 | def pop(self): 78 | # return xx 79 | if len(self.stack2) > 0: 80 | return self.stack2.pop() 81 | # 将栈A的所有元素pop并push至栈B中, 82 | while len(self.stack1)>0: # 或者 while self.stack1 83 | self.stack2.append(self.stack1.pop()) 84 | if len(self.stack2) > 0: 85 | return self.stack2.pop() 86 | ``` 87 | 88 | # 参考 89 | 90 | [思路和代码解答](https://www.nowcoder.com/questionTerminal/54275ddae22f475981afa2244dd448c6) 91 | 92 | -------------------------------------------------------------------------------- /Coding Interviews/03_FindInPartiallySortedMatrix/README.md: -------------------------------------------------------------------------------- 1 | # 题目描述 2 | 3 | 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。 4 | 请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 5 | 6 | # 解题思路 7 | 8 | 根据题目信息,可以知道输入和输出信息如下: 9 | 10 | - 输入: 二维数组和待查询的整数 11 | - 输出: 待查询整数是否在二维数组(True, False) 12 | 13 | 已经二维数组是称规律排列,我们可以先确定一个查询起点,再根据已知的排列规律进行查询。如将二维数组左下角元素作为查询起点,比较左下角元素与待查询数值的大小,如果左下角元素小于待查询数值,则根据排列规则,应该将列数+1。再进行比较,直到左下角元素大于待查询数值,此时即可以将行数-1。继续查询,直到左下角元素等于待查询数值,即可返回True,反之,返回False。 14 | 15 | # 解题步骤 16 | 17 | 二维数组matrix, 二维数组行数: rows,二维数组列数: cols, 待查询数值num 18 | 19 | 1.先将二维数组转换成一维数组进行处理 20 | 2.定义判断初始值为左下角元素matrix[row][col],其中row=rows-1, col=0 21 | 3.将二维数组的左下角元素matrix[row][col](或者右上角元素)值与带查询num进行比较, 22 | 如果matrix[row][col] > num,则--row;如果matrix[row][col] < num,则++col。 23 | 4.重复第3步,直到遍历完所有可以遍历的数组元素。 24 | 25 | 举个栗子,如下图所示(图虽然有点丑,但应该能看懂,嘻嘻) 26 | 27 | ![FindInPartiallySortedMatrix.png](FindInPartiallySortedMatrix.png) 28 | 29 | # 代码 30 | 31 | [C++](FindInPartiallySortedMatrix.cpp) 32 | 33 | ```c++ 34 | class Solution { 35 | public: 36 | bool Find(int target, vector > array) { 37 | int matrix_rows = array.size(); // 二维数组行数 38 | int matrix_cols = array[0].size(); // 二维数组列数 39 | int row = matrix_rows - 1; 40 | int col = 0; 41 | // 判断输入的二维数组是否符合要求 42 | if (matrix_rows == 0 && matrix_cols == 0) 43 | return false; 44 | // 循环 45 | while (row >= 0 && col < matrix_cols) 46 | { // 比较当前元素和待查询元素大小 47 | if (target < array[row][col]) 48 | { 49 | --row; // 减行 50 | } 51 | else if (target > array[row][col]) 52 | { 53 | ++col; // 加列 54 | } 55 | else 56 | return true; 57 | } 58 | return false; 59 | } 60 | }; 61 | ``` 62 | 63 | 64 | 65 | [Python](FindInPartiallySortedMatrix.py) 66 | 67 | ```python 68 | # -*- coding:utf-8 -*- 69 | class Solution: 70 | # array 二维列表 71 | def Find(self, target, array): 72 | # write code here 73 | # 计算数组的行列 74 | rows = len(array) # 计算行数 75 | cols = len(array[0]) # 计算列数 76 | 77 | if rows<=0 or cols<=0: 78 | return False 79 | 80 | row = rows-1 81 | col = 0 82 | 83 | while row >=0 and col target: 87 | row = row-1 88 | else: 89 | return True 90 | return False 91 | ``` 92 | 93 | 94 | 95 | TODO 96 | 97 | 版本1: 仍需要人为输入二维数组的行和列,太不智能化 -------------------------------------------------------------------------------- /Coding Interviews/05_PrintListInReversedOrder/PrintListlnReversedOrder.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | ''' 3 | Copyright: Amusi 4 | Author: Amusi 5 | Date: 2018-06-013 6 | 7 | 题目描述 8 | 输入一个链表,从尾到头打印链表每个节点的值。 9 | ''' 10 | 11 | # Definition for singly-linked list. 12 | # 节点类 13 | class ListNode(): 14 | def __init__(self, x): 15 | self.val = x 16 | self.next = None 17 | # 链表处理类 18 | class ListNode_handle: 19 | def __init__(self): 20 | self.cur_node = None 21 | 22 | def add(self, data): 23 | '''从后向前添加元素''' 24 | # 思想: 将新加节点的next指向当前链表(即在首部加节点),生成新的链表,再赋值给当前链表即可 25 | #add a new node pointed to previous node 26 | node = ListNode(data) 27 | 28 | node.next = self.cur_node 29 | self.cur_node = node 30 | 31 | return self.cur_node 32 | 33 | def append(self, data): 34 | '''从前向后添加新元素''' 35 | # 思想: 找到当前链表的最后节点,将当前链表最后节点的next指向新的节点,即实现链表的扩展,此时不需要重新赋值(因为是在原来的链表上添加的) 36 | node = ListNode(data) # 将元素转换成节点 37 | if self.cur_node == None: 38 | self.cur_node = node # 若为空链表,则将添加的元素设为第一个元素 39 | else: 40 | current = self.cur_node 41 | # 判断是否为最后一个节点 42 | while current.next != None: 43 | current = current.next 44 | current.next = node 45 | print(self.cur_node is current) 46 | return self.cur_node 47 | 48 | def print_ListNode(self, node): 49 | while node: 50 | print('\nnode: ', node, ' value: ', node.val, ' next: ', node.next) 51 | node = node.next 52 | 53 | def _reverse(self, nodelist): 54 | list = [] 55 | while nodelist: 56 | list.append(nodelist.val) 57 | nodelist = nodelist.next 58 | result = ListNode() 59 | result_handle = ListNode_handle() 60 | for i in list: 61 | result = result_handle.add(i) 62 | return result 63 | 64 | 65 | class Solution: 66 | # 返回从尾部到头部的列表值序列,例如[1,2,3] 67 | def printListFromTailToHead(self, listNode): 68 | # write code here 69 | result = [] 70 | while listNode != None: 71 | result.append(listNode.val) 72 | listNode = listNode.next 73 | result.reverse() 74 | return result 75 | #测试用例: 76 | #{67,0,24,58} 77 | #对应输出应该为:[58,24,0,67] 78 | l1 = ListNode_handle() # 初始化对象 79 | l1_list = [67,0,24,58] # 定义列表 80 | for i in l1_list: 81 | l1_node = l1.add(i) # 向列表中添加元素 82 | process = Solution() 83 | print(process.printListFromTailToHead(l1_node)) -------------------------------------------------------------------------------- /Coding Interviews/14_ReorderArray/README.md: -------------------------------------------------------------------------------- 1 | # 题目描述 2 | 3 | **输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对顺序不变。** 4 | 5 | 注:此题是牛客网添加了限制条件的题目,并非原《剑指Offer》第14题:调整数组顺序使奇数位于偶数前面。 6 | 7 | 原题目描述:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。 8 | 9 | 从这里就能看出,牛客网添加了限制条件:保证奇数和奇数,偶数和偶数之间的相对顺序不变。 10 | 11 | # 解题思路 12 | 13 | **思路1(简单粗暴不推荐):时间复杂度o(n)** 14 | 15 | 既然是将数组分成偶数部分和奇数部分,那么可以先遍历一遍整个数组array,分别将奇数和偶数的值拷贝至两个容器中,如奇数容器odd和偶数容器even(此时odd和even各自保持了相对顺序不变)。然后依次将odd和even中的值赋值于array。此时的array即是由相对顺序不变的奇数部分和偶数部分组成。 16 | 17 | **思路2(冒泡排序):时间复杂度o(n^2)** 18 | 19 | 此题也可以利用冒泡排序的思想,相邻元素进行比较,如果前者是偶数,后者是奇数,则交换两个元素的位置。遍历完第 i次数组,倒数第 i个元素就被确定好,不再进行判断交换。具体的可以查看[冒泡排序](https://en.wikipedia.org/wiki/Bubble_sort)的思想。 20 | 21 | - [ ] **思路3(归并、插入、归并和快速排序)** 22 | 23 | # 代码 24 | 25 | [C++](Power.cpp) 26 | 27 | ```c++ 28 | class Solution { 29 | public: 30 | void reOrderArray(vector &array) { 31 | /*方法3(归并、插入、归并和快速排序):TODO*/ 32 | /*方法2(冒泡排序):复杂度为o(n2)*/ 33 | int size = array.size(); 34 | if(size == 0){ 35 | return; 36 | } 37 | int temp=0; 38 | for(int i=0;i odd; 55 | vector even; 56 | for(int i=0;i length) 73 | return; 74 | 75 | int index_original = original_length; 76 | int index_new = new_length; 77 | 78 | // 3. 从右向左排列新的字符串,将空格替换成%20 79 | while (index_original >= 0 && index_new > index_original){ 80 | if (str[index_original] == ' ') 81 | { 82 | str[index_new--] = '0'; 83 | str[index_new--] = '2'; 84 | str[index_new--] = '%'; 85 | } 86 | else{ 87 | str[index_new--] = str[index_original]; 88 | } 89 | 90 | --index_original; // 从右向左 91 | } 92 | 93 | } 94 | }; 95 | ``` 96 | 97 | 98 | 99 | [Python](ReplaceBlank.cpp.py) 100 | 101 | 利用Python写,真的就耍赖皮了(和C++特性差异就出来了),不管怎么处理,返回正确的值重新覆盖即可。根本不用管是值传递还是引用传递(当然了,传递字符串,就是值传递)。 102 | 103 | 注:Python的return,真的美滋滋;Python的replace内置函数真的可以为所欲为 104 | 105 | ```python 106 | # -*- coding:utf-8 -*- 107 | class Solution: 108 | # s 源字符串 109 | def replaceSpace(self, s): 110 | # write code here 111 | return s.replace(' ', '%20') 112 | ``` 113 | -------------------------------------------------------------------------------- /Coding Interviews/22_StackPushPopOrder/README.md: -------------------------------------------------------------------------------- 1 | # 题目描述 2 | 3 | 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的) 4 | 5 | # 解题思路 6 | 7 | 考查知识点: 8 | 9 | - [栈(Stack)知识点](https://github.com/amusi/coding-note/blob/master/Coding%20Interviews/07_QueueWithTwoStacks/QueueStack.md) 10 | - [C++ STL::Stack用法](http://www.cplusplus.com/reference/stack/stack/) 11 | - [Python list用法](https://docs.python.org/3.8/c-api/list.html) 12 | 13 | 一开始看到这个题目,觉得很简单。以为是一下子入栈,然后出栈,所以理所当然以为直接判断第一个序列和第二个序列是否是逆序关系。但结果发现是我太单纯了,题目都没有读懂。 14 | 15 | 为了方便描述,这里定义第一个序列(压入栈)为pushV,第二个序列(弹出栈)为popV。 16 | 17 | 本题的关键考查对栈(stack)的掌握,其特点是先入后出,返回栈顶元素。 18 | 19 | 解决此问题的技巧在于,**构建一个辅助栈stack**。该辅助栈stack就是来模拟pushV的弹出情况是否能和popV一致。如果一致,则表示pushV和popV是满足"栈的压入、弹出序列"关系的,否则,不满足关系。 20 | 21 | 通过将pushV的元素依次压入到stack中,在每压入新元素时,需要将stack栈顶元素与popV栈顶元素进行比较。如果相同,则将stack和popV栈顶元素都弹出;如果不同,则继续压入新元素。当把pushV序列中所有元素压入stack,并进行stack和popV栈顶严元素比较后,判断此时stack是否为空的情况。 22 | 23 | 如果stack为空,则表示辅助栈stack与popV序列对应关系一致,即pushV和popV是满足"栈的压入、弹出序列"关系的,否则,不满足关系。 24 | 25 | 26 | 27 | # 代码 28 | 29 | [C++](StackPushPopOrder.cpp) 30 | 31 | ```c++ 32 | class Solution { 33 | public: 34 | bool IsPopOrder(vector pushV,vector popV) { 35 | // 判断输入 36 | if(pushV.size() == 0) 37 | return false; 38 | // 添加辅助栈 39 | vector stack; // 辅助栈的目的是与popV进行对比 40 | for(int i=0,j=0; i pre,vector in) { 36 | // pre: 前序遍历结果 37 | // vin: 中序遍历结果 38 | // 判断 39 | int inlen = in.size(); 40 | int prelen = pre.size(); 41 | if (inlen==0 || prelen==0) 42 | return NULL; 43 | // 初始化 44 | TreeNode* root = new TreeNode(pre[0]); 45 | // 找到根节点在中序遍历中的位置 46 | int root_index_in_tin=0; 47 | for(int i=0; i left_pre, right_pre, left_in, right_in; 55 | // 左子树 56 | for (int i=0; ileft = reConstructBinaryTree(left_pre, left_in); 67 | root->right = reConstructBinaryTree(right_pre, right_in); 68 | 69 | return root; 70 | 71 | } 72 | }; 73 | ``` 74 | 75 | [Python](ConstructBinaryTree.py) 76 | 77 | ```python 78 | # -*- coding:utf-8 -*- 79 | # class TreeNode: 80 | # def __init__(self, x): 81 | # self.val = x 82 | # self.left = None 83 | # self.right = None 84 | class Solution: 85 | # 返回构造的TreeNode根节点 86 | def reConstructBinaryTree(self, pre, tin): 87 | # write code here 88 | if len(pre)==0 or len(tin)==0: 89 | return None 90 | root = TreeNode(pre[0]) 91 | root_index_in_tin = tin.index(root.val) 92 | root.left = self.reConstructBinaryTree(pre[1:root_index_in_tin+1],tin[:root_index_in_tin]) 93 | root.right = self.reConstructBinaryTree(pre[root_index_in_tin+1:],tin[root_index_in_tin+1:]) 94 | return root 95 | ``` 96 | 97 | -------------------------------------------------------------------------------- /Coding Interviews/23_PrintTreeFromTopToBottom/README.md: -------------------------------------------------------------------------------- 1 | # 从上往下打印二叉树 2 | 3 | # 题目描述 4 | 5 | 从上往下打印出二叉树的每个节点,同层节点从左至右打印。 6 | 7 | # 解题思路 8 | 9 | 考查知识点: 10 | 11 | - 二叉树 12 | - 队列(queue)知识点 13 | 14 | 这道题看起来是考查树的遍历算法,但这种按层遍历算法并不是我们熟悉的前序遍历、中序遍历和后序遍历。 15 | 16 | 解决此题的关键在于使用先入先出的队列(queue)。因为我们可以观察从上往下打印二叉树的规律:每一次打印一个结点的时候,如果该结点有子结点,则把该结点的子结点放到一个队列的末尾。接下来到队列头部取出最早进入队列的结点,重复前面的打印操作,直到队列中的所有的结点都被打印出来为止。详见下述代码 17 | 18 | # 代码 19 | 20 | [C++](PrintTreeFromTopToBottom.cpp) 21 | 22 | ```c++ 23 | /* 24 | struct TreeNode { 25 | int val; 26 | struct TreeNode *left; 27 | struct TreeNode *right; 28 | TreeNode(int x) : 29 | val(x), left(NULL), right(NULL) { 30 | } 31 | };*/ 32 | class Solution { 33 | public: 34 | vector PrintFromTopToBottom(TreeNode* root) { 35 | /* 方法1:不管指针是不是空的都先入队,出队的时候再判断 36 | std::queue q; // 最早被压入队列的元素 37 | q.push(root); 38 | vector resultTree; 39 | // 判断队列是否为空 40 | while(q.size()){ // while(!q.empty()) 41 | root = q.front(); // 最早被压入队列中的元素 42 | q.pop(); // 弹出队列的第一个元素 43 | // 不管指针是不是空的都先入队,出队的时候再判断 44 | if(!root) 45 | continue; 46 | // 将当前队列中的第一个元素存储起来 47 | resultTree.push_back(root->val); 48 | q.push(root->left); // 从左 49 | q.push(root->right); // 到右 50 | } 51 | return resultTree; 52 | */ 53 | 54 | // 方法2:先判断指针是否为空 55 | vector resultTree; 56 | if(root == NULL) 57 | return resultTree; 58 | queue q; 59 | q.push(root); 60 | while(q.size()){ 61 | resultTree.push_back(q.front()->val); 62 | if(q.front()->left!=NULL) 63 | q.push(q.front()->left); 64 | if(q.front()->right!=NULL) 65 | q.push(q.front()->right); 66 | q.pop(); 67 | } 68 | return resultTree; 69 | } 70 | }; 71 | ``` 72 | 73 | [Python](PrintTreeFromTopToBottom.py) 74 | 75 | ```python 76 | # -*- coding:utf-8 -*- 77 | # class TreeNode: 78 | # def __init__(self, x): 79 | # self.val = x 80 | # self.left = None 81 | # self.right = None 82 | class Solution: 83 | # 返回从上到下每个节点值列表,例:[1,2,3] 84 | # 广度优先搜索 BFS, 借助一个队列就可以实现 85 | def PrintFromTopToBottom(self, root): 86 | # write code here 87 | result_list = [] 88 | if root==None: 89 | return result_list 90 | q = [] 91 | q.append(root) 92 | while len(q) > 0: 93 | node = q.pop(0) 94 | result_list.append(node.val) 95 | if node.left: 96 | q.append(node.left) 97 | if node.right: 98 | q.append(node.right) 99 | 100 | return result_list 101 | ``` 102 | 103 | # 参考 104 | 105 | https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106 -------------------------------------------------------------------------------- /Coding Interviews/05_PrintListInReversedOrder/README.md: -------------------------------------------------------------------------------- 1 | # 题目描述 2 | 3 | 输入一个链表,从尾到头打印链表每个节点的值。 4 | 5 | (推荐阅读):[链表(Linked list)](Linkedlist.md) 6 | 7 | # 解题思路 8 | 9 | 此题考查链表的知识点,个人觉得题目不难,但理解数据结构【链表】反倒是一件困难的事情。 10 | 11 | 简单来说,链表可以看成一排元素,注意是一排!手拉手的那种!关于链表的理解,请参考[链表(Linked list)](Linkedlist.md) 12 | 13 | 思路1:此题要求打印链表每个节点的值,由于不用考虑链表的生成(其实有点复杂),所以我们直接在函数中依次将链表中的节点值取出来,保存至一个容器(对于C++)或者列表(对于Python)中;然后再逆序打印这个容器或者列表即可。 14 | 15 | 思路2:思路1其实偷懒了,因为严格意义上来说,既然是对于链表来操作,那么其实返回结果其实也应该是链表,而不应该是简单的容器或者列表。按这样理解,我们其实应该直接对链表进行逆序打印,而不是转换成中间变量来操作。 16 | 17 | 分析: 18 | 19 | 1). 若链表为空或只有一个元素,则直接返回; 20 | 21 | 2). 设置两个前后相邻的指针p,q. 将p所指向的节点作为q指向节点的后继; 22 | 23 | 3). 重复2),直到q为空 24 | 25 | 4). 调整链表头和链表尾 26 | 27 | **思考:**自己实现测试用例,自己提供函数输入,即手写链表,你会写吗? 28 | 29 | 可以参考 30 | 31 | - [C++](PrintListInReversedOrder.cpp) 32 | 33 | 34 | - [Python](PrintListInReversedOrder.py) 35 | 36 | **部分重要思想总结:** 37 | 38 | - 向链表从后向前添加元素:将新加节点的next指向当前链表(即在首部加节点),生成新的链表,再赋值给当前链表即可 39 | - 向链表从前向后添加元素:找到当前链表的最后节点,将当前链表最后节点的next指向新的节点,即实现链表的扩展,此时不需要重新赋值(因为是在原来的链表上添加的) 40 | 41 | # 代码 42 | 43 | [C++](PrintListInReversedOrder.cpp) 44 | 45 | ```c++ 46 | /** 47 | * struct ListNode { 48 | * int val; 49 | * struct ListNode *next; 50 | * ListNode(int x) : 51 | * val(x), next(NULL) { 52 | * } 53 | * }; 54 | */ 55 | class Solution { 56 | public: 57 | vector printListFromTailToHead(ListNode* head){ 58 | vector temp; 59 | vector temp2; 60 | //while(head != NULL){ 61 | // temp.push_back(head->val); 62 | // head = head->next; 63 | //} 64 | // 逆序方法1: for循环 65 | //for(int i=temp.size()-1; i>=0; --i){ 66 | // temp2.push_back(temp[i]); 67 | //} 68 | 69 | // 逆序方法2: vector迭代器 70 | //for (vector::reverse_iterator it = temp.rbegin(); it!= temp.rend(); it++){ 71 | // temp2.push_back(*it); 72 | //} 73 | // 逆序方法3: C++ < algorithm > 中定义的reverse函数 74 | //reverse(temp.begin(), temp.end()); 75 | // 逆序方法4: 栈 76 | std::stack nodes; 77 | ListNode *pNode = head; 78 | while(pNode!=NULL){ 79 | nodes.push(pNode); 80 | pNode = pNode->next; 81 | } 82 | while(!nodes.empty()){ 83 | pNode = nodes.top(); 84 | temp.push_back(pNode->val); 85 | nodes.pop(); 86 | } 87 | return temp; 88 | } 89 | }; 90 | ``` 91 | 92 | [Python](PrintListInReversedOrder.py) 93 | 94 | ```python 95 | # -*- coding:utf-8 -*- 96 | # class ListNode: 97 | # def __init__(self, x): 98 | # self.val = x 99 | # self.next = None 100 | 101 | class Solution: 102 | # 返回从尾部到头部的列表值序列,例如[1,2,3] 103 | def printListFromTailToHead(self, listNode): 104 | # write code here 105 | list_numbers = [] 106 | while listNode != None: 107 | list_numbers.append(listNode.val) 108 | listNode = listNode.next 109 | list_numbers.reverse() 110 | return list_numbers 111 | ``` 112 | 113 | -------------------------------------------------------------------------------- /Coding Interviews/11_Power/README.md: -------------------------------------------------------------------------------- 1 | # 题目描述 2 | 3 | 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 4 | 5 | 注:不得使用库函数,同时不需要考虑大数问题。 6 | 7 | # 解题思路 8 | 9 | 本题旨在实现 C++和 python中的pow库函数,这属于经常遇见的面试题,考查对库函数的理解程度。 10 | 11 | 此题有很多要考虑的特殊情况: 12 | 13 | - base=0,exponent=0,由于0的0次方在数学上没有意义,所以输出0或者1都是可以的,但编写代码的人要知道这一点。 14 | - exponent为负数时,如何处理? 15 | 16 | **思路1:** 17 | 18 | 一般来说,考虑如下三种情况即可: 19 | 20 | 1. base=0,exponent=0 21 | 2. exponent>0 22 | 3. exponent<0 23 | 24 | 提示:由于计算机表示小数(包括float和double型小数)都有误差,我们不能直接用等号(==)判断两个小数是否相等。但如果两个小数的差的绝对值很小,比如小于0.0000001,就可以认为它们相等。 25 | 26 | **思路2(递归法):** 27 | 28 | 如果输入指数为32,那么我们可以看成base的16次方再乘以base的16次方,而base的16次方可以看成两次base的8次方相乘......根据此规律,当n为偶数时,得出a^n = a^(n/2) * a^(n/2);当n为奇数时,得出a^n=a^(n-1)/2 * a^(n-1)/2 * a。此公式即可以使用递归方法实现。 29 | 30 | # 代码 31 | 32 | [C++](Power.cpp) 33 | 34 | ```c++ 35 | class Solution { 36 | public: 37 | double Power(double base, int exponent) { 38 | int baseSmallFlag = false; 39 | baseSmallFlag = JudgeSmallNumber(base); 40 | double pow = 0; 41 | if(baseSmallFlag && exponent==0) 42 | return 0; 43 | if(exponent==0){ 44 | return 1; 45 | } 46 | if(exponent > 0){ 47 | pow = PowerUnsigned(base, exponent); 48 | } 49 | else{ 50 | exponent = -exponent; 51 | pow = 1/PowerUnsigned(base, exponent); 52 | } 53 | return pow; 54 | } 55 | /* 方法1:常规法 56 | double PowerUnsigned(double base, int exponent){ 57 | double pow = 1; 58 | for(int i=1;i<=exponent;++i){ 59 | pow *= base; 60 | } 61 | return pow; 62 | } 63 | }*/ 64 | /*方法2:递归法*/ 65 | double PowerUnsigned(double base, int exponent){ 66 | // 递归中值条件 67 | if(exponent==0) 68 | return 1; 69 | if(exponent==1) 70 | return base; 71 | double pow = PowerUnsigned(base, exponent>>1); // >>1 右移表示除以2 72 | pow *=pow; 73 | if(exponent & 0x1==1) // 判断基偶数 74 | pow *= base; 75 | return pow; 76 | } 77 | 78 | bool JudgeSmallNumber(double base){ 79 | if(abs(base - 0.0)< 0.0000001) 80 | return true; 81 | else 82 | return false; 83 | } 84 | }; 85 | ``` 86 | 87 | [Python](Power.py) 88 | 89 | ```python 90 | # -*- coding:utf-8 -*- 91 | class Solution: 92 | def Power(self, base, exponent): 93 | # write code here 94 | baseSmallFlag = False 95 | pow = 0 96 | baseSmallFlag = self.JudgeSmall(base) 97 | if baseSmallFlag and exponent==0: 98 | return 0 99 | if exponent ==0: 100 | return 1 101 | if exponent > 0: 102 | pow = self.PowerUnsigned(base, exponent) 103 | else: 104 | exponent = abs(exponent) 105 | pow = 1/self.PowerUnsigned(base, exponent) 106 | 107 | return pow 108 | # 计算exponent为正数的情况 109 | def PowerUnsigned(self, base, exponent): 110 | pow = 1 111 | for i in range(exponent): 112 | pow = base*pow 113 | return pow 114 | # 判断base是否很小 115 | def JudgeSmall(self, base): 116 | if(abs(base-0.0)<0.0000001): 117 | return True 118 | else: 119 | return False 120 | ``` 121 | -------------------------------------------------------------------------------- /Coding Interviews/18_SubstructureInTree/README.md: -------------------------------------------------------------------------------- 1 | # 题目描述 2 | 3 | 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构) 4 | 5 | # 解题思路 6 | 7 | 此题考查[二叉树](https://github.com/amusi/coding-note/blob/master/Coding%20Interviews/06_ConstructBinaryTree/Binarytree.md)知识点。 8 | 9 | 假设输入两颗二叉树的根结点分别是是pRoot1和pRoot2。 10 | 11 | **方法:递归法** 12 | 13 | 先在pRoot1中找到与pRoot2根结点数值相同的结点,然后判断该结点以下的结构与pRoot2是否一致。 14 | 15 | 如何找到相同的结点呢?那就需要遍历二叉树了。 16 | 17 | 如何遍历二叉树呢?那就分别从左子树和右子树开始遍历。 18 | 19 | 此题的关键点在于使用“递归法”和对二叉树遍历的理解(左子树和右子树)。 20 | 21 | 注:递归法真的很重要!很重要!编写的时候一定要搞清楚输入是什么,输出是什么?以及何时停止问题。 22 | 23 | 扩展知识点:二叉树的三种遍历方法(前序遍历、中序遍历和后序遍历) 24 | 25 | # 代码 26 | 27 | [C++](SubstructureInTree.cpp) 28 | 29 | 递归法 30 | 31 | ```c++ 32 | /* 33 | struct TreeNode { 34 | int val; 35 | struct TreeNode *left; 36 | struct TreeNode *right; 37 | TreeNode(int x) : 38 | val(x), left(NULL), right(NULL) { 39 | } 40 | };*/ 41 | class Solution { 42 | public: 43 | // 判断pRoot2是不是pRoot1的子结构 44 | // 递归法: 先在pRoot1中找到与pRoot2根结点数值相同的结点,然后判断该结点以下的结构与pRoot2是否一致 45 | bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) 46 | { 47 | bool result = false; 48 | if(pRoot1!=NULL && pRoot2!=NULL){ 49 | // 从pRoot1中查找与pRoot2根结点相同的值 50 | if(pRoot1->val == pRoot2->val){ 51 | result = DoesTree1HaveTree2(pRoot1, pRoot2); // 找到啦 52 | // 从右树开始找 53 | if(!result) 54 | result = HasSubtree(pRoot1->left, pRoot2); 55 | // 从左树开始找 56 | if(!result) 57 | result = HasSubtree(pRoot1->right, pRoot2); 58 | } 59 | } 60 | return result; 61 | } 62 | // 判断pRoot2是不是pRoot1的子树 63 | bool DoesTree1HaveTree2(TreeNode* pRoot1, TreeNode* pRoot2){ 64 | if(pRoot2==NULL) 65 | return true; // 遍历完pRoot2的所有结点 66 | if(pRoot1==NULL) 67 | return false; 68 | if(pRoot1->val != pRoot2->val) 69 | return false; 70 | 71 | return DoesTree1HaveTree2(pRoot1->left, pRoot2->left) && DoesTree1HaveTree2(pRoot1->right, pRoot2->right); 72 | } 73 | }; 74 | ``` 75 | 76 | 77 | 78 | [Python](SubstructureInTree.py) 79 | 80 | 递归法 81 | 82 | ```python 83 | # -*- coding:utf-8 -*- 84 | # class TreeNode: 85 | # def __init__(self, x): 86 | # self.val = x 87 | # self.left = None 88 | # self.right = None 89 | class Solution: 90 | # 递归法 91 | def HasSubtree(self, pRoot1, pRoot2): 92 | '''判断pRoot2是不是pRoot1的子树''' 93 | result = False 94 | if pRoot1!=None and pRoot2!=None: 95 | if pRoot1.val==pRoot2.val: 96 | result = self.DoesTree1HaveTree2(pRoot1, pRoot2) 97 | if result == False: 98 | result = self.HasSubtree(pRoot1.left, pRoot2) # 判断左子树 99 | if result == False: 100 | result = self.HasSubtree(pRoot1.right, pRoot2) # 判断右子树 101 | 102 | return result 103 | 104 | def DoesTree1HaveTree2(self, pRoot1, pRoot2): 105 | '''判断pRoot2是不是pRoot1的子树''' 106 | if pRoot2==None: 107 | return True 108 | if pRoot1==None: 109 | return False 110 | if pRoot1.val != pRoot2.val: 111 | return False 112 | 113 | return self.DoesTree1HaveTree2(pRoot1.left,pRoot2.left) and self.DoesTree1HaveTree2(pRoot1.right,pRoot2.right) 114 | ``` 115 | 116 | # 参考 117 | 118 | https://www.nowcoder.com/questionTerminal/6e196c44c7004d15b1610b9afca8bd88 -------------------------------------------------------------------------------- /Coding Interviews/21_MinInStack/README.md: -------------------------------------------------------------------------------- 1 | # 题目描述 2 | 3 | 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数。在该栈中,调用min、push及pop的时间复杂度都是O(1)。 4 | 5 | # 解题思路 6 | 7 | 考查知识点: 8 | 9 | - [栈(Stack)知识点](https://github.com/amusi/coding-note/blob/master/Coding%20Interviews/07_QueueWithTwoStacks/QueueStack.md) 10 | - [C++ STL::Stack用法](http://www.cplusplus.com/reference/stack/stack/) 11 | - [Python list用法](https://docs.python.org/3.8/c-api/list.html) 12 | 13 | **方法1:数据栈和辅助栈相同容量** 14 | 15 | TODO:待添加描述 16 | 17 | 缺点: 随着压入栈内的元素增多,占用的"不必要"内存较大。如压入3,4,5,5,6...共n个非减的序列,其实最小值一直是3,如果利用方法2,那么辅助栈只需要保存一个元素3即可。但若使用方法一,则需要多存储n-1个元素。 18 | 19 | **方法2:数据栈容量大于辅助栈容量** 20 | 21 | TODO:待添加描述 22 | 23 | 24 | 25 | # 代码 26 | 27 | [C++](MinInStack.cpp):方法1 28 | 29 | ```c++ 30 | class Solution { 31 | public: 32 |     // 题目描述: 包含min函数的栈 33 | // 方法: 34 | // 自定义两个栈 35 | stack dataStack; // 数据栈 36 | stack helpStack; // 辅助栈 37 | 38 | // 压入元素 O(1) 39 |     void push(int value) { 40 | dataStack.push(value); 41 | if (helpStack.empty()){ 42 | helpStack.push(value); 43 | }else{ 44 | if(value < helpStack.top()){ 45 | helpStack.push(value); 46 | }else{ 47 | helpStack.push(helpStack.top()); 48 | } 49 | } 50 |     } 51 |      52 | // 弹出元素 O(1) 53 |     void pop() { 54 | if(dataStack.empty() || helpStack.empty()) 55 | return; 56 | dataStack.pop(); 57 | helpStack.pop(); 58 |     } 59 | // 返回栈顶元素 O(1) 60 |     int top() { 61 | return dataStack.top(); 62 |     } 63 |      64 | // 返回栈中最小元素 O(1) 65 |     int min() { 66 | return helpStack.top(); 67 |     } 68 |       69 | }; 70 | ``` 71 | 72 | 方法2: 73 | 74 | ```c++ 75 | class Solution { 76 | public: 77 |       78 |     stack stack1,stack2; 79 |       80 |     void push(int value) { 81 |         stack1.push(value); 82 |         if(stack2.empty()) 83 |             stack2.push(value); 84 |         else if(value<=stack2.top()) 85 |         { 86 |             stack2.push(value); 87 |         } 88 |     } 89 |       90 |     void pop() { 91 | // 判断两个栈顶元素是否相等 92 |         if(stack1.top()==stack2.top()) 93 |             stack2.pop(); 94 |         stack1.pop(); 95 |           96 |     } 97 |       98 |     int top() { 99 |         return stack1.top();        100 |     } 101 |       102 |     int min() { 103 |         return stack2.top(); 104 |     } 105 |       106 | }; 107 | ``` 108 | 109 | 110 | 111 | [Python](MinInStack.py):方法2 112 | 113 | ```python 114 | # -*- coding:utf-8 -*- 115 | class Solution: 116 | 117 | def __init__(self): 118 | self.data_stack = [] 119 | self.help_stack = [] 120 | # 压入新元素 121 | def push(self, node): 122 | self.data_stack.append(node) 123 | if len(self.help_stack)==0: 124 | self.help_stack.append(node) 125 | else: 126 | if node < self.help_stack[-1]: 127 | self.help_stack.append(node) 128 | else: 129 | self.help_stack.append(self.help_stack[-1]) 130 | # 弹出栈顶元素 131 | def pop(self): 132 | self.data_stack.pop() 133 | self.help_stack.pop() 134 | 135 | # 返回栈顶元素 136 | def top(self): 137 | return self.data_stack[-1] 138 | 139 | # 返回当前栈中最小元素 140 | def min(self): 141 | return self.help_stack[-1] 142 | ``` 143 | 144 | # 参考 145 | 146 | https://www.nowcoder.com/questionTerminal/4c776177d2c04c2494f2555c9fcc1e49 -------------------------------------------------------------------------------- /Coding Interviews/15_KthNodeFromEnd/README.md: -------------------------------------------------------------------------------- 1 | # 题目描述 2 | 3 | 输入一个链表,输出该链表中倒数第k个结点。 4 | 5 | # 解题思路 6 | 7 | 此题考查[链表](https://github.com/amusi/coding-note/blob/master/Coding%20Interviews/05_PrintListInReversedOrder/Linkedlist.md)知识点。题目很简短,就是要输出链表中倒数第k个结点,方法有很多,下面介绍两种常见的方法。 8 | 9 | 注:输出的是结点,而不是结点的value,所以用Python的童鞋不要以为转换成列表,再用list[-k]就可以解决这个问题哦。 10 | 11 | **方法1(根据链表长度再计算):** 12 | 13 | 1. 计算出链表的长度 length 14 | 2. 利用链表list_k,初始情况下,指向输入链表的pListHead,然后移动 length-k位。此时list_k即处于倒数第k个结点的位置。 15 | 16 | 如链表的长度为100,我们需要输出倒数第7个结点,即需要移动 93 = 100-7位,当前节点即处于倒数第7个结点的位置,实质上是正数第94个节点的位置。为什么是94呢?因为每次移动后,list_k=list_k.next。 17 | 18 | **方法2(经典双指针思想:快慢指针):** 19 | 20 | 1. 利用两个链表指针,ListNode *nodePre和 ListNode *nodeLast,初始情况下,两者都是指向输入链表pListHead。 21 | 2. | k-1 -------->| nodePre 领先 nodeLast k-1 步出发 22 | 3. |---------> k-1 | nodePre和 nodeLast一起出发,当 nodePre先到达终点时,nodeLast正好距终点有k-1个节点,而它本身处于倒数第k个结点处。 23 | 24 | # 代码 25 | 26 | [C++](KthNodeFromEnd.cpp) 27 | 28 | ```c++ 29 | /* 30 | struct ListNode { 31 | int val; 32 | struct ListNode *next; 33 | ListNode(int x) : 34 | val(x), next(NULL) { 35 | } 36 | };*/ 37 | class Solution { 38 | public: 39 | ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) { 40 | /*方法2(经典双指针思想:快慢指针)*/ 41 | // 思路: 作者:bigpo 42 | // 链接:https://www.nowcoder.com/questionTerminal/529d3ae5a407492994ad2a246518148a 43 | // | k-1 -------->| nodePre 领先 nodeLast k-1 步出发 44 |         // |---------> k-1 | 当nodePre先到达终点时,nodeLast正好距终点有k-1个节点,而它本身处于倒数第k个节点处 45 | 46 | // 输入判断 47 | if(pListHead==NULL || k==0) 48 | return NULL; 49 | 50 | ListNode *pTail = pListHead, *pHead = pListHead; 51 | // pHead先走 k-1步 52 | for(int i=1;inext!=NULL) 54 | pHead = pHead->next; 55 | else 56 | return NULL; 57 | } 58 | // pHead和pTail同时走,最后pTail还差k-1步才能走到最后,即pTail当前是倒数第k个结点。 59 | while(pHead->next!=NULL){ 60 | pHead = pHead->next; 61 | pTail = pTail->next; 62 | } 63 | return pTail; 64 | 65 | /* 方法1(根据链表长度再计算) 66 | // 缺点:计算量大,无论如何遍历整个链表 67 | if(pListHead==NULL || k==0) 68 | return NULL; 69 | unsigned int length = 0; 70 | ListNode *ln = pListHead; 71 | // 计算链表长度 72 | while(ln!=NULL){ 73 | ++length; 74 | ln = ln->next; 75 | } 76 | if(lengthnext; 82 | } 83 | return ln2;*/ 84 | 85 | } 86 | }; 87 | ``` 88 | 89 | [Python](KthNodeFromEnd.py) 90 | 91 | ```python 92 | # -*- coding:utf-8 -*- 93 | # class ListNode: 94 | # def __init__(self, x): 95 | # self.val = x 96 | # self.next = None 97 | 98 | class Solution: 99 | def FindKthToTail(self, head, k): 100 | # write code here 101 | # 输入判断 102 | if(head==None or k==0): 103 | return None 104 | 105 | pHead = head; 106 | pTail = head; 107 | # pHead先走 k-1步 108 | for i in range(1, k): 109 | if pHead.next!=None: 110 | pHead = pHead.next 111 | else: 112 | return None; 113 | # pHead和pTail同时走,最后pTail还差k-1步才能走到最后,即pTail当前是倒数第k个结点。 114 | while(pHead.next!=None): 115 | pHead = pHead.next 116 | pTail = pTail.next 117 | 118 | return pTail 119 | ``` 120 | 121 | # 参考 122 | 123 | https://www.nowcoder.com/questionTerminal/529d3ae5a407492994ad2a246518148a -------------------------------------------------------------------------------- /Coding Interviews/19_MirrorOfBinaryTree/README.md: -------------------------------------------------------------------------------- 1 | # 题目描述 2 | 3 | 操作给定的二叉树,将其变换为源二叉树的镜像。 4 | 5 | 输入描述: 6 | 7 | ``` 8 | 二叉树的镜像定义: 9 | 源二叉树 10 | 8 11 | / \ 12 | 6 10 13 | / \ / \ 14 | 5 7 9 11 15 | 16 | 镜像二叉树 17 | 8 18 | / \ 19 | 10 6 20 | / \ / \ 21 | 11 9 7 5 22 | ``` 23 | 24 | # 解题思路 25 | 26 | 此题考查[二叉树](https://github.com/amusi/coding-note/blob/master/Coding%20Interviews/06_ConstructBinaryTree/Binarytree.md)知识点。 27 | 28 | **递归法:** 29 | 30 | 我们先前序遍历这棵树的每个结点,如果遍历到的结点有子结点,就交换它的两个子结点(交换两个子结点的写法和交换两个变量值的思路是一样的,设置一个中间变量即可)。当交换完所有非叶子结点的左右子结点后,就得到了数的镜像。 31 | 32 | 注:但遍历到叶子结点后,不需要做任何处理(这个思想很关键)。 33 | 34 | 这里就不详细展开描述,下面放一幅手绘图像,简单说明。 35 | 36 | ![图示](MirrorOfBinaryTree.png) 37 | 38 | 如何找到相同的结点呢?那就需要遍历二叉树了。 39 | 40 | 如何遍历二叉树呢?那就分别从左子树和右子树开始遍历。 41 | 42 | 此题的关键点在于使用“递归法”和对二叉树遍历的理解(左子树和右子树)。 43 | 44 | 注:递归法真的很重要!很重要!编写的时候一定要搞清楚输入是什么,输出是什么?以及何时停止问题。 45 | 46 | 扩展知识点:二叉树的三种遍历方法(前序遍历、中序遍历和后序遍历) 47 | 48 | # 代码 49 | 50 | [C++](SubstructureInTree.cpp) 51 | 52 | 递归法 53 | 54 | ```c++ 55 | /* 56 | struct TreeNode { 57 | int val; 58 | struct TreeNode *left; 59 | struct TreeNode *right; 60 | TreeNode(int x) : 61 | val(x), left(NULL), right(NULL) { 62 | } 63 | };*/ 64 | class Solution { 65 | public: 66 | // 思路: 左右非子结点互换 67 | // 递归法 68 | void Mirror(TreeNode *pRoot) { 69 | // 判断输入是不是空树 70 | if(pRoot == NULL) 71 | return; 72 | // 判断是不是遍历到了叶子结点(叶子结点无子结点) 73 | if(pRoot->left==NULL && pRoot->right==NULL) 74 | return; 75 | // 交换非叶子结点 76 | TreeNode *pTemp = pRoot->left; 77 | pRoot->left = pRoot->right; 78 | pRoot->right = pTemp; 79 | 80 | // 如果是非叶子结点,则继续递归 81 | if(pRoot->left!=NULL) 82 | Mirror(pRoot->left); 83 | if(pRoot->right!=NULL) 84 | Mirror(pRoot->right); 85 | 86 | } 87 | }; 88 | ``` 89 | 90 | 循环法(非递归法) 91 | 92 | ```c++ 93 | /* 94 | struct TreeNode { 95 | int val; 96 | struct TreeNode *left; 97 | struct TreeNode *right; 98 | TreeNode(int x) : 99 | val(x), left(NULL), right(NULL) { 100 | } 101 | };*/ 102 | class Solution { 103 | public: 104 | // 思路: 左右非子结点互换 105 | void Mirror(TreeNode *pRoot) { 106 | // 循环法(非递归) 107 | if(pRoot==NULL) 108 |          return; 109 |      stack stackNode; 110 |      stackNode.push(pRoot); 111 |      while(stackNode.size()){ 112 |          TreeNode* tree=stackNode.top(); 113 |          stackNode.pop(); 114 |         if(tree->left!=NULL || tree->right!=NULL){ 115 |          TreeNode *ptemp=tree->left; 116 |             tree->left=tree->right; 117 |              tree->right=ptemp; 118 |          } 119 |         if(tree->left) 120 |              stackNode.push(tree->left); 121 |          if(tree->right) 122 |              stackNode.push(tree->right); 123 |      } 124 | } 125 | }; 126 | ``` 127 | 128 | 129 | 130 | [Python](SubstructureInTree.py) 131 | 132 | 递归法 133 | 134 | ```python 135 | # -*- coding:utf-8 -*- 136 | # class TreeNode: 137 | # def __init__(self, x): 138 | # self.val = x 139 | # self.left = None 140 | # self.right = None 141 | class Solution: 142 | # 返回镜像树的根节点 143 | def Mirror(self, root): 144 | # write code here 145 | if root==None: 146 | return 147 | #(可选) 判断是不是叶子结点 148 | if root.left==None and root.right==None: 149 | return 150 | # 交换非叶子结点 151 | temp = root.left 152 | root.left = root.right 153 | root.right = temp 154 | # 如果不是非叶子结点,继续递归 155 | if root.left!=None: 156 | self.Mirror(root.left) 157 | if root.right!=None: 158 | self.Mirror(root.right) 159 | ``` 160 | 161 | # 参考 162 | 163 | https://www.nowcoder.com/questionTerminal/6e196c44c7004d15b1610b9afca8bd88 -------------------------------------------------------------------------------- /Coding Interviews/20_PrintMatrix/README.md: -------------------------------------------------------------------------------- 1 | # 题目描述 2 | 3 | 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10. 4 | 5 | # 解题思路 6 | 7 | **方法1:圈圈打印法** 8 | 9 | 我们可以把矩阵想象成若干个圈。于是可以通过一个循环来打印矩阵,每一次打印矩阵中的一个圈。 10 | 11 | 这种方法比较容易想到,很直观。但难度在于设定循环的限制条件,如: 12 | 13 | 1. 每次打印一个圈,那么什么时候停止打印呢? 14 | 2. 打印一个圈的时候,该圈到哪里就停止了呢? 15 | 16 | 接下来分析第一个问题:分析循环结束的条件。假设这个矩阵的行数是rows,列数是columns。打印第一圈的左上角的坐标是(0,0),第二圈的左上角的坐标是(1,1),依次类推。我们注意到,左上角的坐标中行标和列标总是相同的,于是在矩阵中选取左上角为(start, start)的一圈作为我们分析的目标。 17 | 18 | 参考:《剑指Offer》p128 19 | 20 | 第二个问题:如何打印一个圈,停止条件是什么? 21 | 22 | 这里,我就不赘述,因为这是最核心的问题,其实看了下面图像,稍微比划着也就知道如何打印了。但要注意的是,打印一个圈,不一定有多个元素,也许就一个元素,所以要注意条件。 23 | 24 | ![](PrintMatrix.png) 25 | 26 | **方法2:旋转矩阵法** 27 | 28 | 该方法技巧性很足,请参考下面的Python代码好好体会,这里不赘述。 29 | 30 | # 代码 31 | 32 | [C++](PrintMatrix.cpp):方法1 33 | 34 | ```c++ 35 | class Solution { 36 | public: 37 | // 思路: 38 | vector printMatrix(vector > matrix) { 39 | if (matrix.size()==0) 40 | return matrix[0]; 41 | vector> resultMatrixTemp; 42 | vector resultMatrix; // 最终输出值 43 | int rows = matrix.size(); // 矩阵行数 44 | int columns = matrix[0].size(); // 矩阵列数 45 | // 设置起始位置 46 | int start = 0; // start = start_x = start_y 47 | //resultMatrix.resize(rows*columns); 48 | // 根据关系式判断 49 | while(columns > 2*start && rows > 2*start){ 50 | resultMatrixTemp.push_back(printMatrixInCircle(matrix, start)); 51 | ++start; 52 | } 53 | for(int i=0; i printMatrixInCircle(vector >matrix, int start){ 62 | if (matrix.size()==0) 63 | return resultMatrix; 64 | vector resultMatrix; 65 | int rows = matrix.size(); 66 | int columns = matrix[0].size(); 67 | 68 | int endX = columns-1-start; // 水平方向终点 69 | int endY = rows-1-start; // 垂直方向终点 70 | // 从左到右打印一行(行不变) 71 | for(int i=start; i<=endX; ++i){ 72 | int number = matrix[start][i]; 73 | resultMatrix.push_back(number); 74 | } 75 | // 从上到下打印一列(列不变) 76 | if(start < endY){ 77 | for(int i=start+1; i<=endY; ++i){ 78 | int number = matrix[i][endX]; 79 | resultMatrix.push_back(number); 80 | } 81 | } 82 | // 从右到左打印一行(行不变) 83 | if(start < endX && start < endY){ 84 | for(int i=endX-1; i>=start; i--){ 85 | int number = matrix[endY][i]; 86 | resultMatrix.push_back(number); 87 | } 88 | } 89 | // 从下到上打印一列(列不变) 90 | if(start < endX && start < endY-1){ 91 | for(int i=endY-1; i>=start+1; i--){ 92 | int number = matrix[i][start]; 93 | resultMatrix.push_back(number); 94 | } 95 | } 96 | return resultMatrix; 97 | } 98 | }; 99 | ``` 100 | 101 | 102 | 103 | [Python](PrintMatrix.py):方法2 104 | 105 | ```python 106 | # -*- coding:utf-8 -*- 107 | class Solution: 108 | # matrix类型为二维列表,需要返回列表 109 | def printMatrix(self, matrix): 110 | # write code here 111 | result = [] 112 | while(matrix): 113 | result+=matrix.pop(0) 114 | if not matrix or not matrix[0]: 115 | break 116 | matrix = self.turn(matrix) 117 | return result 118 | def turn(self,matrix): 119 | num_r = len(matrix) # 矩阵行数 120 | num_c = len(matrix[0]) # 矩阵列数 121 | newmat = [] 122 | for i in range(num_c): 123 | newmat2 = [] 124 | for j in range(num_r): 125 | newmat2.append(matrix[j][i]) 126 | newmat.append(newmat2) 127 | newmat.reverse() 128 | return newmat 129 | ``` 130 | 131 | # 参考 132 | 133 | https://www.nowcoder.com/questionTerminal/9b4c81a02cd34f76be2659fa0d54342a 134 | 135 | https://www.nowcoder.com/ta/coding-interviews/question-ranking?uuid=9b4c81a02cd34f76be2659fa0d54342a&rp=1 -------------------------------------------------------------------------------- /Coding Interviews/17_MergeSortedLists/README.md: -------------------------------------------------------------------------------- 1 | # 题目描述 2 | 3 | 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。 4 | 5 | # 解题思路 6 | 7 | 此题考查[链表](https://github.com/amusi/coding-note/blob/master/Coding%20Interviews/05_PrintListInReversedOrder/Linkedlist.md)知识点。 8 | 9 | 假设输入两个链表的头结点分别是是ListNode1和ListNode2。 10 | 11 | **方法1:非递归法** 12 | 13 | 非递归法就是新建一个合并链表的头结点pHead,然后将空链表**指向**两个链表中头结点较小的链表(注意这里是指向的思想)。然后再新建一个头结点pCur,其初始化时指向pHead。pCur的目的是不断地给合并链表添加新的结点,因为pHead是头结点,并不能移动(这里试想一下每次移动pHead的后果...)。 14 | 15 | 每次向合并链表添加新的结点,该新结点其实就是**当前**ListNode1和ListNode2中的最小结点。注意这里为什么要用当前,因为每次添加完结点后,ListNode1或ListNode2都要移向下一个结点。如当前ListNode1的结点值比ListNode2的结点值小,那么就应该是pCur->next = ListNode1,然后ListNode1 = ListNode1->next。 16 | 17 | 那么什么时候停止添加新结点呢? 18 | 19 | 答:直到某一个链表的结点全部被遍历时,此刻再将另一个链表剩余的结点添加至合并链表后面即可。 20 | 21 | 注:添加新结点就等价于链表的尾节点指向新结点。 22 | 23 | **方法2:递归法** 24 | 25 | 递归法真的很重要,很考验思维能力和coding,下面提供了C++版本,还有Python版本的递归法实现代码。这里就不赘述(因为很难描述)。 26 | 27 | 注:递归要搞清楚输入是什么,输出是什么?以及何时停止问题。 28 | 29 | # 代码 30 | 31 | [C++](MergeSortedLists.cpp) 32 | 33 | 方法1:非递归法 34 | 35 | ```c++ 36 | /* 37 | struct ListNode { 38 | int val; 39 | struct ListNode *next; 40 | ListNode(int x) : 41 | val(x), next(NULL) { 42 | } 43 | };*/ 44 | class Solution { 45 | public: 46 | // 方法1:常规法 47 | ListNode* Merge(ListNode* pHead1, ListNode* pHead2) 48 | { 49 | // 输入判断 50 | if(pHead1==NULL && pHead2==NULL){ 51 | return NULL; 52 | } 53 | if(pHead1==NULL) 54 | return pHead2; 55 | if(pHead2==NULL) 56 | return pHead1; 57 | // 不确定下面初始化要不要赋值NULL 58 | ListNode* pHead=NULL; // 输出的合成链表(头结点) 59 | ListNode* pCur=NULL; // 指向输出的合成链表(移动结点) 60 | // 初始化pHead 61 | if(pHead1->val<=pHead2->val){ 62 | pHead = pHead1; 63 | pHead1 = pHead1->next; 64 | }else{ 65 | pHead = pHead2; 66 | pHead2 = pHead2->next; 67 | } 68 | pCur = pHead; // 指向链表的头结点 69 | // 给链表添加新结点(单调不减) 70 | while(pHead1!=NULL && pHead2!=NULL){ 71 | if(pHead1->val<=pHead2->val){ 72 | pCur->next = pHead1; 73 | pHead1 = pHead1->next; 74 | }else{ 75 | pCur->next = pHead2; 76 | pHead2 = pHead2->next; 77 | } 78 | pCur = pCur->next; 79 | } 80 | // 将某链表剩余的结点添加到合并链表的后面 81 | if(pHead1==NULL){ 82 | pCur->next = pHead2; 83 | }else{ 84 | pCur->next = pHead1; 85 | } 86 | // 返回单调不减的合并链表 87 | return pHead; 88 | } 89 | } 90 | ``` 91 | 92 | 版本2:递归法 93 | 94 | ```c++ 95 | /* 96 | struct ListNode { 97 | int val; 98 | struct ListNode *next; 99 | ListNode(int x) : 100 | val(x), next(NULL) { 101 | } 102 | };*/ 103 | class Solution { 104 | public: 105 | /* 方法2:递归法*/ 106 | ListNode* Merge(ListNode* pHead1, ListNode* pHead2) 107 | { 108 | // 输入判断 109 | if(pHead1==NULL && pHead2==NULL){ 110 | return NULL; 111 | } 112 | if(pHead1==NULL) 113 | return pHead2; 114 | if(pHead2==NULL) 115 | return pHead1; 116 | 117 | ListNode* pHead=NULL; 118 | if(pHead1->val <= pHead2->val){ 119 | pHead = pHead1; 120 | pHead->next = Merge(pHead1->next, pHead2); 121 | } else { 122 | pHead = pHead2; 123 | pHead->next = Merge(pHead1, pHead2->next); 124 | } 125 | 126 | return pHead; 127 | } 128 | }; 129 | ``` 130 | 131 | [Python](MergeSortedLists.py) 132 | 133 | 版本2:递归法 134 | 135 | ```python 136 | # -*- coding:utf-8 -*- 137 | # class ListNode: 138 | # def __init__(self, x): 139 | # self.val = x 140 | # self.next = None 141 | class Solution: 142 | # 返回合并后列表 143 | def Merge(self, pHead1, pHead2): 144 | # write code here 145 | # 递归法 146 | if pHead1==None: 147 | return pHead2 148 | if pHead2==None: 149 | return pHead1 150 | 151 | if pHead1.val <= pHead2.val: 152 | pHead1.next = self.Merge(pHead1.next, pHead2) 153 | return pHead1 154 | 155 | if pHead2.val < pHead1.val: 156 | pHead2.next = self.Merge(pHead1, pHead2.next) 157 | return pHead2 158 | ``` 159 | 160 | # 参考 161 | 162 | https://www.nowcoder.com/questionTerminal/d8b6b4358f774294a89de2a6ac4d9337 -------------------------------------------------------------------------------- /Coding Interviews/README.md: -------------------------------------------------------------------------------- 1 | # 剑指Offer 2 | 3 | ## **Contents** 4 | 5 | ------ 6 | 7 | ### **第01-10题** 8 | 9 | ------ 10 | 11 | - [x] **【面试题03:二维数组中的查找】** [FindInPartiallySortedMatrix](03_FindInPartiallySortedMatrix/README.md) 12 | 13 | - [x] **【面试题04:替换空格】** [ReplaceBlank](04_ReplaceBlank/README.md) 14 | 15 | - [x] **【面试题05:从尾到头打印链表】** [PrintListInReversedOrder](05_PrintListInReversedOrder) 16 | 17 | - [x] **【面试题06:重建二叉树】** [ConstructBinaryTree](06_ConstructBinaryTree) 18 | 19 | - [x] **【面试题07:用两个栈实现队列】** [QueueWithTwoStacks](07_QueueWithTwoStacks) 20 | 21 | - [x] **【面试题08:旋转数组的最小数字】** [MinNumberInRotatedArray](08_MinNumberInRotatedArray) 22 | 23 | - [x] **【面试题09:斐波那契数列】** [Fibonacci](09_Fibonacci) 24 | 25 | - [x] **【面试题10:二进制中1 的个数】** [NumberOf1InBinary](10_NumberOf1InBinary) 26 | 27 | 28 | ### **第11-20题** 29 | 30 | ------ 31 | 32 | - [x] **【面试题11:数值的整数次方】** [Power](11_Power) 33 | 34 | - [ ] **【面试题12:打印1 到最大的n 位数】** 35 | 36 | - [ ] **【面试题13:在O(1)时间删除链表结点】** 37 | 38 | - [x] **【面试题14:调整数组顺序使奇数位于偶数前面】** [ReorderArray](14_ReorderArray) 39 | 40 | - [x] **【面试题15:链表中倒数第k个结点】** [KthNodeFromEnd](15_KthNodeFromEnd) 41 | 42 | - [x] **【面试题16:反转链表】** [ReverseList](16_ReverseList) 43 | 44 | - [x] **【面试题17:合并两个排序的链表】** [MergeSortedLists](17_MergeSortedLists) 45 | 46 | - [x] **【面试题18:树的子结构】** [SubstructureInTree](18_SubstructureInTree) 47 | 48 | - [x] **【面试题19:二叉树的镜像】** [MirrorOfBinaryTree](19_MirrorOfBinaryTree) 49 | 50 | - [x] **【面试题20:顺时针打印矩阵】** [PrintMatrix](20_PrintMatrix) 51 | 52 | 53 | ### **第21-30题** 54 | 55 | ------ 56 | 57 | - [x] **【面试题21:包含min函数的钱】** [MinInStack](21_MinInStack) 58 | 59 | - [x] **【面试题22:栈的压入、弹出序列】** [StackPushPopOrder](22_StackPushPopOrder) 60 | 61 | - [ ] **【面试题23:从上往下打印二叉树】** 62 | 63 | - [ ] **【面试题24:二叉搜索树的后序遍历序列】** 64 | 65 | - [ ] **【面试题25:二叉树中和为某一值的路径】** 66 | 67 | - [ ] **【面试题26:复杂链表的复制】** 68 | 69 | - [ ] **【面试题27:二叉搜索树与双向链表】** 70 | 71 | - [ ] **【面试题28:字符串的排列】** 72 | 73 | - [ ] **【面试题29:数组中出现次数超过一半的数字】** 74 | 75 | - [ ] **【面试题30:最小的k个数】** 76 | 77 | 78 | ### **第31-40题** 79 | 80 | ------ 81 | 82 | - [ ] **【面试题31:连续子数组的最大和】** 83 | 84 | - [ ] **【面试题32:求从1到n的整数中1出现的次数】** 85 | 86 | - [ ] **【面试题33:把数组排成最小的数】** 87 | 88 | - [ ] **【面试题34:丑数】** 89 | 90 | - [ ] **【面试题35:第一个只出现一次的字符】** 91 | 92 | - [ ] **【面试题36:数组中的逆序对】** 93 | 94 | - [ ] **【面试题37:两个链表的第一个公共结点】** 95 | 96 | - [ ] **【面试题38:数字在排序数组中出现的次数】** 97 | 98 | - [ ] **【面试题39:二叉树的深度】** 99 | 100 | - [ ] **【面试题40:数组中只出现一次的数字】** 101 | 102 | 103 | ### **第41-50题** 104 | 105 | ------ 106 | 107 | - [ ] **【面试题41:和为s 的两个数字vs 和为s 的连续正数序列】** 108 | 109 | - [ ] **【面试题42:翻转单词顺序vs左旋转字符串】** 110 | 111 | - [ ] **【面试题43 : n 个锻子的点数】** 112 | 113 | - [ ] **【面试题44:扑克牌的顺子】** 114 | 115 | - [ ] **【面试题45:圆圈中最后剩下的数字(约瑟夫环问题)】** 116 | 117 | - [ ] **【面试题47:不用加减乘除做加法】** 118 | 119 | - [ ] **【面试题49:把字符串转换成整数】** 120 | 121 | - [ ] **【面试题50:树中两个结点的最低公共祖先】** 122 | 123 | 124 | ### **第51-60题** 125 | 126 | ------ 127 | 128 | - [ ] **【面试题51:数组中重复的数字】** 129 | 130 | - [ ] **【面试题52:构建乘积数组】** 131 | 132 | - [ ] **【面试题53:正则表达式匹配】** 133 | 134 | - [ ] **【面试题54:表示数值的字符串】** 135 | 136 | - [ ] **【面试题55:字符流中第一个不重复的字符】** 137 | 138 | - [ ] **【面试题56:链表中环的入口结点】** 139 | 140 | - [ ] **【面试题57:删除链表中重复的结点】** 141 | 142 | - [ ] **【面试题58:二叉树的下一个结点】** 143 | 144 | - [ ] **【面试题59:对称的二叉树】** 145 | 146 | - [ ] **【面试题60:把二叉树打印出多行】** 147 | 148 | 149 | ### **第61-67题** 150 | 151 | ------ 152 | 153 | - [ ] **【面试题61:按之字形顺序打印二叉树】** 154 | 155 | - [ ] **【面试题62:序列化二叉树】** 156 | 157 | - [ ] **【面试题63:二叉搜索树的第k个结点】** 158 | 159 | - [ ] **【面试题64:数据流中的中位数】** 160 | 161 | - [ ] **【面试题65:滑动窗口的最大值】** 162 | 163 | - [ ] **【面试题66:矩阵中的路径】** 164 | 165 | - [ ] **【面试题67:机器人的运动范围】** 166 | 167 | 168 | 169 | ## github 170 | 171 | ### C/C++ 172 | 173 | (官方完整版:C/C++版本)[**InterviewQuestions**](http://www.broadview.com.cn/23245) 174 | 175 | (官方非完整版:C/C++版本)**[ChineseCodingInterviewAppendix](https://github.com/zhedahht/ChineseCodingInterviewAppendix)** 176 | 177 | (C/C++版本)[CodingInterviews](https://github.com/gatieme/CodingInterviews) 178 | 179 | [CodingInterviewChinese2](https://github.com/zhedahht/CodingInterviewChinese2) 180 | 181 | ### Python 182 | 183 | - [AlgorithmsByPython](https://github.com/Jack-Lee-Hiter/AlgorithmsByPython) 184 | - [Python-Offer](https://github.com/JushuangQiao/Python-Offer) 185 | 186 | - [interactive-coding-challenges](https://github.com/donnemartin/interactive-coding-challenges) 187 | 188 | **博客:** 189 | 190 | - [剑指offer(第2版)刷题 Python版汇总](https://www.cnblogs.com/yanmk/p/9130681.html) 191 | 192 | - [剑指 Offer - python 题解](https://codingcat.cn/article/57) 193 | 194 | ### JAVA 195 | 196 | (大神:JAVA版本)**[coding-interviews](https://github.com/Wang-Jun-Chao/coding-interviews)** 197 | 198 | (JAVA版本)[剑指offer题解](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/%E5%89%91%E6%8C%87%20offer%20%E9%A2%98%E8%A7%A3.md) 199 | 200 | 201 | 202 | ## Tutorials 203 | 204 | [【剑指Offer学习】【所有面试题汇总】](https://blog.csdn.net/derrantcm/article/details/46887821) 205 | 206 | [牛客网在线刷题](https://www.nowcoder.com/ta/coding-interviews) 207 | 208 | [剑指Offer系列刷题笔记汇总](https://blog.csdn.net/c406495762/article/details/79247243) 209 | 210 | 211 | 212 | -------------------------------------------------------------------------------- /Coding Interviews/05_PrintListInReversedOrder/Linkedlist.md: -------------------------------------------------------------------------------- 1 | # 数据结构—链表 2 | 3 | 链表又称线性表。直观的理解,即所有元素排成了一排!注意是一排!没有分支! 4 | 5 | 链表的常用操作(operation): 6 | 7 | InitList(*L):初始化操作,建立一个空的线性表L 8 | 9 | ListEmpty(L):若线性表为空,返回true,否则返回false。 10 | 11 | ClearList(*L):将线性表清空。 12 | 13 | GetElem(L, i, *e):将线性表L中的第i个位置元素值返回给e。 14 | 15 | LocateElem(L, e):在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在表中序号表示成功;否则,返回0表示失败。 16 | 17 | ListInsert(*L, i, e):在线性表L中的第i个位置插入新元素e。 18 | 19 | ListDelete(*L, i, e):删除线性表L中第i个位置元素,并用e返回其值。 20 | 21 | ListLength(L):返回线性表L对元素个数。 22 | 23 | 24 | 25 | C++ 26 | 27 | LinkList.h 28 | 29 | ```c++ 30 | /******************************************************************* 31 | Summary: 链表 32 | Author: Amusi 33 | Date: 2018-06-11 34 | Reference: https://blog.csdn.net/starstar1992/article/details/59808706 35 | *******************************************************************/ 36 | 37 | 38 | #ifndef _LINKLIST_H 39 | #define _LINKLIST_H 40 | 41 | #include 42 | 43 | // 节点定义 44 | typedef struct node { 45 | int data; 46 | struct node *next; 47 | }NODE; 48 | 49 | 50 | // 链表类定义 51 | class LinkList 52 | { 53 | private: 54 | NODE *head; 55 | public: 56 | LinkList() { head = NULL; } 57 | ~LinkList(); 58 | void clearSqList(); 59 | bool isEmpty() { return head == NULL; } 60 | int Length(); 61 | bool GetElem(int i, int *e); 62 | int LocateElem(int e); 63 | bool PriorElem(int cur_e, int *pre_e); 64 | bool NextElem(int cur_e, int *next_e); 65 | bool Insert(int i, int e); 66 | bool Delete(int i, int *e); 67 | NODE * Reverse(); 68 | }; 69 | 70 | //析构函数 71 | LinkList::~LinkList()//和清空一样 72 | { 73 | NODE *p = head; 74 | while (head) 75 | { 76 | p = head; 77 | head = head->next; 78 | delete(p); 79 | } 80 | } 81 | 82 | // 清空函数 83 | void LinkList::clearSqList()//清空函数,和析构一样 84 | { 85 | NODE *p = head; 86 | while (head) 87 | { 88 | p = head; 89 | head = head->next; 90 | delete(p); 91 | } 92 | } 93 | 94 | //获取链表长度 95 | int LinkList::Length() 96 | { 97 | NODE *p = head; 98 | int len = 0; 99 | while (p != NULL) 100 | { 101 | len++; 102 | p = p->next; 103 | } 104 | return len; 105 | } 106 | 107 | // 获取指定位置的元素 108 | bool LinkList::GetElem(int i, int *e)//*e是返回的元素 109 | { 110 | NODE *p = head; 111 | int j = 0; 112 | while (p&&j < i) 113 | { 114 | p = p->next; 115 | j++; 116 | } 117 | if (p == NULL) return false; 118 | *e = p->data; 119 | return true; 120 | } 121 | 122 | // 查找元素e在链表什么位置(下标位置,从0开始) 123 | int LinkList::LocateElem(int e) 124 | { 125 | int i = 0; 126 | NODE *p = head; 127 | while (p != NULL) 128 | { 129 | if (p->data == e) 130 | return i; 131 | else p = p->next; 132 | i++; 133 | } 134 | std::cout << "表中不存在指定元素" << std::endl; 135 | exit(1); 136 | } 137 | 138 | // 取上一个元素 139 | bool LinkList::PriorElem(int cur_e, int *pre_e) 140 | { 141 | NODE *p = head; 142 | if (p->data == cur_e) return false;//是头结点,不存在上一个元素 143 | while (p->next != NULL) 144 | { 145 | if (p->next->data == cur_e) 146 | { 147 | *pre_e = p->data; 148 | return true; 149 | } 150 | else 151 | p = p->next; 152 | } 153 | return false;//遍历完不存在或者只有一个头结点 154 | 155 | } 156 | 157 | // 取下一个元素 158 | bool LinkList::NextElem(int cur_e, int *next_e) 159 | { 160 | NODE *p = head; 161 | if (head == NULL || head->next == NULL) return false; 162 | while (p->next != NULL) 163 | { 164 | if (p->data == cur_e) 165 | { 166 | *next_e = p->next->data; 167 | return true; 168 | } 169 | else 170 | p = p->next; 171 | } 172 | return false; 173 | } 174 | 175 | 176 | // 在指定位置插入元素e 177 | bool LinkList::Insert(int i, int e) 178 | { 179 | NODE *p = head, *s; 180 | int j = 0; 181 | if (i == 0) 182 | { 183 | s = (NODE *)new NODE[1]; 184 | s->data = e; 185 | s->next = p; 186 | head = s; 187 | return true; 188 | } 189 | while (p&&j < i - 1) 190 | { 191 | p = p->next; // p沿着链表移动j位 192 | j++; 193 | } 194 | if (p == NULL) 195 | return false;//到队尾了 196 | // 新建节点 197 | s = (NODE *)new NODE[1]; 198 | s->data = e; 199 | s->next = p->next; 200 | p->next = s; // 关键 201 | return true; 202 | } 203 | 204 | 205 | // 删除指定位置的元素,并把删除的元素赋给*e 206 | bool LinkList::Delete(int i, int *e) 207 | { 208 | NODE *p = head, *s; 209 | if (p == NULL) return false; 210 | int j = 0; 211 | if (i == 0) 212 | { 213 | head = head->next; 214 | *e = p->data; 215 | delete p; 216 | p = NULL; 217 | return true; 218 | } 219 | while (p&&j < i - 1) 220 | { 221 | j++; 222 | p = p->next; // p沿着链表移动 223 | } 224 | if (p == NULL) 225 | return false; 226 | s = p->next; 227 | p->next = p->next->next; 228 | *e = s->data; 229 | delete s; 230 | s = NULL; 231 | return true; 232 | } 233 | 234 | //反转一个链表 235 | NODE* LinkList::Reverse() 236 | { 237 | if (head == NULL || head->next == NULL) return head; 238 | NODE *p = head, *q = head->next, *r; 239 | head->next = NULL; 240 | while (q) 241 | { 242 | r = q->next; 243 | q->next = p; 244 | p = q; 245 | q = r; 246 | } 247 | head = p; 248 | return head; 249 | } 250 | 251 | 252 | #endif 253 | 254 | 255 | ``` 256 | 257 | main.cpp 258 | 259 | ```c++ 260 | /******************************************************************* 261 | Summary: 链表 262 | Author: Amusi 263 | Date: 2018-06-11 264 | Reference: https://blog.csdn.net/starstar1992/article/details/59808706 265 | *******************************************************************/ 266 | 267 | 268 | #include 269 | #include "LinkList.h" 270 | using namespace std; 271 | int main() 272 | { 273 | int a = 0; 274 | int *p = &a; 275 | LinkList li; // 初始化链表 276 | li.Insert(0, 5); 277 | li.Insert(1, 4); 278 | li.Insert(2, 12); 279 | li.Insert(3, 5); 280 | li.Insert(3, 6); 281 | li.Insert(1, 7); 282 | cout << "链表长度" << li.Length() << endl; 283 | cout << "各个元素的值是:"; 284 | for (int i = 0; i < li.Length(); i++)//遍历该链表 285 | { 286 | 287 | if (li.GetElem(i, p)) 288 | cout << *p << " "; 289 | } 290 | cout << endl; 291 | cout << "反转后各个元素的值是:"; 292 | NODE* re_li = li.Reverse(); 293 | while (re_li) 294 | { 295 | cout << re_li->data << " "; 296 | re_li = re_li->next; 297 | } 298 | cout << endl; 299 | } 300 | ``` 301 | 302 | Python 303 | 304 | ```python 305 | # coding=utf-8 306 | # Definition for singly-linked list. 307 | class ListNode(): 308 | def __init__(self, x): 309 | self.val = x 310 | self.next = None 311 | 312 | class ListNode_handle: 313 | def __init__(self): 314 | self.cur_node = None 315 | 316 | def add(self, data): 317 | '''从后向前添加元素''' 318 | #add a new node pointed to previous node 319 | node = ListNode(data) 320 | 321 | node.next = self.cur_node 322 | self.cur_node = node 323 | 324 | return node 325 | 326 | def append(self, data): 327 | '''从前向后添加新元素''' 328 | node = ListNode(data) 329 | if self.cur_node == None: 330 | self.cur_node = node # 若为空表,将添加的元素设为第一个元素 331 | else: 332 | current = self.cur_node 333 | while current.next != None: 334 | current = current.next 335 | current.next = node 336 | return self.cur_node 337 | 338 | def print_ListNode(self, node): 339 | while node: 340 | print '\nnode: ', node, ' value: ', node.val, ' next: ', node.next 341 | node = node.next 342 | 343 | def _reverse(self, nodelist): 344 | list = [] 345 | while nodelist: 346 | list.append(nodelist.val) 347 | nodelist = nodelist.next 348 | result = ListNode() 349 | result_handle = ListNode_handle() 350 | for i in list: 351 | result = result_handle.add(i) 352 | return result 353 | 354 | 355 | class Solution: 356 | # 返回从尾部到头部的列表值序列,例如[1,2,3] 357 | def printListFromTailToHead(self, listNode): 358 | # write code here 359 | result = [] 360 | while listNode != None: 361 | result.append(listNode.val) 362 | listNode = listNode.next 363 | result.reverse() 364 | return result 365 | #测试用例: 366 | #{67,0,24,58} 367 | #对应输出应该为:[58,24,0,67] 368 | l1 = ListNode_handle() 369 | l1_list = [67,0,24,58] 370 | for i in l1_list: 371 | l1_node = l1.append(i) 372 | process = Solution() 373 | print process.printListFromTailToHead(l1_node) 374 | ``` 375 | 376 | 377 | 378 | # 参考 379 | 380 | [链表从无到有](https://www.zhihu.com/question/53645056/answer/139083035) 381 | 382 | [数据结构(二):链表](https://zhuanlan.zhihu.com/p/24720029) 383 | 384 | [链表C++实现](https://blog.csdn.net/starstar1992/article/details/59808706) 385 | 386 | [Linked List Problems](http://cslibrary.stanford.edu/105/LinkedListProblems.pdf) 387 | 388 | [Linked List Challenges](https://www.hackerrank.com/domains/data-structures/linked-lists) -------------------------------------------------------------------------------- /LeetCode/README.md: -------------------------------------------------------------------------------- 1 | # LeetCode 2 | 3 | https://leetcode.com/ 4 | 5 | **推荐在中文网来刷**:https://leetcode-cn.com/problemset/all/ 6 | 7 | 注:推荐按tag来刷。如链表,二叉树,回溯,深度宽度优先遍历,图,贪心,动规,数组,哈希表……每个tag由easy到hard,每道题先自己思考,不会的参考了一个开源的解答或者参考Discuss或者博客。开始的时候自己独立思考的时间比较长,后来没了耐心,不会的题目就马上看解答了。 8 | 9 | ## TODO 10 | 11 | - [x] 正式刷题(按tag来刷) 12 | 13 | 14 | ### 数组 15 | 16 | | # | title | 标题 | Code | Difficulty | 17 | | :--: | :--------------------------------------: | :--------------------------------------: | :--------------------------------------: | :--------: | 18 | | 1 | [Two Sum](https://leetcode.com/problems/two-sum/description/) | [两数之和](https://leetcode-cn.com/problems/two-sum/description/) | [C++](code/0001_TwoSum.cpp) [Python](code/0001_TwoSum.py) | 简单(easy) | 19 | | 4 | [Median of Two Sorted Arrays](https://leetcode.com/problems/median-of-two-sorted-arrays/description/) | [两个排序数组的中位数](https://leetcode-cn.com/problems/median-of-two-sorted-arrays/description/) | [C++](code/0004_.MedianofTwoSortedArrays.cpp) Python | 困难(hard) | 20 | | 26 | [Remove Duplicates from Sorted Array](https://oj.leetcode.com/problems/remove-duplicates-from-sorted-array/) | [删除排序数组中的重复项](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/description/) | [C++](code/0026_RemoveDuplicatesFromSortedArray.cpp) [Python](code/0026_RemoveDuplicatesFromSortedArray.py) | 简单(easy) | 21 | | | | | | | 22 | | | | | | | 23 | | | | | | | 24 | | | | | | | 25 | | | | | | | 26 | | | | | | | 27 | | | | | | | 28 | | | | | | | 29 | | | | | | | 30 | | | | | | | 31 | | | | | | | 32 | | | | | | | 33 | | | | | | | 34 | | | | | | | 35 | | | | | | | 36 | | | | | | | 37 | | | | | | | 38 | | | | | | | 39 | | | | | | | 40 | | | | | | | 41 | | | | | | | 42 | | | | | | | 43 | | | | | | | 44 | | | | | | | 45 | | | | | | | 46 | | | | | | | 47 | | | | | | | 48 | | | | | | | 49 | | | | | | | 50 | | | | | | | 51 | | | | | | | 52 | | | | | | | 53 | | | | | | | 54 | | | | | | | 55 | | | | | | | 56 | | | | | | | 57 | | | | | | | 58 | | | | | | | 59 | | | | | | | 60 | | | | | | | 61 | | | | | | | 62 | | | | | | | 63 | | | | | | | 64 | | | | | | | 65 | | | | | | | 66 | | | | | | | 67 | | | | | | | 68 | | | | | | | 69 | | | | | | | 70 | | | | | | | 71 | | | | | | | 72 | | | | | | | 73 | | | | | | | 74 | | | | | | | 75 | | | | | | | 76 | | | | | | | 77 | 78 | 79 | 80 | ### 其它 81 | 82 | | # | title | 标题 | Code | Difficulty | 83 | | :--: | :--------------------------------------: | :--------------------------------------: | :--------------------------------------: | :--------: | 84 | | 1 | [Two Sum](https://leetcode.com/problems/two-sum/description/) | [两数之和](https://leetcode-cn.com/problems/two-sum/description/) | [C++](code/0001_TwoSum.cpp) [Python](code/0001_TwoSum.py) | 简单(easy) | 85 | | | | | | | 86 | | | | | | | 87 | | | | | | | 88 | | | | | | | 89 | | | | | | | 90 | 91 | 92 | 93 | 94 | 95 | ## github 96 | 97 | ### C/C++ 98 | 99 | - **(推荐)**[haoel/leetcode](https://github.com/haoel/leetcode): 含原 LeetCode题目链接和 C++解决方案 100 | - **(推荐)**[pezy/LeetCode](https://github.com/pezy/LeetCode): LeetCode solutions in C++ 11 and Python3 101 | - **(推荐)**[LeerCode题解](https://legacy.gitbook.com/book/siddontang/leetcode-solution/details):在线题解,分类别,且有PDF 102 | - **(推荐)**[soulmachine/leetcode](https://github.com/soulmachine/leetcode): 含有151道LeetCode题解(C++和JAVA编程语言实现),**附**[LeetCode题解(C++版).pdf](https://github.com/soulmachine/leetcode/raw/master/C%2B%2B/leetcode-cpp.pdf) 103 | - [zhuli19901106/leetcode-2](https://github.com/zhuli19901106/leetcode-2) 104 | 105 | ### Python 106 | 107 | - **(推荐)**[kamyu104/LeetCode](https://github.com/kamyu104/LeetCode-Solutions): Python / C++ 11 Solutions of All 987 LeetCode Problems 108 | - [LeetCode](https://github.com/apachecn/LeetCode) : LeetCode 面试题(中文讲解) 109 | - [pezy/LeetCode](https://github.com/pezy/LeetCode): LeetCode solutions in C++ 11 and Python3 110 | - [LeetCode10Py](https://github.com/veroyatnost/LeetCode10Py): 旨在用10行Python代码解决问题 111 | 112 | ### JAVA 113 | 114 | - [leetcode](https://github.com/gouthampradhan/leetcode): JAVA实现了LeetCode题解,但木有原题目链接 115 | 116 | 117 | 118 | ## Tutorials 119 | 120 | - (官网刷题)https://leetcode.com/ 121 | - (官网中国区刷题)https://leetcode-cn.com/ 122 | - (在线题解,含PDF)[LeerCode题解](https://legacy.gitbook.com/book/siddontang/leetcode-solution/details) 123 | 124 | ### 刷题指南 125 | 126 | [知乎LeetCode话题](https://www.zhihu.com/topic/19925162/hot) 127 | 128 | [Leetcode 分类顺序表](https://cspiration.com/leetcodeClassification) 129 | 130 | -------------------------------------------------------------------------------- /Coding Interviews/07_QueueWithTwoStacks/QueueStack.md: -------------------------------------------------------------------------------- 1 | # 数据结构—栈(Stack) 2 | 3 | ## 栈的定义和基本运算 4 | 5 | 栈(Stack)是一种后进先出(last in first off,LIFO)或先进后出(first in last out,FILO)的数据结构。它还可以理解为运算受限的线性表,其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。 6 | 7 | 注:栈可以看成水杯,先导入水,水慢慢向上积累,再将水倒出来时,最上面的水先出来,这就符合先进后出,后进先出的规则。 8 | 9 | 栈有下面几种基本运算: 10 | 11 | - push(压入):向栈中添加元素(一般向栈顶处添加)。如果栈已满(full),即为溢出(overflow)情况。 12 | - pop(推出):从栈中删除元素(一般删除栈顶元素)。如果栈是空的,即为下溢(underflow)情况。 13 | - Peek 或者 Top:返回栈顶元素。 14 | - isEmpty(是否为空):如果栈为空,返回True;反之,返回False。 15 | 16 | ![栈(Stack)](https://www.geeksforgeeks.org/wp-content/uploads/gq/2013/03/stack.png) 17 | 18 | ## 栈运算的复杂度 19 | 20 | - push():O(1) 21 | - pop():O(1) 22 | - peek()复杂度:O(1) 23 | - isEmpty():O(1) 24 | 25 | ## 用数组实现栈 26 | 27 | 用数组实现栈,实质上是实现了"伪"栈,本质是数组,但添加了pop、push、isEmpty函数来控制数组的索引,造成栈的假象。比如使用push()向栈中添加元素时,只是给数组当前索引的下一个索引对应的内存空间赋值而已。 28 | 29 | 注:为什么认为是伪栈呢?因为数组必须初始化其容量大小,那么将数组作栈的基本数据结构时,其内存空间大小一开始就已经确定好了,哪怕对栈进行pop,实质上内存空间没有变化。 30 | 31 | **C++** 32 | 33 | ```c++ 34 | /* C++ program to implement basic stack 35 | operations */ 36 | #include 37 | using namespace std; 38 | 39 | // 定义栈的最大容量 40 | #define MAX 1000 41 | 42 | class Stack 43 | { 44 | int top; // 栈顶索引 45 | public: 46 | int a[MAX]; // Maximum size of Stack 47 | 48 | Stack() { top = -1; } // 构造函数 49 | bool push(int x); 50 | int pop(); 51 | bool isEmpty(); 52 | }; 53 | // push()压入元素 54 | bool Stack::push(int x) 55 | { 56 | // 判断栈顶索引 57 | if (top >= MAX) 58 | { 59 | cerr << "Stack Overflow" < 150 | #include 151 | #include 152 | 153 | // A structure to represent a stack 154 | struct StackNode 155 | { 156 | int data; 157 | struct StackNode* next; 158 | }; 159 | 160 | struct StackNode* newNode(int data) 161 | { 162 | struct StackNode* stackNode = 163 | (struct StackNode*) malloc(sizeof(struct StackNode)); 164 | stackNode->data = data; 165 | stackNode->next = NULL; 166 | return stackNode; 167 | } 168 | 169 | int isEmpty(struct StackNode *root) 170 | { 171 | return !root; 172 | } 173 | 174 | void push(struct StackNode** root, int data) 175 | { 176 | struct StackNode* stackNode = newNode(data); 177 | stackNode->next = *root; 178 | *root = stackNode; 179 | printf("%d pushed to stack\n", data); 180 | } 181 | 182 | int pop(struct StackNode** root) 183 | { 184 | if (isEmpty(*root)) 185 | return INT_MIN; 186 | struct StackNode* temp = *root; 187 | *root = (*root)->next; 188 | int popped = temp->data; 189 | free(temp); 190 | 191 | return popped; 192 | } 193 | 194 | int peek(struct StackNode* root) 195 | { 196 | if (isEmpty(root)) 197 | return INT_MIN; 198 | return root->data; 199 | } 200 | 201 | int main() 202 | { 203 | struct StackNode* root = NULL; 204 | 205 | push(&root, 10); 206 | push(&root, 20); 207 | push(&root, 30); 208 | 209 | printf("%d popped from stack\n", pop(&root)); 210 | 211 | printf("Top element is %d\n", peek(root)); 212 | 213 | return 0; 214 | } 215 | ``` 216 | 217 | Python 218 | 219 | ```python 220 | # Python program for linked list implementation of stack 221 | 222 | # Class to represent a node 223 | class StackNode: 224 | 225 | # Constructor to initialize a node 226 | def __init__(self, data): 227 | self.data = data 228 | self.next = None 229 | 230 | class Stack: 231 | 232 | # Constructor to initialize the root of linked list 233 | def __init__(self): 234 | self.root = None 235 | 236 | def isEmpty(self): 237 | return True if self.root is None else False 238 | 239 | def push(self, data): 240 | newNode = StackNode(data) 241 | newNode.next = self.root 242 | self.root = newNode 243 | print "%d pushed to stack" %(data) 244 | 245 | def pop(self): 246 | if (self.isEmpty()): 247 | return float("-inf") 248 | temp = self.root 249 | self.root = self.root.next 250 | popped = temp.data 251 | return popped 252 | 253 | def peek(self): 254 | if self.isEmpty(): 255 | return float("-inf") 256 | return self.root.data 257 | 258 | # Driver program to test above class 259 | stack = Stack() 260 | stack.push(10) 261 | stack.push(20) 262 | stack.push(30) 263 | 264 | print "%d popped from stack" %(stack.pop()) 265 | print "Top element is %d " %(stack.peek()) 266 | 267 | # This code is contributed by Nikhil Kumar Singh(nickzuck_007) 268 | ``` 269 | 270 | 271 | 272 | # 数据结构—队列(Queue) 273 | 274 | ## 队列的定义和基本运算 275 | 276 | 队列(Queue)是限制结点插入操作固定在一端进行,而结点的删除操作固定在另一端进行的线性表。 277 | 278 | 队列犹如一个两端开口的管道。允许插入的一端称为队头,允许删除的一端称为队尾。队头和队尾各用一个”指针”指示,称为队头指针和队尾指针。不含任何结点的队列称为”空队列”。队列的特点是结点在队列中的排队次序和出队次序按进队时间先后确定,即先进队者先出队。因此,队列又称先进先出表。简称FIFO(first in first out)表。 279 | 280 | 队列的一个很好的例子就是消费者排队:消费者先排队先消费。 281 | 282 | 队列的基本运算如下: 283 | 284 | - Enqueue(入队/插入):添加元素到队列中。如果队列满了,则表示溢出(Overflow)情况。 285 | - Dequeue(出队/删除):从队列中剔除元素。该元素被压出(pop)的顺序与push(压入)的顺序一样。如果队列是空的,则表示下溢(underflow)情况。 286 | - Front(队头):从队列中获得最前面的元素。 287 | - Rear(队尾):从队列中获得最后面的元素。 288 | 289 | ![Queue](https://www.geeksforgeeks.org/wp-content/uploads/gq/2014/02/Queue.png) 290 | 291 | 队列初始条件:队头指针=队尾指针=0 292 | 293 | 队列满条件:队尾指针=m(设队列当前容量为m) 294 | 295 | 队列空条件:队头指针=队尾指针 296 | 297 | ## 队列的应用 298 | 299 | 如果不必立即处理事件时,则可以使用队列,特别是使用“广度优先搜索”中的“先入先出”顺序进行处理。队列的这个属性使它在以下类型的场景中也很有用。 300 | 301 | 1)资源在多个消费者之间共享。 例子包括CPU调度(scheduling),磁盘调度。 302 | 2)在两个进程(processing)之间异步传输数据(数据接收的速度不一定与发送的速度相同)。例子包括IO缓冲区(Buffers),pipes,file IO等。 303 | 304 | 有关队列和堆栈的更多详细信息,请参阅此处。 305 | 306 | ## 用数组实现队列 307 | 308 | 为了实现队列,我们需要跟踪队头(front)和队尾(rear)的两个索引。我们在队尾插入元素并在队头删除元素。如果我们只是增加队头和队尾的索引,那么可能会出现问题,队头可能会到达数组的末端。解决这个问题的方法是以**循环(circular)**的方式增加队头和队尾。 309 | 310 | [Inplement Queue using array](https://practice.geeksforgeeks.org/problems/implement-queue-using-array/1) 311 | 312 | C 313 | 314 | ```c 315 | // C program for array implementation of queue 316 | #include 317 | #include 318 | #include 319 | 320 | // A structure to represent a queue 321 | struct Queue 322 | { 323 | int front, rear, size; // 队头指针、队尾指针和队列有效元素数量 324 | unsigned capacity; // 队列最大容量 325 | int* array; // 存储队列值的数组 326 | }; 327 | 328 | // function to create a queue of given capacity. 329 | // It initializes size of queue as 0 330 | struct Queue* createQueue(unsigned capacity) 331 | { 332 | struct Queue* queue = (struct Queue*) malloc(sizeof(struct Queue)); 333 | queue->capacity = capacity; 334 | queue->front = queue->size = 0; 335 | queue->rear = capacity - 1; // This is important, see the enqueue 336 | queue->array = (int*) malloc(queue->capacity * sizeof(int)); 337 | return queue; 338 | } 339 | 340 | // Queue is full when size becomes equal to the capacity 341 | int isFull(struct Queue* queue) 342 | { return (queue->size == queue->capacity); } 343 | 344 | // Queue is empty when size is 0 345 | int isEmpty(struct Queue* queue) 346 | { return (queue->size == 0); } 347 | 348 | // Function to add an item to the queue. 349 | // It changes rear and size 350 | void enqueue(struct Queue* queue, int item) 351 | { 352 | if (isFull(queue)) 353 | return; 354 | queue->rear = (queue->rear + 1)%queue->capacity; 355 | queue->array[queue->rear] = item; 356 | queue->size = queue->size + 1; 357 | printf("%d enqueued to queue\n", item); 358 | } 359 | 360 | // Function to remove an item from queue. 361 | // It changes front and size 362 | int dequeue(struct Queue* queue) 363 | { 364 | if (isEmpty(queue)) 365 | return INT_MIN; 366 | int item = queue->array[queue->front]; 367 | queue->front = (queue->front + 1)%queue->capacity; 368 | queue->size = queue->size - 1; 369 | return item; 370 | } 371 | 372 | // Function to get front of queue 373 | int front(struct Queue* queue) 374 | { 375 | if (isEmpty(queue)) 376 | return INT_MIN; 377 | return queue->array[queue->front]; 378 | } 379 | 380 | // Function to get rear of queue 381 | int rear(struct Queue* queue) 382 | { 383 | if (isEmpty(queue)) 384 | return INT_MIN; 385 | return queue->array[queue->rear]; 386 | } 387 | 388 | // Driver program to test above functions./ 389 | int main() 390 | { 391 | // 初始化队列,分配空间为1000 392 | struct Queue* queue = createQueue(1000); 393 | 394 | enqueue(queue, 10); 395 | enqueue(queue, 20); 396 | enqueue(queue, 30); 397 | enqueue(queue, 40); 398 | 399 | printf("%d dequeued from queue\n", dequeue(queue)); 400 | 401 | printf("Front item is %d\n", front(queue)); 402 | printf("Rear item is %d\n", rear(queue)); 403 | 404 | return 0; 405 | } 406 | ``` 407 | 408 | Python 409 | 410 | ```python 411 | # Python3 program for array implementation of queue 412 | 413 | # Class Queue to represent a queue 414 | class Queue: 415 | 416 | # __init__ function 417 | def __init__(self, capacity): 418 | self.front = self.size = 0 419 | self.rear = capacity -1 420 | self.Q = [None]*capacity 421 | self.capacity = capacity 422 | 423 | # Queue is full when size becomes 424 | # equal to the capacity 425 | def isFull(self): 426 | return self.size == self.capacity 427 | 428 | # Queue is empty when size is 0 429 | def isEmpty(self): 430 | return self.size == 0 431 | 432 | # Function to add an item to the queue. 433 | # It changes rear and size 434 | def EnQueue(self, item): 435 | if self.isFull(): 436 | print("Full") 437 | return 438 | self.rear = (self.rear + 1) % (self.capacity) 439 | self.Q[self.rear] = item 440 | self.size = self.size + 1 441 | print("%s enqueued to queue" %str(item)) 442 | 443 | # Function to remove an item from queue. 444 | # It changes front and size 445 | def DeQueue(self): 446 | if self.isEmpty(): 447 | print("Empty") 448 | return 449 | 450 | print("%s dequeued from queue" %str(self.Q[self.front])) 451 | self.front = (self.front + 1) % (self.capacity) 452 | self.size = self.size -1 453 | 454 | # Function to get front of queue 455 | def que_front(self): 456 | if self.isEmpty(): 457 | print("Queue is empty") 458 | 459 | print("Front item is", self.Q[self.front]) 460 | 461 | # Function to get rear of queue 462 | def que_rear(self): 463 | if self.isEmpty(): 464 | print("Queue is empty") 465 | print("Rear item is", self.Q[self.rear]) 466 | 467 | 468 | # Driver Code 469 | if __name__ == '__main__': 470 | 471 | queue = Queue(30) 472 | queue.EnQueue(10) 473 | queue.EnQueue(20) 474 | queue.EnQueue(30) 475 | queue.EnQueue(40) 476 | queue.DeQueue() 477 | queue.que_front() 478 | queue.que_rear() 479 | ``` 480 | 481 | 482 | 483 | ## 队列的类型 484 | 485 | - [ ] 待补充详细内容 486 | 487 | - 顺序队列 488 | - 循环队列 489 | - 链队列 490 | 491 | 492 | 493 | 494 | 495 | 496 | # 使用栈实现队列 497 | 498 | https://www.geeksforgeeks.org/queue-using-stacks/ 499 | 500 | 501 | 502 | # 参考 503 | 504 | ## 栈(Stack) 505 | 506 | [Wiki: Stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) 507 | 508 | **(推荐)**[Stack Data Structure](https://www.geeksforgeeks.org/stack-data-structure/) 509 | 510 | [什么是“堆”,"栈","堆栈","队列",它们的区别?](https://jingyan.baidu.com/article/6c67b1d6a09f9a2786bb1e4a.html) 511 | 512 | ## 队列(Queue) 513 | 514 | [Wiki: Queue](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)) 515 | 516 | **(推荐)**[Queue Data Structure](https://www.geeksforgeeks.org/queue-data-structure/):含队列的定义和代码等 517 | 518 | [队列的定义及其基本操作](https://blog.csdn.net/forwardyzk/article/details/53771544) 519 | 520 | ## 521 | 522 | 523 | 524 | -------------------------------------------------------------------------------- /Coding Interviews/06_ConstructBinaryTree/Binarytree.md: -------------------------------------------------------------------------------- 1 | # 数据结构—二叉树 2 | 3 | ## 树的定义 4 | 5 | [树](http://www.cnblogs.com/polly333/p/4739567.html)是一种数据结构,它是由n(n>=1)个有限结点组成一个具有层次关系的集合。 6 | 7 | 注:二叉树中的元素称为**结点(node)** 8 | 9 | ![树](https://img-blog.csdn.net/20170324154348019) 10 | 11 | 树具有的特点有: 12 | 13 | (1)每个结点有零个或多个子结点 14 | 15 | (2)没有父节点的结点称为根节点 16 | 17 | (3)每一个非根结点有且只有一个父节点 18 | 19 | (4)除了根结点外,每个子结点可以分为多个不相交的子树。 20 | 21 | 22 | 23 | 树的基本术语有: 24 | 25 | 若一个结点有子树,那么该结点称为子树根的“**双亲**”,子树的根称为该结点的“**孩子**”。有相同双亲的结点互为“**兄弟**”。一个结点的所有子树上的任何结点都是该结点的**后裔**。从根结点到某个结点的路径上的所有结点都是该结点的**祖先**。 26 | 27 | 28 | 29 | **结点的度**:结点拥有的子树的数目 30 | 31 | **叶子结点**:度为0的结点 32 | 33 | **分支结点**:度不为0的结点 34 | 35 | **树的度**:树中结点的最大的度 36 | 37 | **层次**:根结点的层次为1,其余结点的层次等于该结点的双亲结点的层次加1 38 | 39 | **树的高度**:树中结点的最大层次 40 | 41 | **森林**:0个或多个不相交的树组成。对森林加上一个根,森林即成为树;删去根,树即成为森林。 42 | 43 | ## 二叉树 44 | 45 | ### 二叉树的定义 46 | 47 | 二叉树是树的特殊一种,具有如下特点: 48 | 49 | 1、每个结点最多有两颗子树,结点的度最大为2。 50 | 51 | 2、左子树和右子树是有顺序的,次序不能颠倒。 52 | 53 | 3、即使某结点只有一个子树,也要区分左右子树。 54 | 55 | 二叉树有五种基本形态:二叉树可以是空集;根可以有空的左子树或右子树;或者左、右子树皆为空。 56 | 57 | ![二叉树五种形态](https://img-blog.csdn.net/20170324154426661) 58 | 59 | ### 二叉树的性质 60 | 61 | 性质1:二叉树第i层上的结点数目最多为2^(i-1) (i>=1) 62 | 63 | 性质2:深度为k的二叉树至多有(2^k)-1个结点(k>=1) 64 | 65 | 性质3:包含n个结点的二叉树的高度至少为(log2n)+1 66 | 67 | 性质4:在任意一棵非空的二叉树中,若叶子结点(度为0)的个数为n0,度为2的结点数为n2,则n0=n2+1 68 | 69 | - 证明:在一棵二叉树中,除了叶子结点(度为0)之外,就剩下度为2(n2)和1(n1)的结点了。则树的结点总数为T = n0+n1+n2; 在二叉树中结点总数为T,而连线数为T-1(至于非0度采用连线).所以有:n0+n1+n2-1 = 2*n2 +n1;最后得到n0 = n2+1。 70 | 71 | - 举个栗子 72 | 73 | ![二叉树性质4栗子](https://images0.cnblogs.com/blog/451660/201508/181911001445541.png) 74 | 75 | ### 二叉树种类 76 | 77 | #### 斜树(Oblique Tree) 78 | 79 | 所有的结点都只有左子树(左斜树),或者只有右子树(右斜树)。这就是斜树,应用较少 80 | 81 | ![斜树](https://note.youdao.com/yws/public/resource/e5d22712496f4f6585b7247eac93871c/xmlnote/WEBRESOURCE0ecdc57388f2c98b9e20a959900a08d7/47830) 82 | 83 | #### 满二叉树**(Perfect Binary Tree)** 84 | 85 | 所有的分支结点都存在左子树和右子树,并且所有的叶子结点都在同一层上,这样就是满二叉树。就是完美圆满的意思,关键在于树的平衡。 86 | 87 | 换个说法:高度为h,并且由2^h-1个结点组成的二叉树,称为满二叉树 88 | 89 | ![满二叉树](https://img-blog.csdn.net/20170324154449411) 90 | 91 | 根据满二叉树的定义,得到其特点为: 92 | 93 | 1. 叶子只能出现在最下一层。 94 | 2. 非叶子结点度一定是2. 95 | 3. 在同样深度的二叉树中,满二叉树的结点个数最多,叶子树最多。 96 | 97 | #### 完全二叉树**(Complete Binary Tree)** 98 | 99 | **定义**:一棵二叉树中,只有最下面两层结点的度可以小于2,并且最下层的叶结点集中在靠左的若干位置上,这样的二叉树称为完全二叉树。 100 | 101 | **特点**:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。 102 | 103 | 结合完全二叉树定义得到其特点: 104 | 105 | 1. 叶子结点只能出现在最下一层(满二叉树继承而来) 106 | 2. 最下层叶子结点一定集中在左 部连续位置。 107 | 3. 倒数第二层,如有叶子节点,一定出现在右部连续位置。 108 | 4. 同样结点树的二叉树,完全二叉树的深度最小(满二叉树也是对的)。 109 | 110 | ![完全二叉树](https://img-blog.csdn.net/20170324154512412) 111 | 112 | 根据下图加深理解,什么时候是完全二叉树。 113 | 114 | ![完全二叉树](http://img.blog.csdn.net/20140424162035437?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaml1cWl5dWxpYW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 115 | 116 | **完全二叉树性质** 117 | 118 | a、具有n的结点的完全二叉树的深度为log2n+1. 119 | 120 | - 证明:满二叉树是完全二叉树,对于深度为k的满二叉树中结点数量是(2^k)-1 = n,完全二叉树结点数量肯定最多(2^k)-1,同时完全二叉树倒数第二层肯定是满的(倒数第一层有结点,那么倒是第二层序号和满二叉树相同),所以完全二叉树的结点数最少大于少一层的满二叉树,为(2^(k-1)-1。 121 | 122 | 根据上面推断得出: (2^(k-1)-1< n=<(2^k)-1,因为结点数Nn为整数那么n<=(2^k)-1可以推出n<=2^k ,n>(2^(k-1)-1可以推出 n>=(2^k)-1,所以(2^k)-11,则其双亲节点为[i/2],向下取整 127 | 128 | ​ 2.如果2i>n那么节点i没有左孩子,否则其左孩子为2i 129 | 130 | ​ 3.如果2i+1>n那么节点没有右孩子,否则右孩子为2i+1 131 | 132 | **举个栗子** 133 | 134 | ![](https://images0.cnblogs.com/blog/451660/201508/181911019725482.png) 135 | 136 | 在上图中验证 137 | 138 | 第一条: 139 | 140 | 当i=1时,为根节点。当i>1时,比如结点为7,他的双亲就是7/2= 3;结点9双亲为4. 141 | 142 | 第二条: 143 | 144 | 结点6,6x2 = 12>10,所以结点6无左孩子,是叶子结点;结点5,5x2 = 10,左孩子是10;结点4,4x2=8<10,左孩子为8. 145 | 146 | 第三条: 147 | 148 | 结点5,2*5+1>10,没有右孩子;结点4,4x2+1<10,则有右孩子。 149 | 150 | 151 | 152 | **完全二叉树面试题**:如果一个完全二叉树的结点总数为768个,求叶子结点的个数。 153 | 154 | 由二叉树的性质知:n0=n2+1,将之带入768=n0+n1+n2中得:768=n1+2n2+1,因为完全二叉树度为1的结点个数要么为0,要么为1,那么就把n1=0或者1都代入公式中,很容易发现n1=1才符合条件。所以算出来n2=383,所以叶子结点个数n0=n2+1=384。 155 | 156 | **总结规律**:如果一棵完全二叉树的结点总数为n,那么叶子结点等于n/2(当n为偶数时)或者(n+1)/2(当n为奇数时) 157 | 158 | ### 完满二叉树(Full Binary Tree) 159 | 160 | ``` 161 | A Full Binary Tree (FBT) is a tree in which every node other than the leaves has two children. 162 | ``` 163 | 164 | 换句话说,**所有非叶子结点的度都是2**。(**只要你有孩子,你就必然是有两个孩子。**) 165 | 166 | **注:**Full Binary Tree又叫做Strictly Binary Tree。 167 | 168 | ![完满二叉树](https://images2015.cnblogs.com/blog/1094457/201702/1094457-20170225183305616-1864401342.png) 169 | 170 | **总结:完美二叉树(满二叉树)、完全二叉树和完满二叉树** 171 | 172 | | **完美二叉树** | Perfect Binary Tree | Every node except the leaf nodes have two children and every level (last level too) is completely filled. **除了叶子结点之外的每一个结点都有两个孩子,每一层(当然包含最后一层)都被完全填充。** | 173 | | --------- | ------------------------- | ---------------------------------------- | 174 | | **完全二叉树** | Complete Binary Tree | Every level except the last level is completely filled and all the nodes are left justified. **除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对齐。** | 175 | | **完满二叉树** | Full/Strictly Binary Tree | Every node except the leaf nodes have two children. **除了叶子结点之外的每一个结点都有两个孩子结点。** | 176 | 177 | - 完美(Perfect)二叉树一定是完全(Complete)二叉树,但完全(Complete)二叉树不一定是完美(Perfect)二叉树。 178 | - 完美(Perfect)二叉树一定是完满(Full)二叉树,但完满(Full)二叉树不一定是完美(Perfect)二叉树。 179 | - 完全(Complete)二叉树可能是完满(Full)二叉树,完满(Full)二叉树也可能是完全(Complete)二叉树。 180 | - 既是完全(Complete)二叉树又是完满(Full)二叉树也不一定就是完美(Perfect)二叉树。 181 | 182 | ## 二叉树遍历 183 | 184 | 二叉树遍历:从树的根节点出发,按照某种次序依次访问二叉树中所有的结点,使得每个结点被访问仅且一次。 185 | 186 | 这里有两个关键词:**访问**和**次序**。 187 | 188 | ### 二叉树结构 189 | 190 | 在介绍二叉树遍历方法之前,先介绍一下二叉树结构。 191 | 192 | ``` 193 | /* A binary tree node has data, pointer to left child 194 | and a pointer to right child */ 195 | struct BiTree{ 196 | int data; 197 | struct BiTree *left; 198 | struct BiTree *right; 199 | }; 200 | ``` 201 | 202 | ### 前序遍历(Pre-Order Traversal) 203 | 204 | ![前序遍历](http://my.csdn.net/uploads/201203/27/1332780800_2559.jpg) 205 | 206 | 基本思想:先访问根结点,再先序遍历左子树,最后再先序遍历右子树,即**根—左—右**。 207 | 208 | 图中前序遍历结果是:1,2,4,5,7,8,3,6。 209 | 210 | **前序遍历算法**:Algorithm Preorder(tree) 211 | 212 | 1. Visit the root. 213 | 2. Traverse the left subtree, i.e., call Preorder(left-subtree) 214 | 3. Traverse the right subtree, i.e., call Preorder(right-subtree) 215 | 216 | **1)前序递归遍历** 217 | 218 | ```c++ 219 | //前序递归遍历 220 | void PreOrderTraverse(BiTree t) 221 | { 222 | //注意跳出条件 223 | if(t != NULL) 224 | { 225 | //注意访问语句顺序 226 | printf("%c ", t->data); 227 | PreOrderTraverse(t->lchild); // 遍历左子树 228 | PreOrderTraverse(t->rchild); // 遍历右子树 229 | } 230 | } 231 | ``` 232 | 233 | **2)前序非递归遍历** 234 | 235 | 对于任一结点p: 236 | 237 | ​ a. 访问结点p,并将结点p入栈; 238 | 239 | ​ b. 判断结点p的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点p,循环置a;若不为空,则将p的左孩子置为当前结点p; 240 | 241 | ​ c. 直到p为空,并且栈为空,则遍历结束。 242 | 243 | ```c++ 244 | //前序非递归遍历 245 | int NoPreOrderTraverse(BiTree t) 246 | { 247 | SqStack s; 248 | InitStack(&s); 249 | 250 | BiTree tmp = t; 251 | if(tmp == NULL) 252 | { 253 | fprintf(stdout, "the tree is null.\n"); 254 | return ERROR; 255 | } 256 | //现将左子树压入栈,当到叶子结点后,出栈,获取右子树,然后在压入右子树的左子树。 257 | //顺序不能变 258 | while((tmp != NULL) || (IsEmpty(&s) != 1)) 259 | { 260 | while(tmp != NULL) 261 | { 262 | Push(&s, tmp); 263 | printf("%c ", tmp->data); 264 | tmp = tmp->lchild; 265 | } 266 | if(IsEmpty(&s) != 1) 267 | { 268 | Pop(&s, &tmp); 269 | tmp = tmp->rchild; 270 | } 271 | } 272 | 273 | return OK; 274 | } 275 | ``` 276 | 277 | ### 中序遍历(In-Order Traversal) 278 | 279 | ![中序遍历](http://my.csdn.net/uploads/201203/27/1332780987_8583.jpg) 280 | 281 | 基本思想:先中序遍历左子树,然后再访问根结点,最后再中序遍历右子树即**左—根—右**。 282 | 283 | 图中中序遍历结果是:4,2,7,8,5,1,3,6。 284 | 285 | **中序遍历算法**:Algorithm Inorder(tree) 286 | 287 | 1. Traverse the left subtree, i.e., call Inorder(left-subtree) 288 | 2. Visit the root. 289 | 3. Traverse the right subtree, i.e., call Inorder(right-subtree) 290 | 291 | **1)中序遍历迭代代码** 292 | 293 | ```c++ 294 | //中序递归遍历 295 | void InOrderTraverse(BiTree t) 296 | { 297 | if(t != NULL) 298 | { 299 | InOrderTraverse(t->lchild); 300 | printf("%c ", t->data); 301 | InOrderTraverse(t->rchild); 302 | } 303 | } 304 | ``` 305 | 306 | **2)中序非递归遍历** 307 | 308 | ​ 根据中序遍历的顺序,对于任一结点,优先访问其左孩子,而左孩子结点又可以看做一个根结点,然后继续访问其左孩子结点,直到遇到左孩子结点为空的结点才停止访问,然后按相同的规则访问其右子树。其处理过程如下: 309 | 310 | ​ 对于任一结点: 311 | 312 | ​ a. 若其左孩子不为空,则将p入栈,并将p的左孩子设置为当前的p,然后对当前结点再进行相同的操作; 313 | 314 | ​ b. 若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的p置为栈顶结点的右孩子; 315 | 316 | ​ c. 直到p为空并且栈为空,则遍历结束。 317 | 318 | ```c++ 319 | //中序非递归遍历二叉树 320 | int NoInOrderTraverse(BiTree t) 321 | { 322 | SqStack s; 323 | InitStack(&s); 324 | 325 | BiTree tmp = t; 326 | if(tmp == NULL) 327 | { 328 | fprintf(stderr, "the tree is null.\n"); 329 | return ERROR; 330 | } 331 | 332 | while(tmp != NULL || (IsEmpty(&s) != 1)) 333 | { 334 | while(tmp != NULL) 335 | { 336 | Push(&s, tmp); 337 | tmp = tmp->lchild; 338 | } 339 | 340 | if(IsEmpty(&s) != 1) 341 | { 342 | Pop(&s, &tmp); 343 | printf("%c ", tmp->data); 344 | tmp = tmp->rchild; 345 | } 346 | } 347 | return OK; 348 | } 349 | ``` 350 | 351 | ### 后序遍历(Post-Order Traversal) 352 | 353 | ![后序遍历](http://my.csdn.net/uploads/201203/27/1332781113_9913.jpg) 354 | 355 | 基本思想:先后序遍历左子树,然后再后序遍历右子树,最后再访问根结点即**左—右—根**。 356 | 357 | 图中后序遍历结果是:4,8,7,5,2,6,3,1。 358 | 359 | **后序遍历算法**:Algorithm Postorder(tree) 360 | 361 | 1. Traverse the left subtree, i.e., call Postorder(left-subtree) 362 | 2. Traverse the right subtree, i.e., call Postorder(right-subtree) 363 | 3. Visit the root. 364 | 365 | 后序递归遍历代码实现,如下所示。 366 | 367 | ```c++ 368 | //后序递归遍历 369 | void PostOrderTraverse(BiTree t) 370 | { 371 | if(t != NULL) 372 | { 373 | PostOrderTraverse(t->lchild); 374 | PostOrderTraverse(t->rchild); 375 | printf("%c ", t->data); 376 | } 377 | } 378 | ``` 379 | 380 | **后序遍历的非递归实现是三种遍历方式中最难的一种**。因为在后序遍历中,要保证左孩子和右孩子都已被访问,并且左孩子在右孩子之前访问才能访问根结点,这就为流程控制带来了难题。下面介绍一种思路。 381 | 382 | 要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点p,先将其入栈。若p不存在左孩子和右孩子,则可以直接访问它,或者p存在左孩子或右孩子,但是其左孩子和右孩子都已经被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将p的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子之前别访问,左孩子和右孩子都在根结点前面被访问。 383 | 384 | ```c++ 385 | //后序非递归遍历二叉树 386 | int NoPostOrderTraverse(BiTree t) 387 | { 388 | SqStack s; 389 | InitStack(&s); 390 | 391 | BiTree cur; //当前结点 392 | BiTree pre = NULL; //前一次访问的结点 393 | BiTree tmp; 394 | 395 | if(t == NULL) 396 | { 397 | fprintf(stderr, "the tree is null.\n"); 398 | return ERROR; 399 | } 400 | 401 | Push(&s, t); 402 | while(IsEmpty(&s) != 1) 403 | { 404 | GetTop(&s, &cur);// 405 | if((cur->lchild == NULL && cur->rchild == NULL) || (pre != NULL && (pre == cur->lchild || pre == cur->rchild))) 406 | { 407 | printf("%c ", cur->data); //如果当前结点没有孩子结点或者孩子结点都已被访问过 408 | Pop(&s, &tmp); 409 | pre = cur; 410 | } 411 | else 412 | { 413 | if(cur->rchild != NULL) 414 | { 415 | Push(&s, cur->rchild); 416 | } 417 | if(cur->lchild != NULL) 418 | { 419 | Push(&s, cur->lchild); 420 | } 421 | } 422 | } 423 | return OK; 424 | } 425 | ``` 426 | 427 | **前序排序、中序排序和后序排序总结** 428 | 429 | 以根结点为基础,根据其位置关系即可判断是前序、中序还是后序。如: 430 | 431 | - 前序排序:**根**—左—右 432 | - 中序排序:左—**根**—右 433 | - 后序排序:左—右—**根** 434 | 435 | **举个栗子** 436 | 437 | ![Example Tree](https://www.geeksforgeeks.org/wp-content/uploads/2009/06/tree12.gif) 438 | 439 | Depth First Traversals 440 | 441 | (a) 前序遍历 Preorder (Root, Left, Right) : 1 2 4 5 3 442 | 443 | (b) 中序遍历 Inorder (Left, Root, Right) : 4 2 5 1 3 444 | 445 | (c) 后序遍历 Postorder (Left, Right, Root) : 4 5 2 3 1 446 | 447 | c++代码 448 | 449 | ```c++ 450 | // C program for different tree traversals 451 | #include 452 | #include 453 | 454 | /* A binary tree node has data, pointer to left child 455 | and a pointer to right child */ 456 | struct node 457 | { 458 | int data; 459 | struct node* left; 460 | struct node* right; 461 | }; 462 | 463 | /* Helper function that allocates a new node with the 464 | given data and NULL left and right pointers. */ 465 | struct node* newNode(int data) 466 | { 467 | struct node* node = (struct node*) 468 | malloc(sizeof(struct node)); 469 | node->data = data; 470 | node->left = NULL; 471 | node->right = NULL; 472 | 473 | return(node); 474 | } 475 | 476 | /* Given a binary tree, print its nodes according to the 477 | "bottom-up" postorder traversal. */ 478 | void printPostorder(struct node* node) 479 | { 480 | if (node == NULL) 481 | return; 482 | 483 | // first recur on left subtree 484 | printPostorder(node->left); 485 | 486 | // then recur on right subtree 487 | printPostorder(node->right); 488 | 489 | // now deal with the node 490 | printf("%d ", node->data); 491 | } 492 | 493 | /* Given a binary tree, print its nodes in inorder*/ 494 | void printInorder(struct node* node) 495 | { 496 | if (node == NULL) 497 | return; 498 | 499 | /* first recur on left child */ 500 | printInorder(node->left); 501 | 502 | /* then print the data of node */ 503 | printf("%d ", node->data); 504 | 505 | /* now recur on right child */ 506 | printInorder(node->right); 507 | } 508 | 509 | /* Given a binary tree, print its nodes in preorder*/ 510 | void printPreorder(struct node* node) 511 | { 512 | if (node == NULL) 513 | return; 514 | 515 | /* first print data of node */ 516 | printf("%d ", node->data); 517 | 518 | /* then recur on left sutree */ 519 | printPreorder(node->left); 520 | 521 | /* now recur on right subtree */ 522 | printPreorder(node->right); 523 | } 524 | 525 | /* Driver program to test above functions*/ 526 | int main() 527 | { 528 | struct node *root = newNode(1); 529 | root->left = newNode(2); 530 | root->right = newNode(3); 531 | root->left->left = newNode(4); 532 | root->left->right = newNode(5); 533 | 534 | printf("\nPreorder traversal of binary tree is \n"); 535 | printPreorder(root); 536 | 537 | printf("\nInorder traversal of binary tree is \n"); 538 | printInorder(root); 539 | 540 | printf("\nPostorder traversal of binary tree is \n"); 541 | printPostorder(root); 542 | 543 | getchar(); 544 | return 0; 545 | } 546 | 547 | ``` 548 | 549 | Python代码 550 | 551 | ```python 552 | # Python program to for tree traversals 553 | 554 | # A class that represents an individual node in a 555 | # Binary Tree 556 | class Node: 557 | def __init__(self,key): 558 | self.left = None 559 | self.right = None 560 | self.val = key 561 | 562 | 563 | # A function to do inorder tree traversal 564 | def printInorder(root): 565 | 566 | if root: 567 | 568 | # First recur on left child 569 | printInorder(root.left) 570 | 571 | # then print the data of node 572 | print(root.val), 573 | 574 | # now recur on right child 575 | printInorder(root.right) 576 | 577 | 578 | 579 | # A function to do postorder tree traversal 580 | def printPostorder(root): 581 | 582 | if root: 583 | 584 | # First recur on left child 585 | printPostorder(root.left) 586 | 587 | # the recur on right child 588 | printPostorder(root.right) 589 | 590 | # now print the data of node 591 | print(root.val), 592 | 593 | 594 | # A function to do postorder tree traversal 595 | def printPreorder(root): 596 | 597 | if root: 598 | 599 | # First print the data of node 600 | print(root.val), 601 | 602 | # Then recur on left child 603 | printPreorder(root.left) 604 | 605 | # Finally recur on right child 606 | printPreorder(root.right) 607 | 608 | 609 | # Driver code 610 | root = Node(1) 611 | root.left = Node(2) 612 | root.right = Node(3) 613 | root.left.left = Node(4) 614 | root.left.right = Node(5) 615 | print "Preorder traversal of binary tree is" 616 | printPreorder(root) 617 | 618 | print "\nInorder traversal of binary tree is" 619 | printInorder(root) 620 | 621 | print "\nPostorder traversal of binary tree is" 622 | printPostorder(root) 623 | ``` 624 | 625 | JAVA 626 | 627 | ```java 628 | // Java program for different tree traversals 629 | 630 | /* Class containing left and right child of current 631 | node and key value*/ 632 | class Node 633 | { 634 | int key; 635 | Node left, right; 636 | 637 | public Node(int item) 638 | { 639 | key = item; 640 | left = right = null; 641 | } 642 | } 643 | 644 | class BinaryTree 645 | { 646 | // Root of Binary Tree 647 | Node root; 648 | 649 | BinaryTree() 650 | { 651 | root = null; 652 | } 653 | 654 | /* Given a binary tree, print its nodes according to the 655 | "bottom-up" postorder traversal. */ 656 | void printPostorder(Node node) 657 | { 658 | if (node == null) 659 | return; 660 | 661 | // first recur on left subtree 662 | printPostorder(node.left); 663 | 664 | // then recur on right subtree 665 | printPostorder(node.right); 666 | 667 | // now deal with the node 668 | System.out.print(node.key + " "); 669 | } 670 | 671 | /* Given a binary tree, print its nodes in inorder*/ 672 | void printInorder(Node node) 673 | { 674 | if (node == null) 675 | return; 676 | 677 | /* first recur on left child */ 678 | printInorder(node.left); 679 | 680 | /* then print the data of node */ 681 | System.out.print(node.key + " "); 682 | 683 | /* now recur on right child */ 684 | printInorder(node.right); 685 | } 686 | 687 | /* Given a binary tree, print its nodes in preorder*/ 688 | void printPreorder(Node node) 689 | { 690 | if (node == null) 691 | return; 692 | 693 | /* first print data of node */ 694 | System.out.print(node.key + " "); 695 | 696 | /* then recur on left sutree */ 697 | printPreorder(node.left); 698 | 699 | /* now recur on right subtree */ 700 | printPreorder(node.right); 701 | } 702 | 703 | // Wrappers over above recursive functions 704 | void printPostorder() { printPostorder(root); } 705 | void printInorder() { printInorder(root); } 706 | void printPreorder() { printPreorder(root); } 707 | 708 | // Driver method 709 | public static void main(String[] args) 710 | { 711 | BinaryTree tree = new BinaryTree(); 712 | tree.root = new Node(1); 713 | tree.root.left = new Node(2); 714 | tree.root.right = new Node(3); 715 | tree.root.left.left = new Node(4); 716 | tree.root.left.right = new Node(5); 717 | 718 | System.out.println("Preorder traversal of binary tree is "); 719 | tree.printPreorder(); 720 | 721 | System.out.println("\nInorder traversal of binary tree is "); 722 | tree.printInorder(); 723 | 724 | System.out.println("\nPostorder traversal of binary tree is "); 725 | tree.printPostorder(); 726 | } 727 | } 728 | ``` 729 | 730 | 731 | 732 | ## 二叉树的建立 733 | 734 | 其实二叉树的建立就是二叉树的遍历,只不过将输入内容改为建立结点而已,比如,利用前序遍历建立二叉树 735 | 736 | ```c++ 737 | //创建树 738 | //按先后次序输入二叉树中结点的值(一个字符),#表示空树 739 | //构造二叉链表表示的二叉树 740 | BiTree CreateTree(BiTree t) 741 | { 742 | char ch; 743 | scanf("%c", &ch); 744 | 745 | if(ch == '#') 746 | { 747 | t = NULL; 748 | } 749 | else 750 | { 751 | t = (BitNode *)malloc(sizeof(BitNode)); 752 | if(t == NULL) 753 | { 754 | fprintf(stderr, "malloc() error in CreateTree.\n"); 755 | return; 756 | } 757 | 758 | t->data = ch; //生成根结点 759 | t->lchild = CreateTree(t->lchild); //构造左子树 760 | t->rchild = CreateTree(t->rchild); //构造右子树 761 | } 762 | return t; 763 | } 764 | ``` 765 | 766 | 767 | 768 | # 参考 769 | 770 | [Wiki: Binary tree](https://en.wikipedia.org/wiki/Binary_tree) 771 | 772 | **(推荐)**[浅谈数据结构—二叉树](http://www.cnblogs.com/polly333/p/4740355.html):以文字、图示和代码的方式,详细介绍二叉树的定义、性质和种类(中文版) 773 | 774 | **(推荐)**[Binary Tree](http://btechsmartclass.com/DS/U3_T3.html) :以文字、图示和代码的方式,详细介绍二叉树的定义、性质和种类(英文版) 775 | 776 | **(重磅推荐)**[Binary Tree Data Structure](https://www.geeksforgeeks.org/binary-tree-data-structure/#Introduction) :二叉树的定义、遍历和大量练习题,(英文版) 777 | 778 | [二叉树常见面试题(进阶)](https://www.cnblogs.com/33debug/p/7252371.html) 779 | 780 | [二叉树基础知识总结](https://blog.csdn.net/xiaoquantouer/article/details/65631708) 781 | 782 | [完美二叉树, 完全二叉树和完满二叉树](https://www.cnblogs.com/idorax/p/6441043.html) 783 | 784 | [看懂二叉树的三种遍历](https://blog.csdn.net/soundwave_/article/details/53120766) 785 | 786 | [二叉树可视化网址](https://visualgo.net/zh) 787 | 788 | [Binary Trees](https://www.cs.cmu.edu/~adamchik/15-121/lectures/Trees/trees.html) 789 | 790 | -------------------------------------------------------------------------------- /Data Structures and Algorithms/sort/README.md: -------------------------------------------------------------------------------- 1 | # 排序 2 | 3 | **排序的定义** 4 | 5 | 假设含有n个记录的序列为{r1,r2,...,rn},其相应的关键字分别是{k1,k2,...,kn},需要确定1,2,...,n的一种排列p1,p2,...,pn,使其相应的关键字满足kp1<=kp2<=...<=kpn 非递减(或非递增)的关系,即使得序列成为一个按关键字有序的序列{rp1,rp2,...,rpn},这样的操作就称为排序[1]。 6 | 7 | 简单来说,排序就是使输入的序列变成符合一定规则(关键字)的有序序列(非递减或非递增)。大多数遇到的排序问题都是按数据元素值的大小规则进行排序的问题。所以本文为了方便起见,只讨论数据元素值大小比较的排序问题。 8 | 9 | **排序的稳定性** 10 | 11 | 假设ki=kj(1<=i《=n,1<=j<=n,i!=j),且在排序前的序列中ri领先于rj(即i`冒泡排序(Bubble Sort` 35 | - `选择排序(Selection Sort` 36 | - `插入排序(Insertion Sort` 37 | - `希尔排序(Shell Sort` 38 | - `堆排序(heap Sort` 39 | - `归并排序(merge Sort` 40 | - `快速排序(Fast Sort` 41 | 42 | 43 | ## 常见排序算法复杂度 44 | 45 | ![常用排序算法1](images/sort_algorithms_1.png) 46 | 47 | ![常用排序算法2](images/sort_algorithms_2.png) 48 | 49 | - [8大排序算法稳定性分析](https://www.cnblogs.com/codingmylife/archive/2012/10/21/2732980.html) 50 | 51 | 52 | 53 | 54 | 55 | ## 冒泡排序(Bubble Sort) 56 | 57 | **基本思想** 58 | 59 | 比较相邻的两个元素,将值大的元素交换到右边(降序则相反) 60 | 61 | **步骤:** 62 | 63 | 1. 比较相邻的元素。如果第一个比第二个大,就交换它们两个; 64 | 2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数; 65 | 3. 针对所有的元素重复以上的步骤,除了最后一个; 66 | 4. 重复步骤1~3,直到排序完成。 67 | 68 | 比如有n个元素,那么第一次比较迭代,需要比较n-1次(因为是相邻成对比较,最后一个元素没有与下一个相邻比较的对象,所以是n-1次),此次迭代完成后确定了最后一个元素为最大值;第二次比较迭代,需要比较n-2次,因为第一次迭代已经确定好了最后一个元素,所以不再需要比较;...;第 i次比较迭代,需要比较n-i次,此时确定后面i个元素是有序的较大元素;...;第n-1次比较迭代,需要比较n-(n-1)次,此时完成冒泡排序操作。 69 | 70 | 时间复杂度:o(n^2) = (n-1)*(n-1) 71 | 72 | **动图演示:** 73 | 74 | ![bubble_sort](images/bubble_sort_1.jpg) 75 | 76 | 77 | 78 | ![bubble_sort](images/bubble_sort.gif) 79 | 80 | **过程演示:**待排序数组:{5, 4, 7, 1, 6, 2},升序排序 81 | 82 | \--------------------------------------- 83 | 84 | 第一次循环: 85 | 86 | 第一次比较5和4,5>4,交换位置:{4,5,7,1,6,2} 87 | 88 | 第二次比较5和7,5 89 | 90 | 第三次比较7和1,7>1,交换位置:{4,5,1,7,6,2} 91 | 92 | 第四次比较7和6,7>6,交换位置:{4,5,1,6,7,2} 93 | 94 | 第五次比较7和2,7>2,交换位置:{4,5,1,6,2,7} 95 | 96 | 第一次循环完成结果:{4,5,1,6,2,7} 97 | 98 | \---------------------------------------- 99 | 100 | 第二次循环: 101 | 102 | 第一次比较4和5,4 103 | 104 | 第二次比较5和1,5>1,交换位置:{4,1,5,6,2,7} 105 | 106 | 第三次比较5和6,5 107 | 108 | 第四次比较6和2,6>2,交换位置:{4,1,5,2,6,7} 109 | 110 | 第五次比较6和7,6 111 | 112 | 第二次循环完成结果:{4,1,5,2,6,7} 113 | 114 | \---------------------------------------- 115 | 116 | 第三次循环: 117 | 118 | 第一次比较4和1,4>1,交换位置:{1,4,5,2,6,7} 119 | 120 | 第二次比较4和5,4 121 | 122 | 第三次比较5和2,5>2,交换位置:{1,4,2,5,6,7} 123 | 124 | 第四次比较5和6,5 125 | 126 | 第五次比较6和7,6 127 | 128 | 第三次循环完成结果:{1,4,2,5,6,7} 129 | 130 | \---------------------------------------- 131 | 132 | 第四次循环: 133 | 134 | 第一次比较1和4,1 135 | 136 | 第二次比较4和2,4>2,交换位置:{1,2,4,5,6,7} 137 | 138 | 第三次比较4和5,4 139 | 140 | 第四次比较5和6,5 141 | 142 | 第五次比较6和7,6 143 | 144 | 第三次循环完成结果:{1,2,4,5,6,7} 145 | 146 | \---------------------------------------- 147 | 148 | 第五次循环: 149 | 150 | 第一次比较1和2,1 151 | 152 | 第二次比较2和4,2 153 | 154 | 第三次比较4和5,4 155 | 156 | 第四次比较5和6,5 157 | 158 | 第五次比较6和7,6 159 | 160 | 第三次循环完成结果:{1,2,4,5,6,7} 161 | 162 | 相信看完上面的演示过程,你对冒泡排序过程及原理有了完全的理解,但是细心的朋友应该会发现其实在第四次循环就已经得到了最终的结果,这么来看第五次循环完全是多余的,于是就有冒泡排序的改进版本:当某一轮循环当中没有交换位置的操作,说明已经排好序了,就没必要再循环了,break退出循环即可。 163 | 164 | **复杂度分析:** 165 | 166 | - 时间复杂度:若给定的数组刚好是排好序的数组,采用改进后的冒泡排序算法,只需循环一次就行了,此时是最优时间复杂度:O(n),若给定的是倒序,此时是最差时间复杂度:O(n^2) ,因此综合平均时间复杂度为:O(n^2) 167 | - 空间复杂度:因为每次只需开辟一个temp的空间,因此空间复杂度是:O(1) 168 | 169 | **代码实现:** 170 | 171 | - [bubble_sort.cpp](code/bubble_sort.cpp) 172 | 173 | ```c++ 174 | /* Summary: 冒泡排序 175 | * Author: Amusi 176 | * Date: 208-05-27 177 | * 178 | * Reference: 179 | * http://en.wikipedia.org/wiki/Bubble_sort 180 | * https://github.com/xtaci/algorithms/blob/master/include/bubble_sort.h 181 | * https://zhuanlan.zhihu.com/p/37077924 182 | * 183 | * 冒泡排序说明:比较相邻的两个元素,将值大的元素交换到右边(降序则相反) 184 | * 185 | */ 186 | 187 | #include 188 | 189 | // 冒泡函数 190 | namespace alg{ 191 | template 192 | static void BubbleSort(T list[], int length) 193 | { 194 | 195 | #if 1 196 | // 版本1:两层for循环 197 | for (int i = 0; i < length-1; ++i) 198 | { 199 | for (int j = 0; j < length - i -1; ++j) 200 | { 201 | // 两两相邻元素比较大小,从小到大排序 202 | // if (list[j] < list[j + 1]) : 从大到小排序 203 | if (list[j] > list[j + 1]) 204 | { 205 | int temp = list[j + 1]; 206 | list[j + 1] = list[j]; 207 | list[j] = temp; 208 | } 209 | } 210 | } 211 | 212 | #else 213 | // 版本2:while+一层for循环 214 | bool swapped = false; 215 | while (!swapped) 216 | { 217 | swapped = true; 218 | 219 | for (int i = 0; i < length - 1; ++i) 220 | { 221 | // 两两相邻元素比较大小,从小到大排序 222 | // if (list[j] < list[j + 1]) : 从大到小排序 223 | if (list[i] > list[i + 1]) 224 | { 225 | int temp = list[i + 1]; 226 | list[i + 1] = list[i]; 227 | list[i] = temp; 228 | } 229 | swapped = false; 230 | } 231 | length--; 232 | } 233 | 234 | #endif 235 | 236 | } 237 | } 238 | 239 | using namespace std; 240 | using namespace alg; 241 | 242 | 243 | int main() 244 | { 245 | int a[8] = { 5, 2, 5, 7, 1, -3, 99, 56 }; 246 | BubbleSort(a, 8); 247 | for (auto e : a) 248 | std::cout << e << " "; 249 | 250 | return 0; 251 | } 252 | ``` 253 | 254 | 255 | 256 | - [bubble_sort.py](code/bubble_sort.py) 257 | 258 | ```python 259 | ''' Summary: 冒泡排序 260 | * Author: Amusi 261 | * Date: 208-05-27 262 | * 263 | * Reference: 264 | * http://en.wikipedia.org/wiki/Bubble_sort 265 | * https://github.com/xtaci/algorithms/blob/master/include/bubble_sort.h 266 | * https://zhuanlan.zhihu.com/p/37077924 267 | * 268 | * 冒泡排序说明:比较相邻的两个元素,将值大的元素交换到右边(降序则相反) 269 | * 270 | ''' 271 | 272 | def BubbleSort(array): 273 | lengths = len(array) 274 | for i in range(lengths-1): 275 | for j in range(lengths-1-i): 276 | if array[j] > array[j+1]: 277 | array[j+1], array[j] = array[j], array[j+1] 278 | 279 | return array 280 | 281 | 282 | array = [1,3,8,5,2,10,7,16,7,4,5] 283 | print("Original array: ", array) 284 | array = BubbleSort(array) 285 | print("BubbleSort: ", array) 286 | 287 | ``` 288 | 289 | **参考:** 290 | 291 | 1 [经典排序算法之冒泡排序](http://baijiahao.baidu.com/s?id=1585931471155461767&wfr=spider&for=pc) 292 | 293 | 2 (图示版):[来、通俗聊聊冒泡排序](https://zhuanlan.zhihu.com/p/37077924) 294 | 295 | 296 | 297 | 298 | 299 | ## 选择排序(Selection Sort) 300 | 301 | **基本思想** 302 | 303 | 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。 304 | 305 | **步骤** 306 | 307 | n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下: 308 | 309 | - 初始状态:无序区为R[1..n],有序区为空; 310 | - 第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R[i+1..n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区; 311 | - n-1趟结束,数组有序化了。 312 | 313 | **动图演示** 314 | 315 | ![selection_sort](images/selection_sort.gif) 316 | 317 | **复杂度分析** 318 | 319 | - 时间复杂度:O(n2) 320 | 321 | 注:无论什么数据进去,选择都是O(n2)的时间复杂度,所以若要使用它,建议数据规模越小越好。 322 | 323 | - 空间复杂度:O(1) 324 | 325 | ​ 326 | 327 | **代码实现** 328 | 329 | - [selection_sort.cpp](code/selection_sort.cpp) 330 | 331 | 332 | ```c++ 333 | /* Summary: 选择排序 334 | * Author: Amusi 335 | * Date: 208-06-22 336 | * 337 | * Reference: 338 | * https://en.wikipedia.org/wiki/Selection_sort 339 | * https://github.com/xtaci/algorithms/blob/master/include/selection_sort.h 340 | * 选择排序说明:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。 341 | * 342 | */ 343 | 344 | #include 345 | 346 | // 选择排序函数 347 | namespace alg{ 348 | template 349 | static void SelectionSort(T list[], int length) 350 | { 351 | // 外循环: length-1次,因为当length-1个元素排序好后,第length个元素位置不再变化 352 | for (int i = 0; i < length-1; ++i) 353 | { 354 | int minIndex = i; 355 | // 从i的位置,进行遍历,因为前i-1个元素已经排序好 356 | for (int j = i; j < length; ++j) 357 | { 358 | // 每次从未排序的数组中选出最小的值放入已排序的数组中,即从小到大排序 359 | if (list[j] < list[minIndex]) 360 | { 361 | minIndex = j; 362 | } 363 | } 364 | int temp = list[minIndex]; 365 | list[minIndex] = list[i]; 366 | list[i] = temp; 367 | } 368 | 369 | } 370 | } 371 | 372 | using namespace std; 373 | using namespace alg; 374 | 375 | 376 | int main() 377 | { 378 | int a[8] = { 5, 2, 5, 7, 1, -3, 99, 56 }; 379 | SelectionSort(a, 8); 380 | for (auto e : a) 381 | std::cout << e << " "; 382 | 383 | return 0; 384 | } 385 | ``` 386 | 387 | 388 | 389 | - [selection_sort.py](code/selection_sort.py) 390 | 391 | 392 | ```python 393 | ''' Summary: 选择排序 394 | * Author: Amusi 395 | * Date: 208-06-22 396 | * 397 | * Reference: 398 | * https://en.wikipedia.org/wiki/Selection_sort 399 | * 400 | * 选择排序说明:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。 401 | * 402 | ''' 403 | 404 | def SelectionSort(array): 405 | lengths = len(array) 406 | for i in range(lengths-1): 407 | min_index = i 408 | for j in range(i, lengths): 409 | if array[j] < array[min_index]: 410 | min_index = j 411 | array[i], array[min_index] = array[min_index], array[i] 412 | 413 | return array 414 | 415 | 416 | array = [1,3,8,5,2,10,7,16,7,4,5] 417 | print("Original array: ", array) 418 | array = SelectionSort(array) 419 | print("SelectionSort: ", array) 420 | 421 | ``` 422 | 423 | 424 | 425 | 426 | 427 | 428 | ## 插入排序(Insertion Sort) 429 | 430 | **基本思想** 431 | 432 | 插入排序(insertion sort)又称直接插入排序(staright insertion sort),其是将未排序元素一个个插入到已排序列表中。对于未排序元素,在已排序序列中从后向前扫描,找到相应位置把它插进去;在从后向前扫描过程中,需要反复把已排序元素逐步向后挪,为新元素提供插入空间。 433 | 434 | **步骤** 435 | 436 | 1. 从第一个元素开始,该元素可以认为已经被排序; 437 | 2. 取出下一个元素(未排序),在已经排序的元素序列中从后向前扫描; 438 | 3. 如果该元素(已排序)大于新元素,将该元素移到下一位置(往前移动); 439 | 4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置; 440 | 5. 将新元素插入到该位置后; 441 | 6. 重复步骤2~5。 442 | 443 | **动图演示** 444 | 445 | ![插入排序图示](images/insertion_sort.gif) 446 | 447 | **复杂度分析** 448 | 449 | - 时间复杂度:最坏O(n2)、平均O(n2)、最好O(n) 450 | - 空间复杂度:O(n1) 451 | - 稳定性:稳定 452 | 453 | 举个例子(暴力手绘图) 454 | 455 | ![Insertion Sort](images/insertion_sort.png) 456 | 457 | **代码实现** 458 | 459 | - [insertion_sort.cpp](code/insertion_sort.cpp) 460 | 461 | 462 | ```c++ 463 | /* Summary: 插入排序(Insertion Sort) 464 | * Author: Amusi 465 | * Date: 2018-07-16 466 | * 467 | * Reference: 468 | * https://en.wikipedia.org/wiki/Insertion_sort 469 | * 470 | * 插入排序(insertion sort)又称直接插入排序(staright insertion sort),其是将未排序元素一个个插入到已排序列表中。对于未排序元素,在已排序序列中从后向前扫描,找到相应位置把它插进去;在从后向前扫描过程中,需要反复把已排序元素逐步向后挪,为新元素提供插入空间。 471 | * 472 | */ 473 | 474 | #include 475 | 476 | // 插入排序函数 477 | namespace alg{ 478 | template 479 | static void InsertionSort(T list[], int length) 480 | { 481 | // 从索引为1的位置开始遍历 482 | for (int i = 1; i < length; ++i) 483 | { 484 | T currentValue = list[i]; // 保存当前值 485 | int preIndex = i - 1; // 前一个索引值 486 | // 循环条件: 前一个索引值对应元素值大于当前值 && 前一个索引值大于等于0 487 | while (list[preIndex] > currentValue && preIndex >= 0){ 488 | list[preIndex + 1] = list[preIndex]; 489 | preIndex--; 490 | } 491 | list[preIndex + 1] = currentValue; 492 | } 493 | } 494 | } 495 | 496 | using namespace std; 497 | using namespace alg; 498 | 499 | 500 | int main() 501 | { 502 | int a[8] = { 5, 2, 5, 7, 1, -3, 99, 56 }; 503 | InsertionSort(a, 8); 504 | for (auto e : a) 505 | std::cout << e << " "; 506 | 507 | return 0; 508 | } 509 | ``` 510 | 511 | 512 | 513 | 514 | - [insertion_sort.py](code/insertion_sort.py) 515 | 516 | ```python 517 | ''' Summary: 插入排序(Insertion Sort) 518 | * Author: Amusi 519 | * Date: 208-07-16 520 | * 521 | * Reference: 522 | * https://en.wikipedia.org/wiki/Insertion_sort 523 | * https://www.cnblogs.com/wujingqiao/articles/8961890.html 524 | * 525 | * 插入排序(insertion sort)又称直接插入排序(staright insertion sort),其是将未排序元素一个个插入到已排序列表中。对于未排序元素,在已排序序列中从后向前扫描,找到相应位置把它插进去;在从后向前扫描过程中,需要反复把已排序元素逐步向后挪,为新元素提供插入空间。 526 | * 527 | ''' 528 | 529 | def InsertionnSort(array): 530 | lengths = len(array) 531 | # 从索引位置1开始 532 | for i in range(1, lengths): 533 | currentValue = array[i] # 当前索引对应的元素数值 534 | preIndex = i-1 # 前一个索引位置 535 | # 循环条件: 前一个索引对应元素值大于当前值,前一个索引值大于等于0 536 | while array[preIndex] > currentValue and preIndex>=0: 537 | array[preIndex+1] = array[preIndex] # 前一个索引对应元素值赋值给当前值 538 | preIndex -= 1 # 前一个索引位置-1 539 | # preIndex+1,实现元素交换 540 | array[preIndex+1] = currentValue 541 | 542 | return array 543 | 544 | 545 | array = [1,3,8,5,2,10,7,16,7,4,5] 546 | print("Original array: ", array) 547 | array = InsertionnSort(array) 548 | print("InsertionnSort: ", array) 549 | 550 | ``` 551 | 552 | 553 | 554 | 555 | 556 | ## 希尔排序(Shell Sort) 557 | 558 | **基本思想** 559 | 560 | 设待排序元素序列有n个元素,首先取一个整数increment(小于n)作为间隔将全部元素分为increment个子序列,所有距离为increment的元素放在同一个子序列中,在每一个子序列中分别实行直接插入。 561 | 562 | 注:在[希尔排序算法](https://en.wikipedia.org/wiki/Shellsort)提出之前,排序算法的时间复杂度都为O(n^2),如冒泡排序、选择排序和插入排序。而希尔排序算法是突破这个时间复杂度的第一批算法之一。该复杂度为O(nlogn),其实直接插入排序算法的改进版,也称为缩小增量排序。**希尔排序是直接插入排序的一种改进,减少了其复制的次数,速度要快很多**。原因是,当n值很大时,数据项每一趟排序需要移动的个数很少,但数据项的距离很长;当n值减小时,每一趟需要移动的数据增多。正是因为这两种情况的结合才使得希尔排序效率比插入排序高很多。 563 | 564 | **步骤** 565 | 566 | 先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述: 567 | 568 | - 选择一个增量序列t1,t2,…,tk 569 | - 按增量序列个数k,对序列进行k 趟排序; 570 | - 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。 571 | 572 | 注:增量的初始值一般为序列长度的一半,然后之后每次再自身减半。 573 | 574 | **动图演示** 575 | 576 | ![希尔排序](images/shell_sort01.gif) 577 | 578 | 上图是不是很难理解,那么来看看这个! 579 | 580 | ![](images/shell_sort02.png) 581 | 582 | 说实话,看了上面两个图,我还是有点不理解,不怕,我又找了下面这幅图像。 583 | 584 | 简单介绍一下: 585 | 586 | 对于[592, 401, 874, 141, 348, 72, 911, 887, 820, 283]序列,一共10个元素。 587 | 588 | **第一次,设置增量为5=10/2**,所以有5个子序列:[592,72]、[401,911]、[874,887]、[141,820]和[348,283]。然后对每个子序列进行插入排序,结果是[72,592]、[401,911]、[874,887]、[141,820]和[283,348]。注意,这些元素在序列中的位置初始是不变的,只会随着部分子序列间元素的位置变化而变化,比如[592,72]在原来的序列中索引是[0,5],之后变成了[5,0];而[401,911]的序列索引是[1,6],第一次处理后,索引值不变。 589 | 590 | 总之,第一次处理的结果是将**[592, 401, 874, 141, 348, 72, 911, 887, 820, 283]—> [72, 401, 874, 141, 283, 592, 911, 887, 820, 348]**。 591 | 592 | **第二次,设置增量为2=5/2**,所以有2个子序列:[72, 874, 283, 911, 820]和[401, 141, 592, 887, 348]。然后对每个子序列进行插入排序,[72, 874, 283, 911, 820]的结果是[72, 283, 820, 874, 911],而[401, 141, 292, 887, 348]的结果是[141, 292, 348, 401, 887]。 593 | 594 | 总之,第二次处理的结果是将 **[72, 401, 874, 141, 283, 592, 911, 887, 820, 348]—>[72, 141, 283, 292, 820, 348, 874, 401, 911, 997]**。 595 | 596 | **第三次,设置增量为1=2/2**,所以有1个序列,就是上述生成的序列[72, 141, 283, 292, 820, 348, 874, 401, 911, 997]。然后进行插入排序,其结果为[72, 141, 283, 292, 348, 401, 820, 874, 911, 997]。 597 | 598 | 总之,第三次处理的结果是将 **[72, 141, 283, 292, 820, 348, 874, 401, 911, 997]—>[72, 141, 283, 292, 348, 401, 820, 874, 911, 997]**。 599 | 600 | 其实本质上还是利用了插入排序,但这里通过增量作用,相当于添加了预处理,减少插入排序中移动元素的次数,提高了效率。通过"增量"预处理,使得希尔排序算法时间复杂度降低。 601 | 602 | ![](images/shell_sort03.jpg) 603 | 604 | **复杂度分析** 605 | 606 | 希尔排序的时间复杂度与增量序列的选取有关。 607 | 608 | 时间复杂度: 609 | 610 | - 平均:O(n^1.3) 611 | - 最差:O(n2) 612 | - 最好:O(n) 613 | 614 | 空间复杂度:O(1) 615 | 616 | 稳定性:不稳定 617 | 618 | **代码实现** 619 | 620 | [shell_sort.cpp](code/shell_sort.cpp) 621 | 622 | ```cpp 623 | /* Summary: 希尔排序(Shell Sort) 624 | * Author: Amusi 625 | * Date: 2018-09-23 626 | * 627 | * Reference: 628 | * https://en.wikipedia.org/wiki/Shellsort 629 | * https://www.geeksforgeeks.org/shellsort/ 630 | * 希尔排序(shell sort):设待排序元素序列有n个元素,首先取一个整数increment(小于n)作为间隔将全部元素分为increment个子序列,所有距离为increment的元素放在同一个子序列中,在每一个子序列中分别实行直接插入。 631 | * 632 | */ 633 | 634 | #include 635 | 636 | // 希尔排序函数(基于快速插入排序) 637 | namespace alg{ 638 | template 639 | static void ShellSort(T list[], int n) 640 | { 641 | // 设置增量:以n/2为初始gap,然后逐渐减小gap(每次缩小为上次gap的一半) 642 | for (int gap = n / 2; gap > 0; gap /= 2){ 643 | // 遍历当前趟,对每个子序列进行插入排序 644 | for (int i = gap; i < n; i++){ 645 | int temp = list[i]; 646 | int j = 0; 647 | // 遍历子序列 648 | for (j = i; j >= gap && list[j - gap]>temp; j -= gap) 649 | list[j] = list[j - gap]; 650 | 651 | list[j] = temp; 652 | } 653 | } 654 | } 655 | } 656 | 657 | using namespace std; 658 | using namespace alg; 659 | 660 | 661 | int main() 662 | { 663 | int a[8] = { 5, 2, 5, 7, 1, -3, 99, 56 }; 664 | int n = sizeof(a) / sizeof(a[0]); 665 | ShellSort(a, n); 666 | for (auto e : a) 667 | std::cout << e << " "; 668 | 669 | return 0; 670 | } 671 | ``` 672 | 673 | 674 | 675 | [shell_sort.py](code/shell_sort.py) 676 | 677 | ```python 678 | ''' 679 | * Summary: 希尔排序(Shell Sort) 680 | * Author: Amusi 681 | * Date: 2018-09-23 682 | * 683 | * Reference: 684 | * https://en.wikipedia.org/wiki/Shellsort 685 | * https://www.geeksforgeeks.org/shellsort/ 686 | * 希尔排序(shell sort):设待排序元素序列有n个元素,首先取一个整数increment(小于n)作为间隔将全部元素分为increment个子序列,所有距离为increment的元素放在同一个子序列中,在每一个子序列中分别实行直接插入。 687 | * 688 | * 689 | ''' 690 | 691 | def ShellSort(array): 692 | lengths = len(array) 693 | # 初始化gap 694 | gap = lengths//2 695 | # 减少增量,遍历子序列进行插入排序 696 | while(gap > 0): 697 | for i in range(gap, lengths): 698 | # 699 | temp = array[i] 700 | j = i 701 | # 子序列插入排序 702 | while j>=gap and array[j-gap]>temp: 703 | array[j] = array[j-gap] 704 | j -= gap 705 | 706 | array[j] = temp 707 | 708 | gap = gap//2 709 | 710 | return array 711 | 712 | 713 | array = [1,3,8,5,2,10,7,16,7,4,5] 714 | print("Original array: ", array) 715 | array = ShellSort(array) 716 | print("InsertionnSort: ", array) 717 | ``` 718 | 719 | 720 | 721 | 参考: 722 | 723 | - [Shell Sort](https://www.geeksforgeeks.org/shellsort/) 724 | - [理解希尔排序的排序过程](https://blog.csdn.net/weixin_37818081/article/details/79202115) 725 | - [图解排序算法(二)之希尔排序](https://www.cnblogs.com/chengxiao/p/6104371.html) 726 | 727 | 728 | 729 | 730 | 731 | ## 堆排序(Heap Sort) 732 | 733 | **基本思想** 734 | 735 | [堆排序(heap sort)](https://en.wikipedia.org/wiki/Heapsort):将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。 736 | 737 | 注:堆排序是一种选择排序,指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。 738 | 739 | 在介绍堆排序之前,先了解一下什么是**堆(heap)**? 740 | 741 | **堆** 742 | 743 | 堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图: 744 | 745 | ![堆结构](images/heap.png) 746 | 747 | 同时,我们对堆的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子: 748 | 749 | ![](images/heap2.png) 750 | 751 | 该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是: 752 | 753 | **大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2] ** 754 | 755 | **小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2] ** 756 | 757 | ok,了解了这些定义。接下来,我们来看看堆排序的基本思想及基本步骤: 758 | 759 | **步骤** 760 | 761 | - 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区; 762 | - 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n]; 763 | - 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。 764 | 765 | **动图演示** 766 | 767 | ![堆排序](images/heap_sort.gif) 768 | 769 | 看到这里,你可能还是晕乎乎的,下面看个讲解示例: 770 | 771 | **步骤一 构造初始堆。将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)。** 772 | 773 | a.假设给定无序序列结构如下 774 | 775 | ![img](images/heap_p1.png) 776 | 777 | b.此时我们从最后一个非叶子结点开始(叶结点自然不用调整,第一个非叶子结点 arr.length/2-1=5/2-1=1,也就是下面的6结点),从左至右,从下至上进行调整。 778 | 779 | ![img](images/heap_p2.png) 780 | 781 | c.找到第二个非叶节点4,由于[4,9,8]中9元素最大,4和9交换。 782 | 783 | ![img](images/heap_p3.png) 784 | 785 | d.这时交换导致了子根[4,5,6]结构混乱,继续调整,[4,5,6]中6最大,交换4和6。 786 | 787 | ![img](images/heap_p4.png) 788 | 789 | 此时,我们就将一个无需序列构造成了一个大顶堆。 790 | 791 | **步骤二 将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换。** 792 | 793 | a.将堆顶元素9和末尾元素4进行交换 794 | 795 | ![img](images/heap_p5.png) 796 | 797 | b.重新调整结构,使其继续满足堆定义 798 | 799 | ![img](images/heap_p6.png) 800 | 801 | c.再将堆顶元素8与末尾元素5进行交换,得到第二大元素8. 802 | 803 | ![img](images/heap_p7.png) 804 | 805 | 后续过程,继续进行调整,交换,如此反复进行,最终使得整个序列有序 806 | 807 | ![img](images/heap_p8.png) 808 | 809 | 再简单总结下堆排序的基本思路: 810 | 811 | **a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;** 812 | 813 | **b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;** 814 | 815 | **c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。** 816 | 817 | **复杂度分析** 818 | 819 | 堆排序整体主要由构建初始堆+交换堆顶元素和末尾元素并重建堆两部分组成。其中构建初始堆经推导复杂度为O(n),在交换并重建堆的过程中,需交换n-1次,而重建堆的过程中,根据完全二叉树的性质,[log2(n-1),log2(n-2)...1]逐步递减,近似为nlogn。所以堆排序时间复杂度一般认为就是O(nlogn)级。 820 | 821 | 时间复杂度: 822 | 823 | - 最差:O(nlogn) 824 | - 平均:O(nlogn) 825 | - 最优:O(nlogn) 826 | 827 | 空间复杂度:O(n) 828 | 829 | 稳定性:不稳定 830 | 831 | **代码实现** 832 | 833 | - [ ] TODO 834 | 835 | 836 | 837 | 参考: 838 | 839 | - [图解排序算法(三)之堆排序](https://www.cnblogs.com/chengxiao/p/6129630.html) 840 | - [heap-sort](https://www.geeksforgeeks.org/heap-sort/) 841 | 842 | 843 | 844 | 845 | 846 | ## 归并排序(Merge Sort) 847 | 848 | **基本思想** 849 | 850 | [归并排序(merge sort)](https://en.wikipedia.org/wiki/Merge_sort): 851 | 852 | **步骤** 853 | 854 | - [ ] TODO 855 | 856 | 857 | 858 | ## 快速排序(Quick Sort) 859 | 860 | **基本思想** 861 | 862 | [快速排序(quick sort)](https://en.wikipedia.org/wiki/Quicksort):通过一趟排序将待排列表分隔成独立的两部分,其中一部分的所有元素均比另一部分的所有元素小,则可分别对这两部分继续重复进行此操作,以达到整个序列有序。(这个过程,我们可以使用递归快速实现) 863 | 864 | **步骤** 865 | 866 | 快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下: 867 | 868 | - 从数列中挑出一个元素,称为 “基准”(pivot),这里我们通常都会选择第一个元素作为prvot; 869 | - 重新排序数列,将比基准值小的所有元素放在基准前面,比基准值大的所有元素放在基准的后面(相同的数可以到任一边)。这样操作完成后,该基准就处于新数列的中间位置,即将数列分成了两部分。这个操作称为分区(partition)操作; 870 | - 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数按上述操作进行排序。这里的递归结束的条件是序列的大小为0或1。此时递归结束,排序就完成了。 871 | 872 | **动图演示** 873 | 874 | ![Quick Sort](images/quick_sort.gif) 875 | 876 | **复杂度分析** 877 | 878 | - 时间复杂度: 879 | - 平均情况:O(nlogn) 880 | - 最好情况:O(nlong) 881 | - 最坏情况:O(n^2) 882 | 其实不难理解,快排的最坏情况就已经退化为冒泡排序了!所以大家深入理解就会发现各个排序算法是相通的,学习时间久了你就会发现它们的内在联系!是不是很神奇哈~ 883 | - 空间复杂度: 884 | - 平均情况:O(logn) 885 | - 最好情况:O(logn) 886 | - 最坏情况:O(n) 887 | - 稳定性:不稳定 (由于关键字的比较和交换是跳跃进行的,所以快速排序是一种不稳定的排序方法~) 888 | 889 | 举个例子(暴力手绘图) 890 | 891 | ![](images/quick_sort.png) 892 | 893 | 894 | 895 | **代码实现** 896 | 897 | 注:下面都是利用递归法实现快速排序。 898 | 899 | [quick_sort.cpp](code/quick_sort.cpp) 900 | 901 | ```c++ 902 | /* Summary: 快速排序(Quick Sort) 903 | * Author: Amusi 904 | * Date: 2018-07-28 905 | * 906 | * Reference: 907 | * https://en.wikipedia.org/wiki/Quicksort 908 | * 909 | * 快速排序(quick sort):通过一趟排序将待排列表分隔成独立的两部分,其中一部分的所有元素均比另一部分的所有元素小,则可分别对这两部分继续重复进行此操作,以达到整个序列有序。(这个过程,我们可以使用递归快速实现) 910 | * 911 | */ 912 | 913 | #include 914 | 915 | // 快速排序函数(递归法) 916 | namespace alg{ 917 | template 918 | static void QuickSort(T list[], int start, int end) 919 | { 920 | int i = start; 921 | int j = end; 922 | // 结束排序(左右两索引值见面,即相等,或者左索引>右索引) 923 | if (i >= j) 924 | return; 925 | // 保存首个数值(以首个数值作为基准) 926 | // 这个位置很重要,一定要在if i >= j判断语句之后,否则就索引溢出了 927 | T pivot = list[i]; 928 | 929 | // 一次排序,i和j的值不断的靠拢,然后最终停止,结束一次排序 930 | while (i < j){ 931 | // 一层循环实现从左边起大于基准的值替换基准的位置,右边起小于基准的值位置替换从左起大于基准值的索引 932 | //(从右往左)和最右边的比较,如果 >= pivot, 即满足要求,不需要交换,然后j - 1,慢慢左移,即拿基准值与前一个值比较; 如果值pivot,那么就交换位置 937 | while (i < j && pivot >= list[i]) 938 | ++i; 939 | list[j] = list[i]; 940 | } 941 | // 列表中索引i的位置为基准值,i左边序列都是小于基准值的,i右边序列都是大于基准值的,当前基准值的索引为i,之后不变 942 | list[i] = pivot; 943 | // 左边排序 944 | QuickSort(list, start, i-1); 945 | // 右边排序 946 | QuickSort(list, i+1, end); 947 | } 948 | } 949 | 950 | using namespace std; 951 | using namespace alg; 952 | 953 | 954 | int main() 955 | { 956 | int a[8] = { 5, 2, 5, 7, 1, -3, 99, 56 }; 957 | QuickSort(a, 0, sizeof(a)/sizeof(a[0]) - 1); 958 | for (auto e : a) 959 | std::cout << e << " "; 960 | 961 | return 0; 962 | } 963 | ``` 964 | 965 | 966 | 967 | [quick_sort.py](code/quick_sort.py) 968 | 969 | ```python 970 | ''' Summary: 快速排序(Quick Sort) 971 | * Author: Amusi 972 | * Date: 208-07-28 973 | * 974 | * Reference: 975 | * https://en.wikipedia.org/wiki/Quicksort 976 | * https://www.cnblogs.com/wujingqiao/articles/8961890.html 977 | * https://github.com/apachecn/LeetCode/blob/master/src/py3.x/sort/QuickSort.py 978 | * 快速排序(quick sort):通过一趟排序将待排列表分隔成独立的两部分,其中一部分的所有元素均比另一部分的所有元素小,则可分别对这两部分继续重复进行此操作,以达到整个序列有序。(这个过程,我们可以使用递归快速实现) 979 | * 980 | ''' 981 | 982 | def QuickSort(array, start, end): 983 | lengths = len(array) 984 | i = start 985 | j = end 986 | # 结束排序(左右两索引值见面,即相等,或者左索引>右索引) 987 | if i >= j: 988 | return # 返回空即可 989 | # 保存首个数值(以首个数值作为基准) 990 | # 这个位置很重要,一定要在if i>=j判断语句之后,否则就索引溢出了 991 | pivot = array[i] 992 | # 一次排序,i和j的值不断的靠拢,然后最终停止,结束一次排序 993 | while i < j: 994 | # (从右往左)和最右边的比较,如果>=pivot,即满足要求,不需要交换,然后j-1,慢慢左移,即拿基准值与前一个值比较; 如果值pivot,那么就交换位置 1000 | while i < j and pivot >= array[i]: 1001 | # print(pivot, array[i], '*' * 30) 1002 | i += 1 1003 | array[j] = array[i] 1004 | # 列表中索引i的位置为基准值,i左边序列都是小于基准值的,i右边序列都是大于基准值的,当前基准值的索引为i,之后不变 1005 | array[i] = pivot 1006 | # 左边排序 1007 | QuickSort(array, start, i-1) 1008 | # 右边排序 1009 | QuickSort(array, i+1, end) 1010 | 1011 | #return array 1012 | 1013 | if __name__ == "__main__": 1014 | array = [1,3,8,5,2,10,7,16,7,4,5] 1015 | print("Original array: ", array) 1016 | #array = QuickSort(array, 0, len(array)-1) 1017 | # 因为python中的list对象是可变对象,所以在函数做"形参"时,是相当于按引用传递 1018 | # 所以不写成返回值的形式,也是OK的 1019 | QuickSort(array, 0, len(array)-1) 1020 | print("QuickSort: ", array) 1021 | 1022 | ``` 1023 | 1024 | 1025 | 1026 | # 参考 1027 | 1028 | **[1](推荐)**[《大话数据结构》](https://book.douban.com/subject/6424904/) 1029 | 1030 | **[2](推荐)**[十大经典排序算法(动图演示)](https://www.cnblogs.com/onepixel/p/7674659.html) 1031 | 1032 | **[3](推荐)**[轻松搞定十大排序算法(C++版)](https://blog.csdn.net/opooc/article/details/80994353) 1033 | 1034 | **[4](推荐)**[从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用](https://blog.csdn.net/han_xiaoyang/article/details/12163251) 1035 | 1036 | **[5](推荐)**[排序算法时间复杂度、空间复杂度、稳定性比较](https://blog.csdn.net/yushiyi6453/article/details/76407640) 1037 | 1038 | **[6](推荐)**[十大排序算法和七大查找算法总结(原理讲解和Python代码实现)---(一)排序算法篇](https://www.cnblogs.com/wujingqiao/p/8961890.html) 1039 | 1040 | **[7]** [常见排序算法C++总结](https://www.cnblogs.com/zyb428/p/5673738.html) 1041 | 1042 | **[8]** [十大经典排序算法(JavaScript版)](http://web.jobbole.com/87968/) 1043 | 1044 | **[9]** [八大排序算法总结(JAVA版)](http://www.runoob.com/w3cnote/sort-algorithm-summary.html) 1045 | 1046 | **[10]** [C++代码](https://github.com/xtaci/algorithms/blob/master/include/selection_sort.h) --------------------------------------------------------------------------------