├── .editorconfig ├── .gitignore ├── Array ├── Contains Duplicate │ ├── ContainsDuplicate.cpp │ └── README.md ├── Intersection of Two Arrays │ ├── IntersectionOfTwoArrays.cpp │ ├── IntersectionOfTwoArraysII.cpp │ └── README.md ├── Maximum Subarray │ ├── MaximumSubarray.cpp │ └── README.md ├── Merge Sorted Array │ ├── MergeSortedArray.cpp │ └── README.md ├── Move Zeroes │ ├── MoveZeroes.cpp │ └── README.md ├── Plus One │ ├── PlusOne.cpp │ └── README.md ├── README.md ├── Remove Duplicates from Sorted Array │ ├── README.md │ ├── RemoveDuplicatesFromSortedArray.cpp │ └── RemoveDuplicatesFromSortedArrayII.cpp ├── Remove Element │ ├── README.md │ └── RemoveElement.cpp ├── Rotate Array │ ├── README.md │ └── RotateArray.cpp ├── Search Insert Position │ ├── README.md │ └── SearchInsertPosition.cpp ├── Search a 2D Matrix │ ├── README.md │ └── Search2DMatrix.cpp ├── Sort Colors │ ├── README.md │ └── SortColors.cpp ├── Third Maximum Number │ ├── README.md │ └── ThirdMaximumNumber.cpp └── Two Sum │ ├── README.md │ ├── TwoSum.cpp │ └── TwoSumII.cpp ├── Bit Manipulation ├── README.md ├── Single Number │ ├── README.md │ └── SingleNumber.cpp └── SumOfTwoIntegers │ ├── README.md │ └── SumOfTwoIntegers.cpp ├── Graph ├── Component │ └── Component.h ├── DenseGraph │ └── DenseGraph.h ├── FindPath │ └── FindPath.h ├── Minimum Span Tree │ ├── Kruskal │ │ ├── KruskalMST.h │ │ ├── MinHeap.h │ │ ├── ReadWeightedGraph.h │ │ ├── UnionFind.h │ │ ├── WeightedDenseGraph.h │ │ ├── WeightedGraphEdge.h │ │ ├── WeightedSparseGraph.h │ │ ├── main.cpp │ │ └── test.txt │ ├── Prim │ │ ├── LazyPrimMST │ │ │ ├── LazyPrimMST.h │ │ │ ├── MinHeap.h │ │ │ ├── ReadWeightedGraph.h │ │ │ ├── WeightedDenseGraph.h │ │ │ ├── WeightedGraphEdge.h │ │ │ ├── WeightedSparseGraph.h │ │ │ ├── main.cpp │ │ │ └── test.txt │ │ └── PrimMST │ │ │ ├── IndexMinHeap.h │ │ │ ├── PrimMST.h │ │ │ ├── ReadWeightedGraph.h │ │ │ ├── WeightedDenseGraph.h │ │ │ ├── WeightedGraphEdge.h │ │ │ ├── WeightedSparseGraph.h │ │ │ ├── main.cpp │ │ │ └── test.txt │ ├── README.md │ └── Weighted Graph │ │ ├── ReadWeightedGraph.h │ │ ├── WeightedDenseGraph.h │ │ ├── WeightedGraphEdge.h │ │ ├── WeightedSparseGraph.h │ │ ├── main.cpp │ │ └── test.txt ├── README.md ├── ReadGraph │ └── ReadGraph.h ├── Shortest-path Algorithms │ ├── Bellman Ford │ │ ├── BellmanFord.h │ │ ├── ReadWeightedGraph.h │ │ ├── WeightedDenseGraph.h │ │ ├── WeightedGraphEdge.h │ │ ├── WeightedSparseGraph.h │ │ ├── main.cpp │ │ └── test.txt │ ├── Dijkstra │ │ ├── Dijkstra.h │ │ ├── IndexMinHeap.h │ │ ├── ReadWeightedGraph.h │ │ ├── WeightedDenseGraph.h │ │ ├── WeightedGraphEdge.h │ │ ├── WeightedSparseGraph.h │ │ ├── main.cpp │ │ └── test.txt │ └── README.md ├── ShortestPath │ └── ShortestPath.h ├── SparseGraph │ └── SparseGraph.h └── TestMain │ ├── ComponentMain.cpp │ ├── FindPathMain.cpp │ ├── GraphIteratorMain.cpp │ ├── ReadGraphMain.cpp │ ├── ShortestPathMain.cpp │ └── test.txt ├── Hash Table ├── HashTableExerciseForCS210Lab │ ├── README.md │ ├── hashtbl.cpp │ ├── hashtbl.h │ ├── listlnk.cpp │ ├── listlnk.h │ ├── login.cpp │ └── password.dat └── README.md ├── LICENSE ├── Linked List ├── Add Two Numbers │ ├── AddTwoNumbers.cpp │ ├── AddTwoNumbersII.cpp │ └── README.md ├── Convert Sorted List to Binary Search Tree │ ├── ConvertSortedListtoBinarySearchTree.cpp │ └── README.md ├── Copy List with Random Pointer │ ├── CopyListwithRandomPointer.cpp │ └── README.md ├── Delete Node in a Linked List │ ├── DeleteNode.cpp │ └── README.md ├── Design Phone Directory │ └── README.md ├── Insertion Sort List │ ├── InsertionSortList.cpp │ └── README.md ├── Intersection of Two Linked Lists │ ├── IntersectionOfTwoLinkedLists.cpp │ └── README.md ├── Linked List Cycle │ ├── Linked List Cycle.PNG │ ├── LinkedListCycle.cpp │ └── README.md ├── Merge Two Sorted Lists │ ├── MergeTwoSortedLists.cpp │ └── README.md ├── Merge k Sorted Lists │ ├── MergeKSortedLists.cpp │ └── README.md ├── Odd Even Linked List │ ├── OddEvenLinkedList.cpp │ └── README.md ├── Palindrome Linked List │ ├── PalindromeLinkedList.cpp │ └── README.md ├── Partition List │ ├── PartitionList.cpp │ └── README.md ├── Plus One Linked List │ ├── PlusOneLinkedList.cpp │ └── README.md ├── README.md ├── Remove Duplicates from Sorted List │ ├── README.md │ ├── RemoveDuplicatesFromSortedList.cpp │ └── RemoveDuplicatesFromSortedListII.cpp ├── Remove Linked List Elements │ ├── README.md │ └── RemoveLinkedListElements.cpp ├── Remove Nth Node From End of List │ ├── README.md │ └── RemoveNthNodeFromEndofList.cpp ├── Reorder List │ ├── README.md │ └── ReorderList.cpp ├── Reverse Linked List │ ├── README.md │ ├── ReverseLinkedList.cpp │ └── ReverseLinkedListII.cpp ├── Reverse Nodes in k-Group │ ├── README.md │ └── ReverseNodesInk-Group.cpp ├── Rotate List │ ├── README.md │ └── RotateList.cpp ├── Sort List │ ├── README.md │ └── SortList.cpp └── Swap Nodes in Pairs │ ├── README.md │ └── SwapNodesInPairs.cpp ├── Math ├── README.md └── Reverse Integer │ ├── README.md │ └── ReverseInteger.cpp ├── Queue ├── Moving Average from Data Stream │ ├── MovingAverageFromDataStream.cpp │ └── README.md └── README.md ├── README.md ├── Sort ├── BubbleSort │ ├── Cpp │ │ └── BubbleSort.cpp │ └── Java │ │ └── BubbleSort.java ├── HeapSort │ ├── Cpp │ │ ├── MaxHeap.h │ │ └── MaxHeapSort.cpp │ └── Java │ │ ├── MaxHeap.java │ │ ├── MaxHeapSort.java │ │ ├── MinHeap.java │ │ └── MinHeapSort.java ├── InsertionSort │ ├── Cpp │ │ └── InsertionSort.cpp │ └── Java │ │ └── InsertionSort.java ├── MergeSort │ ├── Cpp │ │ └── MergeSort.cpp │ └── Java │ │ └── MergeSort.java ├── QuickSort │ ├── Cpp │ │ ├── QuickSort.cpp │ │ └── QuickSortThreeWays.cpp │ └── Java │ │ ├── QuickSort.java │ │ └── QuickSortThreeWays.java ├── README.md ├── SelectionSort │ ├── Cpp │ │ └── SelectionSort.cpp │ └── Java │ │ └── SelectionSort.java └── ShellSort │ ├── Cpp │ └── ShellSort.cpp │ └── Java │ └── ShellSort.java ├── Stack ├── Min Stack │ ├── MinStack.cpp │ └── README.md ├── README.md └── Valid Parentheses │ ├── README.md │ └── ValidParentheses.cpp ├── String ├── Add Binary │ ├── AddBinary.cpp │ └── README.md ├── Add Strings │ ├── AddStrings.cpp │ └── README.md ├── Implement strStr │ ├── ImplementstrStr.cpp │ └── README.md ├── README.md ├── Reverse String │ ├── README.md │ ├── ReverseStringI.cpp │ └── ReverseStringII.cpp ├── Valid Anagram │ ├── README.md │ └── ValidAnagram.cpp └── Valid Palindrome │ ├── README.md │ ├── ValidPalindrome.cpp │ └── ValidPalindromeII.cpp ├── Tree ├── AVL Tree │ └── README.md ├── B Tree │ ├── B-树和B+树的应用.md │ └── README.md ├── Binary Search Tree │ ├── Binary Search Method │ │ ├── Cpp │ │ │ └── BinarySearchMethod.cpp │ │ └── Java │ │ │ └── BinarySearchMethod.java │ ├── Binary Search Tree │ │ ├── Cpp │ │ │ └── BinarySearchTree.cpp │ │ └── Java │ │ │ └── BinarySearchTree.java │ └── README.md ├── IndexHeap │ ├── IndexMaxHeap │ │ ├── Cpp │ │ │ └── IndexMaxHeap.cpp │ │ └── Java │ │ │ └── IndexMaxHeap.java │ ├── IndexMinHeap │ │ ├── Cpp │ │ │ └── IndexMinHeap.cpp │ │ └── Java │ │ │ └── IndexMinHeap.java │ └── README.md ├── LeetCode-Tree │ ├── Balanced Binary Tree │ │ ├── BalancedBinaryTree.cpp │ │ └── README.md │ ├── Binary Tree Inorder Traversal │ │ ├── BinaryTreeInorderTraversal.cpp │ │ └── README.md │ ├── Binary Tree Level Order Traversal │ │ ├── BinaryTreeLevelOrderTraversal.cpp │ │ └── README.md │ ├── Binary Tree Postorder Traversal │ │ ├── BinaryTreePostorderTraversal.cpp │ │ └── README.md │ ├── Binary Tree Preorder Traversal │ │ ├── BinaryTreePreorderTraversal.cpp │ │ └── README.md │ ├── Convert Sorted Array to Binary Search Tree │ │ ├── ConvertSortedArrayToBinarySearchTree.cpp │ │ └── README.md │ ├── Invert Binary Tree │ │ ├── InvertBinaryTree.cpp │ │ └── README.md │ ├── Longest Univalue Path │ │ ├── LongestUnivaluePath.cpp │ │ └── README.md │ ├── Maximum Depth of Binary Tree │ │ ├── MaximumDepthOfBinaryTree.cpp │ │ └── README.md │ ├── Merge Two Binary Trees │ │ ├── MergeTwoBinaryTrees.cpp │ │ └── README.md │ ├── Minimum Depth of Binary Tree │ │ ├── MinimumDepthOfBinaryTree.cpp │ │ └── README.md │ ├── Path Sum │ │ ├── PathSum.cpp │ │ ├── PathSumII.cpp │ │ ├── PathSumIII.cpp │ │ └── README.md │ ├── README.md │ └── Same Tree │ │ ├── README.md │ │ └── SameTree.cpp ├── RB-tree │ └── README.md ├── README.md └── image │ └── Binary Search Method.PNG ├── Union Find ├── PathCompressionByUnionFind.cpp ├── QuickFind.cpp ├── QuickUnion.cpp ├── README.md ├── UnionFindOptimizeByRank.cpp └── UnionFindOptimizeBySize.cpp ├── image ├── Linked List(I).PNG ├── Linked List(II).PNG └── Linked List(III).PNG └── sfo ├── 1. 2D array search.md ├── 10. number of 1.md ├── 11. find kth to tail.md ├── 12. reverse list.md ├── 13. rect cover.md ├── 13.PNG ├── 14. reorder array.md ├── 15. power.md ├── 16. merge.md ├── 17. mirror.md ├── 18. has subtree.md ├── 19. print from top to bottom.md ├── 2. replace space.md ├── 20. is pop order.md ├── 21. min stack.md ├── 22. print matrix.md ├── 23. more than half num.md ├── 24. verify squence of BST.md ├── 25. get least numbers.md ├── 26. find greatest sum of subarray.md ├── 27. find path.md ├── 28. tree depth.md ├── 29. first not repeating char.md ├── 3. print list from tail to head.md ├── 30. permutation.md ├── 31. sum.md ├── 32. duplicate.md ├── 33. find first common node.md ├── 34. get number of k.md ├── 35. clone.md ├── 36. find nums appear once.md ├── 37. print min number.md ├── 38. get ugly number.md ├── 39. find numbers with sum.md ├── 4. fibonacci.md ├── 40. number of 1 between 1 and N.md ├── 41. left rotate string.md ├── 42. reverse sentence.md ├── 43. balanced binary tree.md ├── 44. delete duplication.md ├── 45. find continuous sequence.md ├── 46. add.md ├── 47. entry node of loop.md ├── 48. inverse pairs.md ├── 49. str to int.md ├── 5. jump floor.md ├── 50. is symmetrical.md ├── 51. get next.md ├── 52. is continuous.md ├── 53. last remaining.md ├── 54. multiply.md ├── 55. print.md ├── 56. KthNode.md ├── 57. print2.md ├── 58. first appearing once.md ├── 59. max in windows.md ├── 6. implement a queue with two stacks.md ├── 60. moving count.md ├── 61. is numeric.md ├── 62. match.md ├── 63. has path.md ├── 64. get median.md ├── 65. serialize.md ├── 66. convert.md ├── 67. cut rope.md ├── 7. min number in rotate array.md ├── 8. jump floor ii.md ├── 9. reconstruct binary tree.md └── README.md /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # all files 5 | [*] 6 | indent_style = tab 7 | indent_size = 4 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Java class files 35 | *.class 36 | 37 | # Eclipse project files 38 | .classpath 39 | .project 40 | .metadata 41 | .settings 42 | 43 | # IntelliJ files 44 | .idea 45 | *.iml 46 | -------------------------------------------------------------------------------- /Array/Contains Duplicate/ContainsDuplicate.cpp: -------------------------------------------------------------------------------- 1 | // unordered_set 2 | class Solution { 3 | public: 4 | bool containsDuplicate(vector& nums) { 5 | unordered_set s; 6 | for(int i : nums){ 7 | if(s.count(i)) 8 | return true; 9 | s.insert(i); 10 | } 11 | return false; 12 | } 13 | }; 14 | 15 | // unordered_map 16 | class Solution { 17 | public: 18 | bool containsDuplicate(vector& nums) { 19 | unordered_map m; 20 | 21 | unsigned int n = nums.size(); 22 | 23 | for (unsigned int i = 0; i < n; i++) { 24 | if (m.find(nums[i]) != m.end()) { 25 | return true; 26 | } 27 | 28 | ++m[nums[i]]; 29 | } 30 | 31 | return false; 32 | } 33 | }; 34 | 35 | // sort 36 | class Solution { 37 | public: 38 | bool containsDuplicate(vector& nums) { 39 | 40 | if(nums.size() < 2) 41 | return false; 42 | 43 | sort(nums.begin(), nums.end()); 44 | 45 | for(int i = 0; i < (nums.size()-1); i++) { 46 | if(nums[i] == nums[i+1]) 47 | return true; 48 | } 49 | return false; 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /Array/Contains Duplicate/README.md: -------------------------------------------------------------------------------- 1 | ## Contains Duplicate「LeetCode 217」 2 | 3 | 题目:判断数组包含重复值 4 | 5 | ``` 6 | Given an array of integers, find if the array contains any duplicates. 7 | 8 | Your function should return true if any value appears at least twice in the array, 9 | 10 | and it should return false if every element is distinct. 11 | ``` 12 | 13 | 解题思路:(简单) 14 | 15 | 1. 对整形的数组,查找数组中是否有重复的数 16 | 2. 使用 unordered_map 遍历数组,哈希表 key 具有唯一性,如果数组中有重复,比如一个元素先进入 unordered_map,再次遍历相同元素,就能在 unordered_map 找到 17 | 18 | 也可以用 unordered_set 19 | 20 | 还有一种方法,对整个数组进行排序,然后判断前后元素是否有相等。 21 | -------------------------------------------------------------------------------- /Array/Intersection of Two Arrays/IntersectionOfTwoArrays.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector intersection(vector& nums1, vector& nums2) { 4 | 5 | set s(nums1.begin(), nums1.end()); 6 | 7 | set ret; 8 | 9 | for (int i = 0; i < nums2.size(); i++) { 10 | 11 | if (s.find(nums2[i]) != s.end()) { 12 | ret.insert(nums2[i]); 13 | } 14 | } 15 | 16 | return vector(ret.begin(), ret.end()); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /Array/Intersection of Two Arrays/IntersectionOfTwoArraysII.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector intersect(vector& nums1, vector& nums2) { 4 | map m; 5 | 6 | vector res; 7 | 8 | for (int i = 0; i < nums1.size(); i++) { 9 | m[nums1[i]]++; 10 | } 11 | 12 | for (int i = 0; i < nums2.size(); i++) { 13 | if (m[nums2[i]] > 0) { 14 | res.push_back(nums2[i]); 15 | m[nums2[i]]--; 16 | } 17 | } 18 | 19 | return res; 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /Array/Intersection of Two Arrays/README.md: -------------------------------------------------------------------------------- 1 | ## Intersection of Two Arrays「LeetCode 349」 2 | 3 | 题目:求两个数组的交集 4 | 5 | ``` 6 | Given two arrays, write a function to compute their intersection. 7 | 8 | Example: 9 | Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2]. 10 | 11 | Note: 12 | Each element in the result must be unique. 13 | The result can be in any order. 14 | ``` 15 | 16 | 解题思路:时间复杂度 O(nlogn),空间复杂度 O(n) 17 | 18 | 1. 题目要求是每个元素只能出现一次,出现的顺序可以是任意;结合这个条件,选用 set 关联性容器,该容器中的数据排好序,并且唯一 19 | 2. 第一步,将 nums1 数组的元素存储到 set1 中 20 | 3. 新建一个 set2 集合,对 nums2 中的所有元素遍历,再从 set1 查找 nums2 的元素是否已经存在,如果存在就插入到 set2 集合中。 21 | 22 | ## Intersection of Two Arrays II「LeetCode 350」 23 | 24 | 题目:求两个数组的交集,交集的结果出现多次,全部返回 25 | 26 | ``` 27 | Given two arrays, write a function to compute their intersection. 28 | 29 | Example: 30 | Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2, 2]. 31 | 32 | Note: 33 | Each element in the result should appear as many times as it shows in both arrays. 34 | The result can be in any order. 35 | Follow up: 36 | What if the given array is already sorted? How would you optimize your algorithm? 37 | What if nums1's size is small compared to nums2's size? Which algorithm is better? 38 | What if elements of nums2 are stored on disk, and the memory is limited 39 | such that you cannot load all elements into the memory at once? 40 | ``` 41 | 42 | 解题思路: 43 | 44 | 1. 两个数组交集,可能出现多次的元素,使用 map 或 unordered_map 关联性容器实现 45 | 2. map 第一个参数是数组的元素,第二个参数是数组元素出现个数 46 | 3. 把 nums1 先入 map 中,然后对 nums2 进行遍历,看 nums2 中每个元素在 map 中是否存在,如果存在,判断出现次数,依次存入到 vector 中 47 | -------------------------------------------------------------------------------- /Array/Maximum Subarray/MaximumSubarray.cpp: -------------------------------------------------------------------------------- 1 | // 遍历 2 | class Solution { 3 | public: 4 | int maxSubArray(vector& nums) { 5 | int curSum = 0, ret = INT_MIN; 6 | 7 | for (int number : nums) { 8 | curSum = max(number + curSum, number); 9 | ret = max(ret, curSum); 10 | } 11 | 12 | return ret; 13 | } 14 | }; 15 | 16 | // 分冶法 17 | class Solution { 18 | public: 19 | int maxSubArray(vector& nums) { 20 | if (nums.empty()) { 21 | return 0; 22 | } 23 | 24 | return doHelper(nums, 0, nums.size() - 1); 25 | } 26 | 27 | private: 28 | int doHelper(vector& nums, int left, int right) { 29 | if (left >= right) { 30 | return nums[left]; 31 | } 32 | 33 | int mid = left + (right - left) / 2; 34 | 35 | int leftMax = doHelper(nums, left, mid - 1); 36 | int rightMax = doHelper(nums, mid + 1, right); 37 | 38 | int midMax = nums[mid]; 39 | 40 | int temp = midMax; 41 | 42 | for (int i = mid - 1; i >= left; i--) { 43 | temp += nums[i]; 44 | midMax = max(midMax, temp); 45 | } 46 | 47 | temp = midMax; 48 | 49 | for (int i = mid + 1; i <= right; i++) { 50 | temp += nums[i]; 51 | midMax = max(midMax, temp); 52 | } 53 | 54 | return max(midMax, max(leftMax, rightMax)); 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /Array/Maximum Subarray/README.md: -------------------------------------------------------------------------------- 1 | ## Maximum Subarray「LeetCode 53」 2 | 3 | 题目:最大的子数组的和 4 | 5 | ``` 6 | Find the contiguous subarray within an array (containing at least one number) which has the largest sum. 7 | 8 | For example, given the array [-2,1,-3,4,-1,2,1,-5,4], 9 | the contiguous subarray [4,-1,2,1] has the largest sum = 6. 10 | 11 | click to show more practice. 12 | 13 | More practice: 14 | 15 | If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, 16 | which is more subtle. 17 | ``` 18 | 19 | 方法一:遍历,时间复杂度为 O(n) 20 | 21 | 1. 定义两个变量,一个存储返回值 ret,即最大的子数组的和,另一个变量为当前累加最大的值 curSum 22 | 2. 每遍历一个数字 number,比较 curSum + number 和 number 中的较大值存入 curSum 23 | 3. 然后再把 ret 和 curSum 中的较大值存入 ret 24 | 25 | 方法二:分冶法,时间复杂度为 O(nlogn) 26 | 27 | 这个分治法的思想就类似于二分搜索法 28 | 29 | 1. 把数组一分为二,分别找出左边和右边的最大子数组之和 30 | 2. 然后从中间开始向左右分别扫描,求出的最大值分别和左右两边得出的最大值相比较取最大的那一个 31 | -------------------------------------------------------------------------------- /Array/Merge Sorted Array/MergeSortedArray.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void merge(vector& nums1, int m, vector& nums2, int n) { 4 | int count = m + n - 1; // 合并后的长度 5 | 6 | --m; 7 | --n; 8 | 9 | while (m >= 0 && n >= 0) { // 从尾部往前扫 10 | if (nums1[m] > nums2[n]) { 11 | nums1[count--] = nums1[m--]; 12 | } else { 13 | nums1[count--] = nums2[n--]; 14 | } 15 | } 16 | 17 | while (n >= 0) { 18 | nums1[count--] = nums2[n--]; 19 | } 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /Array/Merge Sorted Array/README.md: -------------------------------------------------------------------------------- 1 | ## Merge Sorted Array「LeetCode 88」 2 | 3 | 题目:合并两个已排序的数组。 4 | 5 | ``` 6 | Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. 7 | 8 | Note: 9 | You may assume that nums1 has enough space (size that is greater or equal to m + n) to 10 | 11 | hold additional elements from nums2. The number of elements initialized in nums1 and nums2 12 | 13 | are m and n respectively. 14 | ``` 15 | 16 | 解题思路: 17 | 18 | 1. nums1 的长度为 m,nums2 的长度为 n,将两个已排序的数组合并,那么长度变为 m + n - 1 19 | 2. 对 nums1 和 nums2 进行从尾向前扫,先比较它们的最后一个元素的大小,把较大的那个插入到 m+n-1 的位置上,再依次向前推 20 | 3. 如果 nums1 中所有的元素都比 nums2 小,那么前 m 个还是 nums1 原来的内容,没有改变 21 | 4. 如果 nums1 中的数组比 nums2 大的,当 nums1 循环完了,nums2 中还有元素没加入 nums1, 22 | 直接用个循环把 nums2 中所有的元素赋值到 nums1 剩下的位置 23 | -------------------------------------------------------------------------------- /Array/Move Zeroes/MoveZeroes.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void moveZeroes(vector& nums) { 4 | int j = 0; 5 | 6 | for (int i = 0; i < nums.size(); i++) { 7 | if (nums[i]) { 8 | nums[j++] = nums[i]; 9 | } 10 | } 11 | 12 | for (; j < nums.size(); j++) { 13 | nums[j] = 0; 14 | } 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /Array/Move Zeroes/README.md: -------------------------------------------------------------------------------- 1 | ## Move Zeroes「LeetCode 283」 2 | 3 | 题目:给定一个数组,写一个函数,将数组中所有的 0 移到数组的末尾,维持其它所有非 0 元素的相对位置。 4 | 5 | ``` 6 | Given an array nums, write a function to move all 0's to the end of it while maintaining 7 | the relative order of the non-zero elements. 8 | 9 | For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0]. 10 | 11 | Note: 12 | You must do this in-place without making a copy of the array. 13 | Minimize the total number of operations. 14 | ``` 15 | 16 | 解题思路: 17 | 18 | 1. 题目要求是将所有非 0 元素移到前面,并且它们非 0 元素相对位置不变,可以设置一个变量 j, 从 0 开始,将非 0 元素一个个赋值以 j 为索引的原有数组 19 | 2. 以给定数组大小为截止条件,继续将 0 元素复制到原有数组中 20 | -------------------------------------------------------------------------------- /Array/Plus One/PlusOne.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector plusOne(vector& digits) { 4 | int nums = digits.size(); 5 | 6 | for (int i = nums - 1; i >= 0; i--) { 7 | 8 | if (digits[i] == 9) { 9 | digits[i] = 0; 10 | } else { 11 | digits[i] += 1; 12 | return digits; 13 | } 14 | } 15 | 16 | if (digits.front() == 0) { 17 | digits.insert(digits.begin(), 1); 18 | } 19 | 20 | return digits; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /Array/Plus One/README.md: -------------------------------------------------------------------------------- 1 | ## Plus One 2 | 3 | 题目:一个非负整数,存储在 vector 中,加 1 操作 4 | 5 | ``` 6 | Given a non-negative integer represented as a non-empty array of digits, plus one to the integer. 7 | 8 | You may assume the integer do not contain any leading zero, except the number 0 itself. 9 | 10 | The digits are stored such that the most significant digit is at the head of the list. 11 | ``` 12 | 13 | 解题思路: 14 | 15 | 1. 整数的最高位存储在一维向量的开头,最低位存储在一维向量的末尾,从最低位开始加 1 16 | 2. 在末尾数字加一,如果末尾数字是 9,那么则会有进位问题,而如果前面位上的数字仍为9,则需要继续向前进位 17 | 3. 首先判断最后一位是否为 9,若不是,直接加一返回,若是,则该位赋值为 0,再继续查前一位,同样的方法,直到查完第一位 18 | 4. 如果第一位原本为9,加一后会产生新的一位,那么最后要做的是,查运算完的第一位是否为 0,如果是,则在最前头加一个 1。 19 | -------------------------------------------------------------------------------- /Array/Remove Duplicates from Sorted Array/README.md: -------------------------------------------------------------------------------- 1 | ## Remove Duplicates from Sorted Array「LeetCode 26」 2 | 3 | 题目:给定一个排序好的数组,删除数组中重复的数,每个数只出现一次,返回数组的长度。 4 | 5 | ``` 6 | Given a sorted array, remove the duplicates in place 7 | 8 | such that each element appear only once and return the new length. 9 | 10 | Do not allocate extra space for another array, you must do this in place with constant memory. 11 | 12 | For example, 13 | Given input array nums = [1,1,2], 14 | 15 | Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. 16 | 17 | It doesn't matter what you leave beyond the new length. 18 | ``` 19 | 20 | 解题思路: 21 | 22 | 1. 不能使用额外的空间,原地复制,与 LeetCode 283 或 LeetCode 27 方法类似 23 | 2. 前后元素进行比较,设一个变量,`int index = 0;`,从第2个元素(`int i = 1`)开始遍历,按照条件,前面一个元素与后面一个元素比较, 24 | 如果不等,那么原地赋值操作(注意地方) 25 | 3. 否则,前后两个元素相等,继续遍历 26 | 27 | ## Remove Duplicates from Sorted Array II「LeetCode 80」 28 | 29 | 题目:给定一个排序的数组,重复的数最多只能二次,最后返回数组的长度。 30 | 31 | ``` 32 | Follow up for "Remove Duplicates": 33 | What if duplicates are allowed at most twice? 34 | 35 | For example, 36 | Given sorted array nums = [1,1,1,2,2,3], 37 | 38 | Your function should return length = 5, 39 | 40 | with the first five elements of nums being 1, 1, 2, 2 and 3. It doesn't matter what you leave beyond the new length. 41 | ``` 42 | 43 | 解题思路: 44 | 45 | 1. 设一个变量,`int index = 2`,因为重复的元素能最多出现2次 46 | 2. 遍历从第3个元素开始比较,如果第3个元素不等于第1个元素,那么原地赋值操作,同时 index++ 47 | 3. 否则,继续遍历 48 | 49 | 50 | -------------------------------------------------------------------------------- /Array/Remove Duplicates from Sorted Array/RemoveDuplicatesFromSortedArray.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int removeDuplicates(vector& nums) { 4 | if (nums.empty()) { 5 | return 0; 6 | } 7 | 8 | int index = 0; 9 | int n = nums.size(); 10 | 11 | // 比较,应从第二个元素开始遍历 12 | for (int i = 1; i < n; i++) { 13 | if (nums[index] != nums[i]) { // 表示后面的元素不等于前面的元素,那么index需要先加1,再赋值 14 | nums[++index] = nums[i]; 15 | } 16 | } 17 | 18 | return index + 1; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /Array/Remove Duplicates from Sorted Array/RemoveDuplicatesFromSortedArrayII.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int removeDuplicates(vector& nums) { 4 | if (nums.size() <= 2) { 5 | return nums.size(); 6 | } 7 | 8 | int index = 2; 9 | int n = nums.size(); 10 | 11 | for (int i = 2; i < n; i++) { 12 | if (nums[i] != nums[index - 2]) { 13 | nums[index] = nums[i]; 14 | index ++; 15 | } 16 | } 17 | 18 | return index; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /Array/Remove Element/README.md: -------------------------------------------------------------------------------- 1 | ## Remove Element「LeetCode 27」 2 | 3 | 题目:给定一个数组和值,将数组中与该值相等的元素全部删除,返回删除后的数组大小。 4 | 5 | ``` 6 | Given an array and a value, remove all instances of that value in place and return the new length. 7 | 8 | Do not allocate extra space for another array, you must do this in place with constant memory. 9 | 10 | The order of elements can be changed. It doesn't matter what you leave beyond the new length. 11 | 12 | Example: 13 | Given input array nums = [3,2,2,3], val = 3 14 | 15 | Your function should return length = 2, with the first two elements of nums being 2. 16 | ``` 17 | 18 | 解题思路:与 LeetCode 283 题目做法类似,很简单。 19 | 20 | 1. 此题不能用额外的数组,所以只能原地做复制操作,遍历,当前的值与 val 比较,不等,复制,并且计数。 21 | -------------------------------------------------------------------------------- /Array/Remove Element/RemoveElement.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int removeElement(vector& nums, int val) { 4 | int number = 0; 5 | int size = nums.size(); 6 | 7 | for (int i = 0; i < size; i++) { 8 | if (nums[i] != val) { 9 | nums[number++] = nums[i]; 10 | } 11 | } 12 | 13 | return number; 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /Array/Rotate Array/README.md: -------------------------------------------------------------------------------- 1 | ## Rotate Array「LeetCode 189」 2 | 3 | 题目:旋转数组,向右旋转 k 步 4 | 5 | ``` 6 | Rotate an array of n elements to the right by k steps. 7 | 8 | For example, with n = 7 and k = 3, the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4]. 9 | 10 | Note: 11 | Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem. 12 | ``` 13 | 14 | 解题思路:三步 15 | 16 | 思路是先把前 n-k 个数字翻转一下,再把后 k 个数字翻转一下,最后再把整个数组翻转一下: 17 | 18 | 1 2 3 4 5 6 7 19 | 20 | 4 3 2 1 5 6 7 (前 n-k 个数字翻转一下) 21 | 22 | 4 3 2 1 7 6 5 (把后 k 个数字翻转一下) 23 | 24 | 5 6 7 1 2 3 4 (把整个数组翻转一下) 25 | -------------------------------------------------------------------------------- /Array/Rotate Array/RotateArray.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void rotate(vector& nums, int k) { 4 | 5 | if (nums.empty() || ((k %= nums.size()) == 0)) { 6 | return ; 7 | } 8 | 9 | int n = nums.size(); 10 | 11 | // 1. 前 n-k 个数字翻转 12 | reverse(nums.begin(), nums.begin() + n - k); 13 | 14 | // 2. k 个数字向右翻转 15 | reverse(nums.begin() + n - k, nums.end()); 16 | 17 | // 3. 整体翻转 18 | reverse(nums.begin(), nums.end()); 19 | 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /Array/Search Insert Position/README.md: -------------------------------------------------------------------------------- 1 | ## Search Insert Position「LeetCode 35」 2 | 3 | 题目:查找插入的位置,一个排序的数组,给定一个目标值,如果有目标值,返回索引,没有,返回插入到数组中的索引 4 | 5 | ``` 6 | Given a sorted array and a target value, return the index if the target is found. 7 | 8 | If not, return the index where it would be if it were inserted in order. 9 | 10 | You may assume no duplicates in the array. 11 | 12 | Here are few examples. 13 | [1,3,5,6], 5 → 2 14 | [1,3,5,6], 2 → 1 15 | [1,3,5,6], 7 → 4 16 | [1,3,5,6], 0 → 0 17 | ``` 18 | 19 | 解题思路: 20 | 21 | 方法一: 22 | 23 | 1. 只需要遍历一遍原数组,若当前数字大于或等于目标值,则返回当前坐标,如果遍历结束了,说明目标值比数组中任何一个数都要大,则返回数组长度n即可 24 | 25 | 方法二: 26 | 27 | 1. 二分搜索法,必须完整正确写出,考虑异常情况 28 | 29 | -------------------------------------------------------------------------------- /Array/Search Insert Position/SearchInsertPosition.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int searchInsert(vector& nums, int target) { 4 | if (nums.empty()) { 5 | return 0; 6 | } 7 | 8 | int num = nums.size(); 9 | 10 | for (int i = 0; i < num; i++) { 11 | if (nums[i] >= target) { 12 | return i; 13 | } 14 | } 15 | 16 | return nums.size(); 17 | } 18 | }; 19 | 20 | class Solution { 21 | public: 22 | int searchInsert(vector& nums, int target) { 23 | if (nums.empty()) { 24 | return 0; 25 | } 26 | 27 | if (nums.back() < target) { 28 | return nums.size(); 29 | } 30 | 31 | int left = 0, right = nums.size() - 1; 32 | 33 | while (left <= right) { 34 | int mid = left + (right - left) / 2; 35 | 36 | if (nums[mid] == target) { 37 | return mid; 38 | } else if (nums[mid] < target) { 39 | left = mid + 1; 40 | } else { 41 | right = mid - 1; 42 | } 43 | 44 | } 45 | 46 | return left; 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /Array/Search a 2D Matrix/README.md: -------------------------------------------------------------------------------- 1 | ## Search a 2D Matrix「LeetCode 74」 2 | 3 | ``` 4 | Write an efficient algorithm that searches for a value in an m x n matrix. 5 | This matrix has the following properties: 6 | 7 | Integers in each row are sorted from left to right. 8 | The first integer of each row is greater than the last integer of the previous row. 9 | For example, 10 | 11 | Consider the following matrix: 12 | 13 | [ 14 | [1, 3, 5, 7], 15 | [10, 11, 16, 20], 16 | [23, 30, 34, 50] 17 | ] 18 | Given target = 3, return true. 19 | ``` 20 | 21 | 解题思路: 22 | 23 | 1. 二维数组是有序的,用二分搜索法 24 | 2. 求二维数组的行和列 25 | -------------------------------------------------------------------------------- /Array/Sort Colors/README.md: -------------------------------------------------------------------------------- 1 | ## Sort Colors「LeetCode 75」 2 | 3 | 题目:对三种颜色(红、白、蓝)进行排序 4 | 5 | ``` 6 | Given an array with n objects colored red, white or blue, 7 | 8 | sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue. 9 | 10 | Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively. 11 | 12 | Note: 13 | You are not suppose to use the library's sort function for this problem. 14 | ``` 15 | 16 | 解题思路: 17 | 18 | 可以用计数排序,因为只有三种颜色,可以新建一个数组 colors[3],分别统计 0, 1, 2 的元素个数。时间复杂度为 O(n),空间复杂度为 O(k)。 19 | 20 | 可以用三路快速排序法。对整个数组只遍历一遍,时间复杂度为 O(n),空间复杂度为 O(1)。 21 | 22 | 1. 三路快排,注意临界条件 23 | 2. arr[0...zero] == 0,arr[zero+1...i-1] == 1,arr[two...n-1] == 2 24 | 3. 其中 i 一直向前探索,终止条件是,i < two 25 | 4. 注意 zero,two 的初值;zero = -1,two = nums.size(); 26 | -------------------------------------------------------------------------------- /Array/Sort Colors/SortColors.cpp: -------------------------------------------------------------------------------- 1 | // 计数排序 2 | class Solution { 3 | public: 4 | void sortColors(vector& nums) { 5 | int colors[3] = {0}; 6 | 7 | int count = nums.size(); 8 | 9 | // 计数 10 | for (int i = 0; i < count; i++) { 11 | colors[nums[i]] ++; 12 | } 13 | 14 | int index = 0; 15 | for (int i = 0; i < colors[0]; i++) { 16 | nums[index++] = 0; 17 | } 18 | 19 | for (int i = 0; i < colors[1]; i++) { 20 | nums[index++] = 1; 21 | } 22 | 23 | for (int i = 0; i < colors[2]; i++) { 24 | nums[index++] = 2; 25 | } 26 | } 27 | }; 28 | 29 | // 三路快排 30 | class Solution { 31 | public: 32 | void sortColors(vector& nums) { 33 | int zero = -1; 34 | int two = nums.size(); 35 | 36 | for (int i = 0; i < two; ) { 37 | if (nums[i] == 1) { 38 | i++; 39 | } else if (nums[i] == 2) { 40 | swap(nums[i], nums[--two]); 41 | } else { 42 | swap(nums[++zero], nums[i++]); 43 | } 44 | } 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /Array/Third Maximum Number/README.md: -------------------------------------------------------------------------------- 1 | ## Third Maximum Number「LeetCode 414」 2 | 3 | 题目:求出一个数组中第三大的元素 4 | 5 | ``` 6 | Given a non-empty array of integers, return the third maximum number in this array. 7 | 8 | If it does not exist, return the maximum number. The time complexity must be in O(n). 9 | 10 | Example 1: 11 | Input: [3, 2, 1] 12 | 13 | Output: 1 14 | 15 | Explanation: The third maximum is 1. 16 | Example 2: 17 | Input: [1, 2] 18 | 19 | Output: 2 20 | 21 | Explanation: The third maximum does not exist, so the maximum (2) is returned instead. 22 | Example 3: 23 | Input: [2, 2, 3, 1] 24 | 25 | Output: 1 26 | 27 | Explanation: Note that the third maximum here means the third maximum distinct number. 28 | Both numbers with value 2 are both considered as second maximum. 29 | ``` 30 | 31 | 解题思路: 32 | 33 | 方法一: 34 | 35 | 使用 set,插入操作是 O(logn),遍历插入,时间复杂度 O(nlogn)。 36 | 37 | 1. 一维向量中元素有重复,首先遍历,插入到 set 中,去重复元素 38 | 2. 定义反向迭代器 set::reverse_iterator,之后判断 set 中有多少个元素,小于三个就直接返回最大值,否则反向迭代就可以找到第三大的值 39 | 40 | 方法二: 41 | 42 | 用三个变量记录第一大,第二大,第三大的数,在遍历数据过程中更新这三个值。 43 | 44 | 45 | -------------------------------------------------------------------------------- /Array/Third Maximum Number/ThirdMaximumNumber.cpp: -------------------------------------------------------------------------------- 1 | // 初始化要用长整型 long 的最小值,否则当数组中有 INT_MIN 存在时,不知道该返回 INT_MIN 还是最大值 first 2 | class Solution { 3 | public: 4 | int thirdMax(vector& nums) { 5 | long first = LONG_MIN, second = LONG_MIN, third = LONG_MIN; 6 | 7 | for (int num : nums) { 8 | if (num == first || num == second || num == third) 9 | continue; 10 | 11 | if (num > first) { 12 | third = second; 13 | second = first; 14 | first = num; 15 | } else if (num > second) { 16 | third = second; 17 | second = num; 18 | } else if (num > third) { 19 | third = num; 20 | } 21 | } 22 | 23 | return (third == LONG_MIN) ? (int)first : (int)third; 24 | } 25 | }; 26 | 27 | // set,时间复杂度 O(nlogn) 28 | class Solution { 29 | public: 30 | int thirdMax(vector& nums) { 31 | if (nums.empty()) { 32 | return 0; 33 | } 34 | 35 | set s; 36 | 37 | for (int i = 0; i < nums.size(); i++) { 38 | s.insert(nums[i]); 39 | } 40 | 41 | set::reverse_iterator it = s.rbegin(); 42 | 43 | if (s.size() < 3) { 44 | return *it; 45 | } 46 | 47 | it++; 48 | it++; 49 | 50 | return *it; 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /Array/Two Sum/TwoSum.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector twoSum(vector& nums, int target) { 4 | unordered_map maps; 5 | 6 | vector result; 7 | 8 | int n = nums.size(); 9 | 10 | // 遍历,map 数据 11 | for (int i = 0; i < n; i++) { 12 | maps[nums[i]] = i; 13 | } 14 | 15 | // 遍历,找差值是否存在 16 | for (int i = 0; i < n; i++) { 17 | int diff = target - nums[i]; 18 | 19 | // 找到差值 20 | if (maps.count(diff) && maps[diff] != i) { 21 | result.push_back(i); 22 | result.push_back(maps[diff]); 23 | break; 24 | } 25 | } 26 | 27 | return result; 28 | } 29 | }; 30 | 31 | // 简洁版 32 | class Solution { 33 | public: 34 | vector twoSum(vector& nums, int target) { 35 | unordered_map map; 36 | 37 | for(int i = 0; i < nums.size(); i++) { 38 | int temp = target - nums[i]; 39 | if(map.count(temp)){ 40 | return vector{i,map[target-nums[i]]}; 41 | } else { 42 | map[nums[i]] = i; 43 | } 44 | } 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /Array/Two Sum/TwoSumII.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector twoSum(vector& numbers, int target) { 4 | int first = 0, last = numbers.size() - 1; 5 | 6 | while (first < last) { 7 | if (numbers[first] + numbers[last] == target) { 8 | int ret[2] = {first+1, last+1}; 9 | return vector(ret, ret+2); 10 | } else if (numbers[first] + numbers[last] < target) { 11 | first++; 12 | } else { 13 | last--; 14 | } 15 | } 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /Bit Manipulation/README.md: -------------------------------------------------------------------------------- 1 | # 位操作 2 | 3 | * [Sum of Two Integers](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Bit%20Manipulation/SumOfTwoIntegers) 4 | * [Single Number](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Bit%20Manipulation/Single%20Number) 5 | 6 | ## 位操作的基础 7 | 8 | 1.测试某位是否为 1, 为 1 返回 true(1),否则 false(0) 9 | 10 | ```c++ 11 | // 测试 a 的第 b 位是否为 1 12 | #define TSTBIT(a, b) (((a) & (1 << b)) ? (true) : (false)) 13 | ``` 14 | 15 | 2.将某位置为 1 16 | 17 | ```c++ 18 | // 将 a 的第 b 位置为 1 19 | #define SETBIT(a, b) (a = ((a) | (1 << b))) 20 | ``` 21 | 22 | 3.将某位置为 0 23 | 24 | ```c++ 25 | // 将 a 的第 b 位置为 0 26 | #define CLRBIT(a, b) (a = ((a) & (~(1 << (b))))) 27 | ``` 28 | 29 | ```c++ 30 | // 测试 31 | #include 32 | 33 | #define TSTBIT(a, b) (((a) & (1 << b)) ? (true) : (false)) 34 | #define SETBIT(a, b) (a = ((a) | (1 << b))) 35 | #define CLRBIT(a, b) (a = ((a) & (~(1 << (b))))) 36 | 37 | int main() 38 | { 39 | int number = 10; 40 | 41 | std::cout << TSTBIT(number, 2) << std::endl; // 0 42 | 43 | std::cout << SETBIT(number, 3) << std::endl; // 10 44 | 45 | std::cout << CLRBIT(number, 3) << std::endl; // 2 46 | 47 | return 0; 48 | } 49 | ``` 50 | -------------------------------------------------------------------------------- /Bit Manipulation/Single Number/README.md: -------------------------------------------------------------------------------- 1 | ## 求整形数组中出现一次的元素「LeetCode 136」 2 | 3 | Given an array of integers, every element appears twice except for one. Find that single one. 4 | 5 | Note: 6 | Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory? 7 | 8 | 题解: 9 | 10 | 在一个整形数组中,只有一个元素出现一次,其他元素都出现两次,找出只出现一次的元素,不能用额外的空间。 11 | 12 | 根据异或(XOR)特性,两个元素异或,相同为 0,不同为 1,与 0 异或得本身。 13 | 14 | 所以把整形数组中的所有元素进行异或,得出的结果就是只出现一次的元素。 15 | 16 | -------------------------------------------------------------------------------- /Bit Manipulation/Single Number/SingleNumber.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int singleNumber(vector& nums) { 4 | int ret = 0; 5 | 6 | for (int i = 0; i < nums.size(); i++) { 7 | ret = ret ^ nums[i]; 8 | } 9 | 10 | return ret; 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /Bit Manipulation/SumOfTwoIntegers/README.md: -------------------------------------------------------------------------------- 1 | ## 求两个整形的数的和,不能用 `+` 和 `-` 运算符 「LeetCode 371」 2 | 3 | 使用位运算符来实现加法运算,其实也是计算机 CPU 内部实现加法运算的方案。 4 | 5 | 两个单独的位相加,其结果可以用 异或(XOR) 得到,进位可以用 与(AND) 得到。 6 | 7 | 如 1 + 1 = 2; 1 ^ 1 = 0, 1 & 1 = 1, 得 10(二进制) = 2 8 | 9 | 第一步:对 a 和 b 进行 与 位运算,得出每一位上的进位。 10 | 11 | 第二步:对 a 和 b 进行 异或 位运算,得出没有加进位的和。 12 | 13 | 第三步:进位值左移一位,因为进位是与下一位相加(求异或)。 14 | 15 | 第四步:重复上面操作,直到进位为0,就可以得到最终结果。 16 | -------------------------------------------------------------------------------- /Bit Manipulation/SumOfTwoIntegers/SumOfTwoIntegers.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -. 3 | */ 4 | // 内含迭代思想 5 | class Solution { 6 | public: 7 | int getSum(int a, int b) { 8 | while (b) { 9 | int carray = a & b; 10 | int sum = a ^ b; 11 | a = sum; 12 | b = carray << 1; 13 | } 14 | 15 | return a; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /Graph/Component/Component.h: -------------------------------------------------------------------------------- 1 | #ifndef COMPONENT_H_ 2 | #define COMPONENT_H_ 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | // 求无权图的连通分量 10 | template 11 | class Component { 12 | private: 13 | Graph &g; 14 | bool *visited; // 记录 DFS 过程中顶点是否被遍历 15 | unsigned int counts; // 记录连通分量的个数 16 | int *id; // 每个顶点所对应的连通分量标记 17 | 18 | // 图的深度优先遍历 DFS 19 | void dfs(int v) { 20 | visited[v] = true; 21 | id[v] = counts; 22 | 23 | typename Graph::adjIterator adj(g, v); 24 | 25 | for (int i = adj.begin(); !adj.end(); i = adj.next()) { 26 | if (!visited[i]) { 27 | dfs(i); 28 | } 29 | } 30 | } 31 | 32 | public: 33 | // 构造函数,求出无权图的连通分量 34 | Component(Graph &graph) : g(graph) { 35 | visited = new bool[g.V()]; 36 | id = new int[g.V()]; 37 | counts = 0; 38 | 39 | for (int i = 0; i < g.V(); i++) { 40 | visited[i] = false; 41 | id[i] = -1; 42 | } 43 | 44 | // 图的连通分量 45 | for (int i = 0; i < g.V(); i++) { 46 | if (!visited[i]) { 47 | dfs(i); 48 | counts++; 49 | } 50 | } 51 | } 52 | 53 | ~Component() { 54 | delete[] visited; 55 | delete[] id; 56 | } 57 | 58 | int count() { 59 | return counts; 60 | } 61 | 62 | // 查询顶点 v 和顶点 w 是否连通 63 | bool isConnected(int v, int w) { 64 | assert(v >= 0 && w < g.V()); 65 | assert(w >= 0 && w < g.V()); 66 | 67 | return id[v] == id[w]; 68 | } 69 | }; 70 | 71 | #endif /* COMPONENT_H_ */ 72 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/Kruskal/ReadWeightedGraph.h: -------------------------------------------------------------------------------- 1 | #ifndef READ_WEIGHTED_GRAPH_H_ 2 | #define READ_WEIGHTED_GRAPH_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | template 13 | class ReadWeightedGraph { 14 | public: 15 | // 从文件 filename 中读取有权图的信息, 存储进图 graph 中 16 | ReadWeightedGraph(Graph &graph, const string &filename) { 17 | ifstream file(filename); 18 | string line; 19 | int V, E; 20 | 21 | assert(file.is_open()); 22 | 23 | assert(getline(file, line)); // 文件第一行,V 和 E 24 | stringstream s(line); 25 | s >> V >> E; 26 | 27 | assert(V == graph.V()); 28 | 29 | for (int i = 0; i < E; i++) { 30 | assert(getline(file, line)); 31 | stringstream s(line); 32 | 33 | int a, b; 34 | Weight weight; 35 | 36 | s >> a >> b >> weight; 37 | assert(a >= 0 && a < V); 38 | assert(b >= 0 && b < V); 39 | 40 | graph.addEdge(a, b, weight); 41 | } 42 | } 43 | }; 44 | 45 | #endif /* READGRAPH_H_ */ 46 | 47 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/Kruskal/WeightedGraphEdge.h: -------------------------------------------------------------------------------- 1 | #ifndef WEIGHTED_GRAPH_EDGE_H 2 | #define WEIGHTED_GRAPH_EDGE_H 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | // 边类 10 | template 11 | class WeightedGraphEdge { 12 | public: 13 | WeightedGraphEdge(int u, int v, T weight) { 14 | this->u = u; 15 | this->v = v; 16 | this->weight = weight; 17 | } 18 | 19 | WeightedGraphEdge() {} 20 | 21 | ~WeightedGraphEdge() {} 22 | 23 | int V() { return u;} // 第一个顶点 24 | 25 | int W() { return v;} // 第二个顶点 26 | 27 | T wt() { 28 | return weight; // 边的权值 29 | } 30 | 31 | // 求另一条边 32 | int other(int x) { 33 | assert(x == u || x == v); 34 | return x == u ? v : u; 35 | } 36 | 37 | // 输出边的信息 38 | friend ostream& operator<<(ostream &os, const WeightedGraphEdge &e) { 39 | os << e.u << " - " << e.v << " : " << e.weight; 40 | return os; 41 | } 42 | 43 | // 对边的权值的大小比较 44 | bool operator<(WeightedGraphEdge& e) { 45 | return weight < e.wt(); 46 | } 47 | 48 | bool operator<=(WeightedGraphEdge& e) { 49 | return weight <= e.wt(); 50 | } 51 | 52 | bool operator>(WeightedGraphEdge& e) { 53 | return weight > e.wt(); 54 | } 55 | 56 | bool operator>=(WeightedGraphEdge& e) { 57 | return weight >= e.wt(); 58 | } 59 | 60 | bool operator==(WeightedGraphEdge& e) { 61 | return weight == e.wt(); 62 | } 63 | 64 | private: 65 | int u, v; // 边的两个顶点 66 | T weight; // 边的权值 67 | }; 68 | 69 | 70 | #endif 71 | 72 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/Kruskal/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "WeightedDenseGraph.h" 4 | #include "WeightedSparseGraph.h" 5 | #include "ReadWeightedGraph.h" 6 | #include "KruskalMST.h" 7 | 8 | using namespace std; 9 | 10 | // Kruskal MST 11 | int main() { 12 | 13 | string filename = "test.txt"; 14 | int V = 8; 15 | 16 | WeightedSparseGraph g = WeightedSparseGraph(V, false); 17 | ReadWeightedGraph, double> readGraph(g, filename); 18 | 19 | // Test Kruskal MST 20 | cout << "Test Kruskal MST:" << endl; 21 | KruskalMST, double> kruskalMST(g); 22 | vector> mst = kruskalMST.mstEdges(); 23 | 24 | for( unsigned int i = 0 ; i < mst.size() ; i ++ ) 25 | cout << mst[i] << endl; 26 | 27 | cout << "The Kruskal MST weight is: " << kruskalMST.result() << endl; 28 | 29 | cout << endl; 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/Kruskal/test.txt: -------------------------------------------------------------------------------- 1 | 8 16 2 | 4 5 .31 3 | 4 7 .37 4 | 5 7 .28 5 | 0 7 .16 6 | 1 5 .32 7 | 0 4 .38 8 | 2 3 .20 9 | 1 7 .19 10 | 0 2 .26 11 | 1 2 .36 12 | 1 3 .29 13 | 2 7 .34 14 | 6 2 .40 15 | 3 6 .52 16 | 6 0 .58 17 | 6 4 .93 18 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/Prim/LazyPrimMST/ReadWeightedGraph.h: -------------------------------------------------------------------------------- 1 | #ifndef READ_WEIGHTED_GRAPH_H_ 2 | #define READ_WEIGHTED_GRAPH_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | template 13 | class ReadWeightedGraph { 14 | public: 15 | // 从文件 filename 中读取有权图的信息, 存储进图 graph 中 16 | ReadWeightedGraph(Graph &graph, const string &filename) { 17 | ifstream file(filename); 18 | string line; 19 | int V, E; 20 | 21 | assert(file.is_open()); 22 | 23 | assert(getline(file, line)); // 文件第一行,V 和 E 24 | stringstream s(line); 25 | s >> V >> E; 26 | 27 | assert(V == graph.V()); 28 | 29 | for (int i = 0; i < E; i++) { 30 | assert(getline(file, line)); 31 | stringstream s(line); 32 | 33 | int a, b; 34 | Weight weight; 35 | 36 | s >> a >> b >> weight; 37 | assert(a >= 0 && a < V); 38 | assert(b >= 0 && b < V); 39 | 40 | graph.addEdge(a, b, weight); 41 | } 42 | } 43 | }; 44 | 45 | #endif /* READGRAPH_H_ */ 46 | 47 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/Prim/LazyPrimMST/WeightedGraphEdge.h: -------------------------------------------------------------------------------- 1 | #ifndef WEIGHTED_GRAPH_EDGE_H 2 | #define WEIGHTED_GRAPH_EDGE_H 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | // 边类 10 | template 11 | class WeightedGraphEdge { 12 | public: 13 | WeightedGraphEdge(int u, int v, T weight) { 14 | this->u = u; 15 | this->v = v; 16 | this->weight = weight; 17 | } 18 | 19 | WeightedGraphEdge() {} 20 | 21 | ~WeightedGraphEdge() {} 22 | 23 | int V() { return u;} // 第一个顶点 24 | 25 | int W() { return v;} // 第二个顶点 26 | 27 | T wt() { 28 | return weight; // 边的权值 29 | } 30 | 31 | // 边的另一个顶点 32 | int other(int x) { 33 | assert(x == u || x == v); 34 | return x == u ? v : u; 35 | } 36 | 37 | // 输出边的信息 38 | friend ostream& operator<<(ostream &os, const WeightedGraphEdge &e) { 39 | os << e.u << " - " << e.v << " : " << e.weight; 40 | return os; 41 | } 42 | 43 | // 对边的权值的大小比较 44 | bool operator<(WeightedGraphEdge& e) { 45 | return weight < e.wt(); 46 | } 47 | 48 | bool operator<=(WeightedGraphEdge& e) { 49 | return weight <= e.wt(); 50 | } 51 | 52 | bool operator>(WeightedGraphEdge& e) { 53 | return weight > e.wt(); 54 | } 55 | 56 | bool operator>=(WeightedGraphEdge& e) { 57 | return weight >= e.wt(); 58 | } 59 | 60 | bool operator==(WeightedGraphEdge& e) { 61 | return weight == e.wt(); 62 | } 63 | 64 | private: 65 | int u, v; // 边的两个顶点 66 | T weight; // 边的权值 67 | }; 68 | 69 | 70 | #endif 71 | 72 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/Prim/LazyPrimMST/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "WeightedDenseGraph.h" 4 | #include "WeightedSparseGraph.h" 5 | #include "ReadWeightedGraph.h" 6 | #include "LazyPrimMST.h" 7 | 8 | using namespace std; 9 | 10 | // 娴嬭瘯鏈�灏忕敓鎴愭爲绠楁硶 11 | int main() { 12 | 13 | string filename = "test.txt"; 14 | int V = 8; 15 | 16 | WeightedSparseGraph g = WeightedSparseGraph(V, false); 17 | ReadWeightedGraph, double> readGraph(g, filename); 18 | 19 | // Test Lazy Prim MST 20 | cout << "Test Lazy Prim MST:" << endl; 21 | LazyPrimMST, double> lazyPrimMST(g); 22 | vector> mst = lazyPrimMST.mstEdges(); 23 | for( unsigned int i = 0 ; i < mst.size() ; i ++ ) 24 | cout << mst[i] << endl; 25 | 26 | cout << "The MST weight is: " << lazyPrimMST.result() << endl; 27 | 28 | cout << endl; 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/Prim/LazyPrimMST/test.txt: -------------------------------------------------------------------------------- 1 | 8 16 2 | 4 5 .31 3 | 4 7 .37 4 | 5 7 .28 5 | 0 7 .16 6 | 1 5 .32 7 | 0 4 .38 8 | 2 3 .20 9 | 1 7 .19 10 | 0 2 .26 11 | 1 2 .36 12 | 1 3 .29 13 | 2 7 .34 14 | 6 2 .40 15 | 3 6 .52 16 | 6 0 .58 17 | 6 4 .93 18 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/Prim/PrimMST/ReadWeightedGraph.h: -------------------------------------------------------------------------------- 1 | #ifndef READ_WEIGHTED_GRAPH_H_ 2 | #define READ_WEIGHTED_GRAPH_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | template 13 | class ReadWeightedGraph { 14 | public: 15 | // 从文件 filename 中读取有权图的信息, 存储进图 graph 中 16 | ReadWeightedGraph(Graph &graph, const string &filename) { 17 | ifstream file(filename); 18 | string line; 19 | int V, E; 20 | 21 | assert(file.is_open()); 22 | 23 | assert(getline(file, line)); // 文件第一行,V 和 E 24 | stringstream s(line); 25 | s >> V >> E; 26 | 27 | assert(V == graph.V()); 28 | 29 | for (int i = 0; i < E; i++) { 30 | assert(getline(file, line)); 31 | stringstream s(line); 32 | 33 | int a, b; 34 | Weight weight; 35 | 36 | s >> a >> b >> weight; 37 | assert(a >= 0 && a < V); 38 | assert(b >= 0 && b < V); 39 | 40 | graph.addEdge(a, b, weight); 41 | } 42 | } 43 | }; 44 | 45 | #endif /* READGRAPH_H_ */ 46 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/Prim/PrimMST/WeightedGraphEdge.h: -------------------------------------------------------------------------------- 1 | #ifndef WEIGHTED_GRAPH_EDGE_H 2 | #define WEIGHTED_GRAPH_EDGE_H 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | // 边类 10 | template 11 | class WeightedGraphEdge { 12 | public: 13 | WeightedGraphEdge(int u, int v, T weight) { 14 | this->u = u; 15 | this->v = v; 16 | this->weight = weight; 17 | } 18 | 19 | WeightedGraphEdge() {} 20 | 21 | ~WeightedGraphEdge() {} 22 | 23 | int V() { return u;} // 第一个顶点 24 | 25 | int W() { return v;} // 第二个顶点 26 | 27 | T wt() { 28 | return weight; // 边的权值 29 | } 30 | 31 | // 边的另一个顶点 32 | int other(int x) { 33 | assert(x == u || x == v); 34 | return x == u ? v : u; 35 | } 36 | 37 | // 输出边的信息 38 | friend ostream& operator<<(ostream &os, const WeightedGraphEdge &e) { 39 | os << e.u << " - " << e.v << " : " << e.weight; 40 | return os; 41 | } 42 | 43 | // 对边的权值的大小比较 44 | bool operator<(WeightedGraphEdge& e) { 45 | return weight < e.wt(); 46 | } 47 | 48 | bool operator<=(WeightedGraphEdge& e) { 49 | return weight <= e.wt(); 50 | } 51 | 52 | bool operator>(WeightedGraphEdge& e) { 53 | return weight > e.wt(); 54 | } 55 | 56 | bool operator>=(WeightedGraphEdge& e) { 57 | return weight >= e.wt(); 58 | } 59 | 60 | bool operator==(WeightedGraphEdge& e) { 61 | return weight == e.wt(); 62 | } 63 | 64 | private: 65 | int u, v; // 边的两个顶点 66 | T weight; // 边的权值 67 | }; 68 | 69 | 70 | #endif 71 | 72 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/Prim/PrimMST/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "WeightedDenseGraph.h" 4 | #include "WeightedSparseGraph.h" 5 | #include "ReadWeightedGraph.h" 6 | #include "PrimMST.h" 7 | 8 | using namespace std; 9 | 10 | // Prim MST 11 | int main() { 12 | 13 | string filename = "test.txt"; 14 | int V = 8; 15 | 16 | WeightedSparseGraph g = WeightedSparseGraph(V, false); 17 | ReadWeightedGraph, double> readGraph(g, filename); 18 | 19 | // Test Prim MST 20 | cout << "Test Prim MST:" << endl; 21 | PrimMST, double> primMST(g); 22 | vector> mst = primMST.mstEdges(); 23 | for( unsigned int i = 0 ; i < mst.size() ; i ++ ) 24 | cout << mst[i] << endl; 25 | 26 | cout << "The MST weight is: " << primMST.result() << endl; 27 | 28 | cout << endl; 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/Prim/PrimMST/test.txt: -------------------------------------------------------------------------------- 1 | 8 16 2 | 4 5 .31 3 | 4 7 .37 4 | 5 7 .28 5 | 0 7 .16 6 | 1 5 .32 7 | 0 4 .38 8 | 2 3 .20 9 | 1 7 .19 10 | 0 2 .26 11 | 1 2 .36 12 | 1 3 .29 13 | 2 7 .34 14 | 6 2 .40 15 | 3 6 .52 16 | 6 0 .58 17 | 6 4 .93 18 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/README.md: -------------------------------------------------------------------------------- 1 | ## 最小生成树 Minimum Span Tree 2 | 3 | 在一给定的无向图 G = (V, E) 中,w(u, v) 代表连接顶点 u 与顶点 v 的边,而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集且为无循环图,使得 4 | 的 w(T) 最小,则此 T 为 G 的最小生成树。 5 | 6 | 最小生成树其实是最小权重生成树的简称。 7 | 8 | 如果无向连通图中,边的权值有相等情况(如果横切边有相等的边),那么最小生成树不只有一条。 9 | 10 | ### [有权图](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Graph/Minimum%20Span%20Tree/Weighted%20Graph) 11 | 12 | 图可以用邻接矩阵(稠密图)和邻接表(稀疏图)来表示,对于一个有权图,由于有边的权值,所以需要在邻接矩阵和邻接表中加入边的权值。 13 | 14 | 邻接矩阵,其实是一个二维数组结构,w(u, v) 代表连接顶点 u 与顶点 v 的边,w(u, v) 代表此边的权重,二维数组表示就是 `arr[u][v] = w(u, v)`。 15 | 16 | 邻接表,是每个顶点,将其相邻的顶点和两点之间的权值,存放到向量或链表中。 17 | 18 | 用一个类来单独表示顶点之间的权值。 19 | 20 | ### Prim 算法——贪心算法 21 | 22 | * [利用最小堆实现 Prim 算法](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Graph/Minimum%20Span%20Tree/Prim/LazyPrimMST) 23 | 24 | 原理:根据切分定理,任意选取图中的一个顶点,把该顶点的所有横切边,入最小堆,取出最小权值(该边一定为最小生成树的边),该边的另一个顶点没有访问过,现在对两个顶点进行切分,它们的所有横切边,入最小堆,取出最小权值,如果该最小权值边的另一个顶点没有被访问过,就加入切分阵营,继续加入横切边到最小堆中,反复操作,直到所有顶点都被访问过,找出最小生成树。 25 | 26 | 时间复杂度为 O(ElogE)。 27 | 28 | **缺点:图中的每个边都会进入最小堆中,并且进入的横切边不一定是最小生成树的边。** 29 |   30 | * [利用最小索引堆实现 Prim 算法](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Graph/Minimum%20Span%20Tree/Prim/PrimMST) 31 | 32 | 时间复杂度为 O(ElogV)。 33 | 34 | 每个顶点对应索引,每个顶点总是保存最小的权值。 35 | 36 | ### [Kruskal 算法](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Graph/Minimum%20Span%20Tree/Kruskal) 37 | 38 | 最小堆 + 并查集 实现 Kruskal 算法。 39 | 40 | 原理:对图中的所有边的权值进行`排序`,依次取最小的边,并且利用`并查集`来判断环。 41 | 42 | 利用 Union Find 来判断是否构成环。 43 | 44 | 时间复杂度为 O(ElogE)。 45 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/Weighted Graph/ReadWeightedGraph.h: -------------------------------------------------------------------------------- 1 | #ifndef READ_WEIGHTED_GRAPH_H_ 2 | #define READ_WEIGHTED_GRAPH_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | template 13 | class ReadWeightedGraph { 14 | public: 15 | // 从文件 filename 中读取有权图的信息, 存储进图 graph 中 16 | ReadWeightedGraph(Graph &graph, const string &filename) { 17 | ifstream file(filename); 18 | string line; 19 | int V, E; 20 | 21 | assert(file.is_open()); 22 | 23 | assert(getline(file, line)); // 文件第一行,V 和 E 24 | stringstream s(line); 25 | s >> V >> E; 26 | 27 | assert(V == graph.V()); 28 | 29 | for (int i = 0; i < E; i++) { 30 | assert(getline(file, line)); 31 | stringstream s(line); 32 | 33 | int a, b; 34 | Weight weight; 35 | 36 | s >> a >> b >> weight; 37 | assert(a >= 0 && a < V); 38 | assert(b >= 0 && b < V); 39 | 40 | graph.addEdge(a, b, weight); 41 | } 42 | } 43 | }; 44 | 45 | #endif /* READGRAPH_H_ */ 46 | 47 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/Weighted Graph/WeightedGraphEdge.h: -------------------------------------------------------------------------------- 1 | #ifndef WEIGHTED_GRAPH_EDGE_H 2 | #define WEIGHTED_GRAPH_EDGE_H 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | // 边类 10 | template 11 | class WeightedGraphEdge { 12 | public: 13 | WeightedGraphEdge(int u, int v, T weight) { 14 | this->u = u; 15 | this->v = v; 16 | this->weight = weight; 17 | } 18 | 19 | WeightedGraphEdge() {} 20 | 21 | ~WeightedGraphEdge() {} 22 | 23 | int V() { return u;} // 第一个顶点 24 | 25 | int W() { return v;} // 第二个顶点 26 | 27 | T wt() { 28 | return weight; // 边的权值 29 | } 30 | 31 | // 求另一条边 32 | int other(int x) { 33 | assert(x == u || x == v); 34 | return x == u ? v : u; 35 | } 36 | 37 | // 输出边的信息 38 | friend ostream& operator<<(ostream &os, const WeightedGraphEdge &e) { 39 | os << e.u << " - " << e.v << " : " << e.weight; 40 | return os; 41 | } 42 | 43 | // 对边的权值的大小比较 44 | bool operator<(WeightedGraphEdge& e) { 45 | return weight < e.wt(); 46 | } 47 | 48 | bool operator<=(WeightedGraphEdge& e) { 49 | return weight <= e.wt(); 50 | } 51 | 52 | bool operator>(WeightedGraphEdge& e) { 53 | return weight > e.wt(); 54 | } 55 | 56 | bool operator>=(WeightedGraphEdge& e) { 57 | return weight >= e.wt(); 58 | } 59 | 60 | bool operator==(WeightedGraphEdge& e) { 61 | return weight == e.wt(); 62 | } 63 | 64 | private: 65 | int u, v; // 边的两个顶点 66 | T weight; // 边的权值 67 | }; 68 | 69 | 70 | #endif 71 | 72 | -------------------------------------------------------------------------------- /Graph/Minimum Span Tree/Weighted Graph/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "WeightedDenseGraph.h" 3 | #include "WeightedSparseGraph.h" 4 | #include "ReadWeightedGraph.h" 5 | 6 | using namespace std; 7 | 8 | // 测试有权图和有权图的读取 9 | int main() { 10 | 11 | string filename = "test.txt"; 12 | int V = 8; 13 | 14 | // Test Weighted Dense Graph,无向图 15 | WeightedDenseGraph g1 = WeightedDenseGraph(V, false); 16 | 17 | ReadWeightedGraph, double> readGraph1(g1, filename); 18 | 19 | g1.show(); 20 | 21 | cout< g2 = WeightedSparseGraph(V, false); 25 | 26 | ReadWeightedGraph, double> readGraph2(g2, filename); 27 | 28 | g2.show(); 29 | 30 | cout< 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | template 13 | class ReadGraph { 14 | public: 15 | ReadGraph(Graph &graph, const string &filename) { 16 | ifstream file(filename); 17 | string line; 18 | int V, E; 19 | 20 | assert(file.is_open()); 21 | assert(getline(file, line)); // 文件第一行,V 和 E 22 | stringstream s(line); 23 | s >> V >> E; 24 | 25 | assert(V == graph.V()); 26 | 27 | for (int i = 0; i < E; i++) { 28 | assert(getline(file, line)); 29 | stringstream s(line); 30 | 31 | int a, b; 32 | 33 | s >> a >> b; 34 | assert(a >= 0 && a < V); 35 | assert(b >= 0 && b < V); 36 | 37 | graph.addEdge(a, b); 38 | } 39 | } 40 | }; 41 | 42 | #endif /* READGRAPH_H_ */ 43 | 44 | -------------------------------------------------------------------------------- /Graph/Shortest-path Algorithms/Bellman Ford/ReadWeightedGraph.h: -------------------------------------------------------------------------------- 1 | #ifndef READ_WEIGHTED_GRAPH_H_ 2 | #define READ_WEIGHTED_GRAPH_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | template 13 | class ReadWeightedGraph { 14 | public: 15 | // 从文件 filename 中读取有权图的信息, 存储进图 graph 中 16 | ReadWeightedGraph(Graph &graph, const string &filename) { 17 | ifstream file(filename); 18 | string line; 19 | int V, E; 20 | 21 | assert(file.is_open()); 22 | 23 | assert(getline(file, line)); // 文件第一行,V 和 E 24 | stringstream s(line); 25 | s >> V >> E; 26 | 27 | assert(V == graph.V()); 28 | 29 | for (int i = 0; i < E; i++) { 30 | assert(getline(file, line)); 31 | stringstream s(line); 32 | 33 | int a, b; 34 | Weight weight; 35 | 36 | s >> a >> b >> weight; 37 | assert(a >= 0 && a < V); 38 | assert(b >= 0 && b < V); 39 | 40 | graph.addEdge(a, b, weight); 41 | } 42 | } 43 | }; 44 | 45 | #endif /* READGRAPH_H_ */ 46 | -------------------------------------------------------------------------------- /Graph/Shortest-path Algorithms/Bellman Ford/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "WeightedSparseGraph.h" 3 | #include "ReadWeightedGraph.h" 4 | #include "BellmanFord.h" 5 | 6 | using namespace std; 7 | 8 | // 测试Bellman-Ford算法 9 | int main() { 10 | 11 | string filename = "test.txt"; 12 | int V = 5; 13 | 14 | // 有向图 15 | WeightedSparseGraph g = WeightedSparseGraph(V, true); 16 | ReadWeightedGraph, int> readGraph(g, filename); 17 | 18 | cout<<"Test Bellman-Ford: "<, int> bellmanFord(g, 0); 20 | if( bellmanFord.negativeCycle() ) 21 | cout<<"The graph contain negative cycle!"< 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | template 13 | class ReadWeightedGraph { 14 | public: 15 | // 从文件 filename 中读取有权图的信息, 存储进图 graph 中 16 | ReadWeightedGraph(Graph &graph, const string &filename) { 17 | ifstream file(filename); 18 | string line; 19 | int V, E; 20 | 21 | assert(file.is_open()); 22 | 23 | assert(getline(file, line)); // 文件第一行,V 和 E 24 | stringstream s(line); 25 | s >> V >> E; 26 | 27 | assert(V == graph.V()); 28 | 29 | for (int i = 0; i < E; i++) { 30 | assert(getline(file, line)); 31 | stringstream s(line); 32 | 33 | int a, b; 34 | Weight weight; 35 | 36 | s >> a >> b >> weight; 37 | assert(a >= 0 && a < V); 38 | assert(b >= 0 && b < V); 39 | 40 | graph.addEdge(a, b, weight); 41 | } 42 | } 43 | }; 44 | 45 | #endif /* READGRAPH_H_ */ 46 | -------------------------------------------------------------------------------- /Graph/Shortest-path Algorithms/Dijkstra/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "WeightedSparseGraph.h" 3 | #include "ReadWeightedGraph.h" 4 | #include "Dijkstra.h" 5 | 6 | using namespace std; 7 | 8 | int main() { 9 | 10 | string filename = "test.txt"; 11 | int V = 5; 12 | 13 | WeightedSparseGraph g = WeightedSparseGraph(V, true); 14 | // Dijkstra最短路径算法同样适用于有向图 15 | //WeightedSparseGraph g = WeightedSparseGraph(V, false); 16 | ReadWeightedGraph, int> readGraph(g, filename); 17 | 18 | cout<<"Test Dijkstra:"<, int> dij(g, 0); 21 | 22 | for( int i = 0 ; i < V ; i ++ ) { 23 | 24 | if(dij.hasPathTo(i)){ 25 | cout << "Shortest Path to " << i << " : " << dij.shortestPathTo(i) << endl; 26 | 27 | dij.showPath(i); 28 | } 29 | else 30 | cout << "No Path to " << i << endl; 31 | 32 | cout << "----------" << endl; 33 | } 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /Graph/Shortest-path Algorithms/Dijkstra/test.txt: -------------------------------------------------------------------------------- 1 | 5 8 2 | 0 1 5 3 | 0 2 2 4 | 0 3 6 5 | 1 4 1 6 | 2 1 1 7 | 2 4 5 8 | 2 3 3 9 | 3 4 2 10 | -------------------------------------------------------------------------------- /Graph/Shortest-path Algorithms/README.md: -------------------------------------------------------------------------------- 1 | ## 最短路径算法 Shortest-path Algorithms 2 | 3 | 最小生成树,对于无向图来说; 4 | 5 | 最短路径问题,一般对于有向图,同时也适用无向图。 6 | 7 | 松弛操作(Relaxation)是求解最短路径算法的核心。 8 | 9 | ### [Dijkstra 算法](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Graph/Shortest-path%20Algorithms/Dijkstra) 10 | 11 | 贪婪算法 12 | 13 | Dijkstra 算法适用于处理没有负权边的图。 14 | 15 | 时间复杂度为 O(ElogV)。 16 | 17 | 借助最小索引堆来实现。 18 | 19 | ### [Bellman Ford 算法](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Graph/Shortest-path%20Algorithms/Bellman%20Ford) 20 | 21 | Bellman Ford 算法可以处理有负权边的图,但是图中不能有负权环。 22 | 23 | 复杂度为 O(EV)。 24 | 25 | > **Bellman Ford 算法可以判断图中是否有负权环** 26 | 27 | 如果一个图没有负权环,从一点到另外一点的最短路径,最多经过所有的 V 个顶点,有 V-1 条边;否则,存在顶点经过了两次,既存在负权环。 28 | 29 | > **Bellman Ford 算法原理** 30 | 31 | 对所有的点进行第 1 次松弛操作,找到从原点开始,经过 1 条边的最短路径; 32 | 33 | 对所有的点进行第 2 次松弛操作,找到从原点开始,经过 2 条边的最短路径; 34 | 35 | 对一个点的一次松弛操作,就是找到经过这个点的另外一条路径,多一条边,权值更小。 36 | 37 | 如果一个图没有负权环,从一点到另外一点的最短路径,最多经过所有的 V 个顶点,有 V-1 条边,对所有的点进行 V-1 次松弛操作。 38 | 39 | 对所有的点进行 V-1 次松弛操作,理论上就找到了从源点到其他所有点的最短路径。 40 | 41 | 如果还可以继续松弛,所说原图中有负权环。 42 | 43 | ## 单源最短路径算法 44 | 45 | | 单源最短路径算法       | 适用  | 适用 |时间复杂度| 46 | | -------- | -----: | :----: |:----: | 47 | | Dijkstra | 无负权边 | 有向无向图均可 |O(ElogV)| 48 | | BellmanFord | 无负权环 | 有向图 |O(VE)| 49 | | 拓扑排序 | 有向无环图 DAG | 有向图 |O(V+E)| 50 | 51 | 52 | ## 延伸 53 | 54 | > **所有对最短路径算法** 55 | 56 | Floyed 算法,处理无负权环的图 O(V^3)。 57 | 58 | > **最长路径算法** 59 | 60 | 最长路径问题不能有正权环。 61 | 62 | 无权图的最长路径问题是指数级难度的。 63 | 64 | 对于有权图,不能使用 Dijkstra 求最长路径问题。 65 | 66 | 可以使用 Bellman-Ford 算法。 67 | -------------------------------------------------------------------------------- /Graph/TestMain/ComponentMain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "SparseGraph.h" 3 | #include "DenseGraph.h" 4 | #include "ReadGraph.h" 5 | #include "Component.h" 6 | 7 | using namespace std; 8 | 9 | int main() { 10 | 11 | string filename = "test.txt"; 12 | 13 | SparseGraph g1(10, false); 14 | ReadGraph readGraph1(g1, filename); 15 | Component component1(g1); 16 | cout << "test.txt, Component Count: " << component1.count() << endl; 17 | 18 | cout << endl; 19 | 20 | DenseGraph g2(10, false); 21 | ReadGraph readGraph2(g2, filename); 22 | Component component2(g2); 23 | cout<<"test.txt, Component Count: "< 2 | #include "SparseGraph.h" 3 | #include "DenseGraph.h" 4 | #include "ReadGraph.h" 5 | #include "FindPath.h" 6 | 7 | using namespace std; 8 | 9 | int main() { 10 | 11 | string filename = "test.txt"; 12 | SparseGraph g = SparseGraph(10, false); 13 | ReadGraph readGraph(g, filename); 14 | g.show(); 15 | cout< path(g, 0); 18 | cout<<"Path from 0 to 7 : " << endl; 19 | path.showPath(7); 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /Graph/TestMain/GraphIteratorMain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "SparseGraph.h" 5 | #include "DenseGraph.h" 6 | 7 | using namespace std; 8 | 9 | #define N 10 10 | #define M 50 11 | 12 | int main() { 13 | srand(time(NULL)); 14 | 15 | // Sparse Graph 16 | SparseGraph sparseGraph(N, false); 17 | 18 | for (int i = 0; i < M; i++) { 19 | int a = rand() % N; 20 | int b = rand() % N; 21 | 22 | sparseGraph.addEdge(a, b); // 增加邻边 23 | } 24 | 25 | // 遍历邻边 O(E) 26 | for (int v = 0; v < N; v++) { 27 | cout << v << " : "; 28 | 29 | SparseGraph::adjIterator it(sparseGraph, v); 30 | 31 | for (int w = it.begin(); !it.end(); w = it.next()) { 32 | cout << w << " "; 33 | } 34 | 35 | cout << endl; 36 | } 37 | 38 | cout << "----------------------------------------------" << endl; 39 | 40 | // Dense Graph 41 | DenseGraph denseGraph(N, false); 42 | 43 | for (int i = 0; i < M; i++) { 44 | int a = rand() % N; 45 | int b = rand() % N; 46 | 47 | denseGraph.addEdge(a, b); // 增加邻边 48 | } 49 | 50 | // 遍历邻边 O(V^2) 51 | for (int v = 0; v < N; v++) { 52 | cout << v << " : "; 53 | 54 | DenseGraph::adjIterator it(denseGraph, v); 55 | 56 | for (int w = it.begin(); !it.end(); w = it.next()) { 57 | cout << w << " "; 58 | } 59 | 60 | cout << endl; 61 | } 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /Graph/TestMain/ReadGraphMain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "SparseGraph.h" 3 | #include "DenseGraph.h" 4 | #include "ReadGraph.h" 5 | 6 | using namespace std; 7 | 8 | int main() { 9 | 10 | string filename = "test.txt"; 11 | 12 | SparseGraph g1(10, false); 13 | ReadGraph readGraph1(g1, filename); 14 | g1.show(); 15 | 16 | cout << endl; 17 | 18 | DenseGraph g2(10, false); 19 | ReadGraph readGraph2(g2, filename); 20 | g2.show(); 21 | 22 | return 0; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /Graph/TestMain/ShortestPathMain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "DenseGraph.h" 3 | #include "SparseGraph.h" 4 | #include "FindPath.h" 5 | #include "ReadGraph.h" 6 | #include "ShortestPath.h" 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | string filename = "test.txt"; 12 | 13 | SparseGraph g(10, false); 14 | 15 | ReadGraph readGraph(g, filename); 16 | 17 | g.show(); 18 | 19 | cout << endl; 20 | 21 | // 比较使用深度优先遍历和广度优先遍历获得路径的不同 22 | // 广度优先遍历获得的是无权图的最短路径 23 | FindPath dfs(g, 0); 24 | cout<<"DFS : "; 25 | dfs.showPath(4); 26 | 27 | ShortestPath bfs(g, 0); 28 | cout<<"BFS : "; 29 | bfs.showPath(4); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /Graph/TestMain/test.txt: -------------------------------------------------------------------------------- 1 | 10 10 2 | 0 5 3 | 4 3 4 | 0 1 5 | 6 4 6 | 5 4 7 | 0 2 8 | 9 5 9 | 0 6 10 | 7 8 11 | 5 3 12 | -------------------------------------------------------------------------------- /Hash Table/HashTableExerciseForCS210Lab/README.md: -------------------------------------------------------------------------------- 1 | 说明:这是使用 Hash Table 的用户登录的实例,源代码来源于 [CS210 Lab: Hash Table](http://www.cs.uregina.ca/Links/class-info/210/Hash/#IMPLEMENTATION) 2 | 3 | Application: Looking up Passwords 4 | 5 | 该工程使用 C++ 实现,哈希表的哈希函数采用除法散列法,解决碰撞方式采用链接法(Chaining)。 6 | 7 | One possible use for a hash table is to store computer user login usernames and passwords. 8 | 9 | * `hashtbl.cpp` and `hashtble.h` -- contain the implementation of the hashtable class 10 | * `listlnk.cpp` and `listlnk.h` -- contain the implementation of linked lists class 11 | * `login.cpp` -- the main program. This contains the Password structure, which is inserted into the hashtable. 12 | * `password.dat` -- contains all the users and corresponding passwords. 13 | -------------------------------------------------------------------------------- /Hash Table/HashTableExerciseForCS210Lab/hashtbl.h: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------- 2 | // 3 | // Laboratory 12 hashtbl.h 4 | // 5 | // Class declaration for the Hash Table ADT 6 | // 7 | //-------------------------------------------------------------------- 8 | 9 | #include 10 | #include "listlnk.cpp" 11 | 12 | using namespace std; 13 | 14 | template < class DT, class KF > 15 | class HashTbl 16 | { 17 | public: 18 | HashTbl ( int initTableSize ); 19 | ~HashTbl (); 20 | 21 | void insert ( const DT &newDataItem) throw ( bad_alloc ); 22 | bool remove ( KF searchKey ); 23 | bool retrieve ( KF searchKey, DT &dataItem ); 24 | void clear (); 25 | 26 | bool isEmpty () const; 27 | bool isFull () const; 28 | 29 | void showStructure () const; 30 | 31 | private: 32 | int tableSize; 33 | List
*dataTable; 34 | }; 35 | -------------------------------------------------------------------------------- /Hash Table/HashTableExerciseForCS210Lab/password.dat: -------------------------------------------------------------------------------- 1 | jack broken.crown 2 | jill tumblin'down 3 | mary contrary 4 | bopeep sheep!lost 5 | -------------------------------------------------------------------------------- /Linked List/Convert Sorted List to Binary Search Tree/README.md: -------------------------------------------------------------------------------- 1 | ## Convert Sorted List to Binary Search Tree「LeetCode 109」 2 | 3 | 题目:将有序链表转换为二叉搜索树。 4 | 5 | ``` 6 | Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST. 7 | ``` 8 | 9 | 解题思路: 10 | 11 | 1. 二分搜索树的特点,根节点的值大于左节点的值,小于右节点的值 12 | 2. 每次需要先找到中间节点,然后一分为二 13 | 3. 对于链表,使用快慢指针法,找出链表的中间节点 14 | 4. 找到中间节点,以中间节点的值建立一个二叉搜索树的根节点,然后把链表断开,分成前后两个链表,前链表尾部记得为NULL,都不包含链表的中间节点 15 | 5. 对前后两个链表继续递归 16 | -------------------------------------------------------------------------------- /Linked List/Copy List with Random Pointer/CopyListwithRandomPointer.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list with a random pointer. 3 | * struct RandomListNode { 4 | * int label; 5 | * RandomListNode *next, *random; 6 | * RandomListNode(int x) : label(x), next(NULL), random(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | RandomListNode *copyRandomList(RandomListNode *head) { 12 | if (!head) { return NULL;} 13 | 14 | // 新增链表的每个节点 15 | for (RandomListNode *cur = head; cur; ) { 16 | RandomListNode *node = new RandomListNode(cur->label); 17 | 18 | node->next = cur->next; 19 | cur->next = node; 20 | cur = node->next; 21 | } 22 | 23 | // 对新增链表的每个节点,进行 random 24 | for (RandomListNode *cur = head; cur; ) { 25 | if (cur->random) { 26 | cur->next->random = cur->random->next; 27 | } 28 | 29 | cur = cur->next->next; 30 | } 31 | 32 | // 拆分新旧链表,返回新链表 33 | RandomListNode dummy(-1); 34 | RandomListNode *newCur = &dummy; 35 | RandomListNode *cur = head; 36 | 37 | while (cur) { 38 | newCur->next = cur->next; 39 | cur->next = cur->next->next; 40 | newCur = newCur->next; 41 | cur = cur->next; 42 | } 43 | 44 | return dummy.next; 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /Linked List/Copy List with Random Pointer/README.md: -------------------------------------------------------------------------------- 1 | ## Copy List with Random Pointer「LeetCode 138」 2 | 3 | 题目:深拷贝一个链表,链表除了含有 next 指针外,还包含一个 random 指针,该指针指向字符串中的某个节点或者为空。 4 | 5 | ``` 6 | A linked list is given such that each node contains an additional random pointer 7 | which could point to any node in the list or null. 8 | 9 | Return a deep copy of the list. 10 | ``` 11 | 12 | 解题思路:两边遍历,时间复杂度为 O(n),空间复杂度为 O(1)。 13 | 14 | 1. 第一个遍历,一个个复制节点,新链表和旧链表组成一个链表 15 | 2. 第二个遍历,旧链表有 random 指针指向,对新链表的节点也要做 random 指针指向 16 | 3. 新旧链表的拆分 17 | -------------------------------------------------------------------------------- /Linked List/Delete Node in a Linked List/DeleteNode.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Write a function to delete a node (except the tail) in a singly linked list, given only access to that node. 3 | * Supposed the linked list is 1 -> 2 -> 3 -> 4 and you are given the third node with value 3, 4 | * the linked list should become 1 -> 2 -> 4 after calling your function. 5 | */ 6 | 7 | /** 8 | * Definition for singly-linked list. 9 | * struct ListNode { 10 | * int val; 11 | * ListNode *next; 12 | * ListNode(int x) : val(x), next(NULL) {} 13 | * }; 14 | */ 15 | 16 | class Solution { 17 | public: 18 | void deleteNode(ListNode* node) { 19 | if (!node) 20 | { 21 | return; 22 | } 23 | 24 | if (!node->next) 25 | { 26 | throw "the node next is NULL"; 27 | } 28 | 29 | 30 | ListNode *nextNode = node->next; 31 | node->val = nextNode->val; 32 | node->next = nextNode->next; 33 | 34 | delete nextNode; 35 | 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /Linked List/Delete Node in a Linked List/README.md: -------------------------------------------------------------------------------- 1 | ## Delete Node in a Linked List「LeetCode 237」 2 | 3 | 题目要求是在单链表中删除一个节点,已经告诉要删除的节点,怎么去删除。 4 | 5 | ```cpp 6 | struct ListNode { 7 | int val; 8 | ListNode *next; 9 | ListNode(int x) : val(x), next(NULL) {} 10 | }; 11 | 12 | class Solution{ 13 | public: 14 | void deleteNode(ListNode *node) { 15 | 16 | } 17 | }; 18 | ``` 19 | 20 | **如何删除指定的节点?** 21 | 22 | 方法:跳出传统思维(用删除的前一个节点来操作),单链表的特点是不知道前驱节点。既然已知删除节点,那么很容易知道它的下一个节点,将下一个节点的值赋给待删除节点,这样删除节点和它的下一个节点就是一样,用删除节点的 next 指向它的next的next;这样只用删除待删除节点的下一个节点就可以了。 23 | 24 | ```cpp 25 | void deleteNode(ListNode *node) { 26 | 27 | ListNode *nextNode = node->next; 28 | 29 | node->val = nextNode->val; 30 | node->next = nextNode->next; 31 | 32 | delete nextNode; 33 | } 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /Linked List/Insertion Sort List/InsertionSortList.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode *insertionSortList(ListNode *head) { 12 | if (!head || !(head->next)) { 13 | return head; 14 | } 15 | 16 | ListNode *dummy = new ListNode(-1); 17 | ListNode *cur = dummy; // cur 指向哑节点 18 | 19 | // 当前遍历的节点 20 | while (head) { 21 | ListNode *next = head->next; 22 | cur = dummy; // 每次比较当前遍历的节点,需要把 cur 重新指向哑节点,从头开始比较 23 | 24 | // 从头一个个比较 25 | while (cur->next && cur->next->val <= head->val) { 26 | cur = cur->next; 27 | } 28 | 29 | // 插入操作 30 | head->next = cur->next; 31 | cur->next = head; 32 | head = next; 33 | } 34 | 35 | return dummy->next; 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /Linked List/Insertion Sort List/README.md: -------------------------------------------------------------------------------- 1 | ## Insertion Sort List「LeetCode 147」 2 | 3 | 题目:使用插入排序算法排序一个链表 4 | 5 | ``` 6 | Sort a linked list using insertion sort. 7 | ``` 8 | 9 | 解题思路: 10 | 11 | 1. 插入排序使用链表中,思想与使用数组中一样,时间复杂度为 O(n^2), 空间复杂度为 O(1) 12 | 2. 借助哑节点 dummy,每次遍历,把当前节点插入到已排序的链表中,这里已排序链表是当前遍历节点前的已排序链表 13 | 3. 如何插入已排序链表,其实也需要遍历,值大小判断 14 | 4. 找到插入的位置,涉及到链表插入操作 15 | -------------------------------------------------------------------------------- /Linked List/Intersection of Two Linked Lists/IntersectionOfTwoLinkedLists.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { 12 | if (!headA || !headB) { 13 | return NULL; 14 | } 15 | 16 | int lengthA = 0; 17 | int lengthB = 0; 18 | 19 | ListNode *pA = headA; 20 | ListNode *pB = headB; 21 | 22 | while (pA) { 23 | lengthA++; 24 | pA = pA->next; 25 | } 26 | 27 | while (pB) { 28 | lengthB++; 29 | pB = pB->next; 30 | } 31 | 32 | if (lengthA <= lengthB) { 33 | pA = headA; 34 | pB = headB; 35 | 36 | int n = lengthB - lengthA; 37 | 38 | while(n) { 39 | pB = pB->next; 40 | n--; 41 | } 42 | } else { 43 | pA = headA; 44 | pB = headB; 45 | 46 | int n = lengthA - lengthB; 47 | 48 | while(n) { 49 | pA = pA->next; 50 | n--; 51 | } 52 | } 53 | 54 | while (pA != pB) { 55 | pA = pA->next; 56 | pB = pB->next; 57 | } 58 | 59 | return pA; 60 | } 61 | }; 62 | -------------------------------------------------------------------------------- /Linked List/Intersection of Two Linked Lists/README.md: -------------------------------------------------------------------------------- 1 | ## Intersection of Two Linked Lists「LeetCode 160」 2 | 3 | 题目:找出两个单链表的第一个交集点。找到交互点,需要保持原有的结构返回。 4 | 5 | ``` 6 | Write a program to find the node at which the intersection of two singly linked lists begins. 7 | 8 | 9 | For example, the following two linked lists: 10 | 11 | A: a1 → a2 12 | ↘ 13 | c1 → c2 → c3 14 | ↗ 15 | B: b1 → b2 → b3 16 | begin to intersect at node c1. 17 | 18 | Notes: 19 | 20 | If the two linked lists have no intersection at all, return null. 21 | The linked lists must retain their original structure after the function returns. 22 | You may assume there are no cycles anywhere in the entire linked structure. 23 | Your code should preferably run in O(n) time and use only O(1) memory. 24 | ``` 25 | 26 | 解题思路: 27 | 28 | 1. 理解题目,两个链表,不构成环,并且长度不一定相等,如果两个链表有交集点,那么交集点之后的所有节点都是两个链表共有的 29 | 2. 链表 A 的长度为 lengthA,链表 B 的长度为 lengthB 30 | 3. 以尾部对齐,如果两个链表长度不相等,那么可以先让长度长的链表从头节点先走 abs(lengthA - lengthB) 步,这样两个链表的指针就可以对齐 31 | 4. 最后长度短的从起始开始走,长度长的继续向前走,这样,节点值相等就为交集点 32 | -------------------------------------------------------------------------------- /Linked List/Linked List Cycle/Linked List Cycle.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveLauwh/Algorithms/e8ce0c5cc2a54fbe9700ed8c02acf0f758243eaa/Linked List/Linked List Cycle/Linked List Cycle.PNG -------------------------------------------------------------------------------- /Linked List/Linked List Cycle/README.md: -------------------------------------------------------------------------------- 1 | ## 如何判断单链表存在环 「LeetCode 141」 2 | 3 | 利用快慢指针方法,设定两个指针 slow、fast,初始都指向头指针,其中 slow 每次前进一步,fast 每次前进二步;如果单链表存在环,那么 fast 必定先进入环,而 slow 后进入环,必定会相遇。否则不存在环,fast 遇到 NULL 退出。 4 | 5 | ## 对于存在环的单链表,求出环的入口点 「LeetCode 142」 6 | 7 | ![](https://github.com/steveLauwh/Data-Structures-And-Algorithms/raw/master/Linked%20List/Linked%20List%20Cycle/Linked%20List%20Cycle.PNG) 8 | 9 | 推理: 10 | 11 | fast 与 slow 相遇时,slow 肯定没有遍历完链表,而 fast 已经在环内循环了 n 圈(n>=1)。 12 | 13 | 标记三个点,起始点为 X,环的入口点为 Y,相遇点为 Z。 14 | 15 | 设整个链表长度为 L,起始点到环的入口点距离为 a,环的入口点到相遇点距离为 b,相遇点到环的入口点距离是c。(起始点是开始,方向性) 16 | 17 | 假设 slow 走 s 步,则 fast 走了 2s 步(fast 步数还等于 s 加上 在环上多转的 n 圈),环长为 r; 18 | 19 | 得出关系:2s = s + nr,所以 s = nr。 20 | 21 | 此时,slow 和 fast 相遇, 得出关系:a + b = s = nr。 22 | 23 | a + b = nr = (n-1)r + r = (n-1)r + L -a 24 | 25 | a = (n-1)r + (L - a - b) 26 | 27 | 其实 (L - a - b) 就是相遇点到环的入口点的距离,等于 c。 28 | 29 | 表达式关系表明:从链表头到环的入口点 等于 (n-1)个环 + 相遇点到环的入口点。其中 (n-1)个环 最终还是它自己的起点,于是从链表头开始走和从相遇点开始走, 30 | 每一次各走一步,两个指针必定会相遇,且相遇第一点就是环的入口点。 31 | 32 | -------------------------------------------------------------------------------- /Linked List/Merge Two Sorted Lists/MergeTwoSortedLists.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { 12 | if (!l1 && !l2) { 13 | return NULL; 14 | } 15 | 16 | if (!l1) { 17 | return l2; 18 | } 19 | 20 | if (!l2) { 21 | return l1; 22 | } 23 | 24 | ListNode dummy(-1); 25 | 26 | dummy.next = l1; 27 | 28 | ListNode *p = &dummy; 29 | 30 | while (l1 && l2) { 31 | if (l1->val > l2->val) { 32 | p->next = l2; 33 | l2 = l2->next; 34 | p = p->next; 35 | p->next = l1; 36 | } 37 | else { 38 | p = l1; 39 | l1 = l1->next; 40 | } 41 | } 42 | 43 | if (l2) { 44 | p->next = l2; 45 | } 46 | 47 | return dummy.next; 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /Linked List/Merge Two Sorted Lists/README.md: -------------------------------------------------------------------------------- 1 | ## Merge Two Sorted Lists 合并两个已排序的链表「LeetCode 21」 2 | 3 | **题目要求** 4 | 5 | ``` 6 | Merge two sorted linked lists and return it as a new list. 7 | The new list should be made by splicing together the nodes of the first two lists. 8 | ``` 9 | ```cpp 10 | /** 11 | * Definition for singly-linked list. 12 | * struct ListNode { 13 | * int val; 14 | * ListNode *next; 15 | * ListNode(int x) : val(x), next(NULL) {} 16 | * }; 17 | */ 18 | class Solution { 19 | public: 20 | ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { 21 | 22 | } 23 | }; 24 | ``` 25 | 26 | 将两个已排序的链表合并成一个新的链表。合并后的链表肯定也是排好序的。 27 | 28 | 思路: 29 | 30 | * 为了更好操作合并的新链表,首先生成哑节点 dummy(-1); 31 | * 以某一个链表为主链表,以它为准,dummy(-1) 的 next 指向它,另外新增遍历指针 p 指向 dummy,p 是在 l1 和 l2 两个链表中来回移动; 32 | * 涉及到链表节点的值比较大小,插入操作,插入一般往前插入; 33 | * 假设 l1 链表为主链表,要把 l2 合并到 l1 上,当 l1->val > l2->val,那么就把 l2 指向的节点插入到 l1 上;否则 l1 指向它的下一个节点; 34 | * l1 作为主链表,当 l1 遍历完,但是 l2 没有遍历完;需要把 l2 剩下合并到 l1 上;当 l2 遍历完,l1 没有遍历完,因为主链表,所以不需要操作。 35 | 36 | 总结: 37 | 38 | * 链表的操作,注意先后顺序,不要出现断链; 39 | * 要思考判断条件是什么,边界情况如何。 40 | -------------------------------------------------------------------------------- /Linked List/Odd Even Linked List/OddEvenLinkedList.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* oddEvenList(ListNode* head) { 12 | if (!head) { 13 | return NULL; 14 | } 15 | 16 | if (!(head->next)) { 17 | return head; 18 | } 19 | 20 | ListNode *odd = head; // 奇节点 21 | ListNode *even = head->next; // 偶节点 22 | 23 | // 保存偶节点的头节点,遍历完需要连接 24 | ListNode *temp = even; 25 | 26 | while (even && even->next) { 27 | odd->next = even->next; 28 | odd = odd->next; 29 | 30 | even->next = odd->next; 31 | even = even->next; 32 | } 33 | 34 | odd->next = temp; 35 | 36 | return head; 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /Linked List/Odd Even Linked List/README.md: -------------------------------------------------------------------------------- 1 | ## Odd Even Linked List 所有奇节点在前,偶节点在后「LeetCode 328」 2 | 3 | 题目:使链表的所有奇节点在前,偶节点在后 4 | 5 | ``` 6 | Given a singly linked list, group all odd nodes together followed by the even nodes. 7 | 8 | Please note here we are talking about the node number and not the value in the nodes. 9 | 10 | You should try to do it in place. The program should run in O(1) space complexity and O(nodes) time complexity. 11 | 12 | Example: 13 | Given 1->2->3->4->5->NULL, 14 | return 1->3->5->2->4->NULL. 15 | ``` 16 | 17 | 解题思路: 18 | 19 | 1. 题目链表是按顺序,奇偶相连 20 | 2. 两个指针,一个指针 odd 指向奇节点,一个指针 even 指向偶节点,所有奇节点形成一个链表,所有偶节点形成一个链表 21 | 3. 注意在遍历前,需要保存偶节点的头节点,遍历完需要连接;最后把奇节点形成链表连接上偶节点形成链表 22 | -------------------------------------------------------------------------------- /Linked List/Palindrome Linked List/README.md: -------------------------------------------------------------------------------- 1 | ## Palindrome Linked List「LeetCode 234」 2 | 3 | 题目:判断单链表是不是回文,要求 O(n) 的时间复杂度和 O(1) 的空间复杂度。 4 | 5 | ``` 6 | Given a singly linked list, determine if it is a palindrome. 7 | 8 | Follow up: 9 | Could you do it in O(n) time and O(1) space? 10 | ``` 11 | 12 | 解题思路: 13 | 14 | 方法一: 15 | 16 | 遍历整个链表,将链表每个节点的值记录在数组中,再判断数组是不是一个回文数组,时间复杂度为 O(n),但空间复杂度也为 O(n),不满足空间复杂度要求。 17 | 18 | 方法二: 19 | 20 | 利用栈先进后出的性质,将链表前半段压入栈中,再逐个弹出与链表后半段比较。时间复杂度 O(n),但仍然需要 n/2 的栈空间,空间复杂度为 O(n)。 21 | 22 | 方法三: 23 | 24 | 反转链表法,将链表后半段原地翻转,再将前半段、后半段依次比较,判断是否相等,时间复杂度 O(n),空间复杂度为 O(1) 满足题目要求。 25 | 26 | 链表翻转可以参考 [Reverse Linked List](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Linked%20List/Reverse%20Linked%20List) 的代码。 27 | 28 | 对于反转链表法: 29 | 30 | 1. 如何找到链表的中心位置,注意链表长度的奇偶性,使用快慢指针法 31 | 2. 找到链表中心位置,将链表的后半段进行翻转操作 32 | 3. 前半段和后半段一一比较 33 | -------------------------------------------------------------------------------- /Linked List/Partition List/PartitionList.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* partition(ListNode* head, int x) { 12 | ListNode lessDummy(-1); 13 | ListNode moreDummy(-1); 14 | 15 | ListNode *less = &lessDummy; // 小于 x 的链表 16 | ListNode *more = &moreDummy; // 大于或等于 x 的链表 17 | 18 | for (ListNode *cur = head; cur; cur = cur->next) { 19 | if (cur->val < x) { 20 | less->next = cur; 21 | less = cur; 22 | } else { 23 | more->next = cur; 24 | more = cur; 25 | } 26 | } 27 | 28 | less->next = moreDummy.next; 29 | more->next = NULL; 30 | 31 | return lessDummy.next; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /Linked List/Partition List/README.md: -------------------------------------------------------------------------------- 1 | ## Partition List 「LeetCode 86」 2 | 3 | 题目:链表划分,给定一个链表和值 x,对其进行分区,使小于 x 的所有节点,都在大于或等于 x 前面,同时保留原有的顺序。 4 | 5 | ``` 6 | Given a linked list and a value x, 7 | 8 | partition it such that all nodes less than x come before nodes greater than or equal to x. 9 | 10 | You should preserve the original relative order of the nodes in each of the two partitions. 11 | 12 | For example, 13 | Given 1->4->3->2->5->2 and x = 3, 14 | return 1->2->2->4->3->5. 15 | ``` 16 | 17 | 解题思路: 18 | 19 | 1. 链表划分,一边的所有节点小于某值,另一边的所有节点都大于等于某值,可以使用两个指针,初始分别指向两个哑节点 dummy 20 | 2. 对链表遍历,指针 A 负责串联小于某值,指针 B 负责串联大于等于某值 21 | 3. 然后将指针 A 串联的链表,连接指针 B 串联的链表,这样就实现链表的划分(Partition)操作。 22 | -------------------------------------------------------------------------------- /Linked List/Plus One Linked List/README.md: -------------------------------------------------------------------------------- 1 | ## Plus One Linked List「LeetCode 369」 2 | 3 | 题目:链表加1 4 | 5 | ``` 6 | Given a non-negative number represented as a singly linked list of digits, plus one to the number. 7 | 8 | The digits are stored such that the most significant digit is at the head of the list. 9 | 10 | Example: 11 | Input: 12 | 1->2->3 13 | 14 | Output: 15 | 1->2->4 16 | ``` 17 | 18 | 解题思路: 19 | 20 | 此题从链表末尾加1,考虑进位,最容易想到的先把链表反转,再加1,然后求出结果,再把链表反转。 21 | 22 | 1. 反转链表 23 | 2. 循环遍历,从链表首元素开始加1,考虑进位 24 | 3. 再反转链表 25 | 26 | 27 | 另一种方法:可以利用栈的特性,先进后出 28 | 29 | 1. 先把链表节点全部入栈 30 | 2. 链表的尾节点最先出栈,加 1 操作,如果进位,继续出栈相加;当栈的最后一个节点(链表头节点)出栈,加进位操作,如果 carry 大于0,那么需要在链表头部插入一个新节点。 31 | -------------------------------------------------------------------------------- /Linked List/Remove Linked List Elements/README.md: -------------------------------------------------------------------------------- 1 | ## Remove Linked List Elements「LeetCode 203」 2 | 3 | 题目:给定一个值,删除链表中所有等于该值的节点。 4 | 5 | ``` 6 | Remove all elements from a linked list of integers that have value val. 7 | 8 | Example 9 | Given: 1 --> 2 --> 6 --> 3 --> 4 --> 5 --> 6, val = 6 10 | Return: 1 --> 2 --> 3 --> 4 --> 5 11 | ``` 12 | ``` 13 | /** 14 | * Definition for singly-linked list. 15 | * struct ListNode { 16 | * int val; 17 | * ListNode *next; 18 | * ListNode(int x) : val(x), next(NULL) {} 19 | * }; 20 | */ 21 | class Solution { 22 | public: 23 | ListNode* removeElements(ListNode* head, int val) { 24 | 25 | } 26 | }; 27 | ``` 28 | 29 | 解题思路: 30 | 31 | 1. 涉及到删除节点的题目,利用哑节点 dummy 32 | 2. 一前一后指针,遍历,当节点的值与给定的值相等,就做删除操作;否则一前一后指针,都前进一步。 33 | -------------------------------------------------------------------------------- /Linked List/Remove Linked List Elements/RemoveLinkedListElements.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* removeElements(ListNode* head, int val) { 12 | if (!head) { 13 | return NULL; 14 | } 15 | 16 | ListNode dummy(-1); 17 | 18 | dummy.next = head; 19 | 20 | ListNode *prev = &dummy; 21 | ListNode *cur = head; 22 | 23 | while (cur) { 24 | if (cur->val == val) { 25 | prev->next = cur->next; 26 | delete cur; 27 | cur = prev->next; 28 | } else { 29 | prev = prev->next; 30 | cur = cur->next; 31 | } 32 | } 33 | 34 | return dummy.next; 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /Linked List/Remove Nth Node From End of List/README.md: -------------------------------------------------------------------------------- 1 | ## 从尾部开始删第 n 个节点 Remove Nth Node From End of List「LeetCode 19」 2 | 3 | 题目:只允许一次遍历, 对一个链表,从尾部开始数,删掉第 n 个节点。 4 | 5 | ``` 6 | Given a linked list, remove the nth node from the end of list and return its head. 7 | 8 | For example, 9 | 10 | Given linked list: 1->2->3->4->5, and n = 2. 11 | 12 | After removing the second node from the end, the linked list becomes 1->2->3->5. 13 | Note: 14 | Given n will always be valid. 15 | Try to do this in one pass. 16 | ``` 17 | 18 | 解题思路: 19 | 20 | 1. 情况一:链表长度为2,n = 2,需要删除首元素 21 | 2. 由于只允许一次遍历,所以不能用一次完整的遍历来统计链表中元素的个数 22 | 3. 双指针法,prev,cur 指针分别指向链表头部,首先 cur 先走 n 步,如果此时 cur 指向为空,那么删除的是首元素 23 | 4. 如果 cur 不指向空,那么此时 cur 和 prev 同时走,当 cur 走完,那么 prev 指向要删除节点的前一个节点 24 | 5. 然后进行删除操作 25 | -------------------------------------------------------------------------------- /Linked List/Remove Nth Node From End of List/RemoveNthNodeFromEndofList.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* removeNthFromEnd(ListNode* head, int n) { 12 | if (!head) { 13 | return NULL; 14 | } 15 | 16 | if (!(head->next)) { 17 | if (n == 1) { 18 | return NULL; 19 | } 20 | } 21 | 22 | ListNode *pre = head; 23 | ListNode *cur = head; 24 | 25 | // cur 先走 n 步 26 | for (int i = 0; i < n; i++) { 27 | cur = cur->next; 28 | } 29 | 30 | // 说明链表的长度为n,要删除首元素 31 | if (!cur) { 32 | return head->next; 33 | } 34 | 35 | // 继续同时走 36 | while (cur->next) { 37 | cur = cur->next; 38 | pre = pre->next; 39 | } 40 | 41 | pre->next = pre->next->next; 42 | 43 | return head; 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /Linked List/Reorder List/README.md: -------------------------------------------------------------------------------- 1 | ## Reorder List「LeetCode 143」 2 | 3 | 题目:给定一个链表,把最后一个结点插入到第1个结点后,倒数第二个结点插入到第2个结点后,倒数第三个结点插入到第3个结点后,以此类推…… 4 | 5 | ``` 6 | Given a singly linked list L: L0->L1->…->Ln-1->Ln, 7 | reorder it to: L0->Ln->L1->Ln-1->L2->Ln-2->… 8 | 9 | You must do this in-place without altering the nodes' values. 10 | 11 | For example, 12 | Given {1,2,3,4}, reorder it to {1,4,2,3}. 13 | ``` 14 | 15 | 解题思路: 16 | 17 | 1. 利用快慢指针法,找出链表中间点,分成两部分 18 | 2. 把后半部分的链表进行翻转操作 19 | 3. 把翻转后的后半部分链表一个个插入到前半部分 20 | 21 | 特别注意: 22 | 23 | * 当链表只有两个元素,是不用重排序的,因为第一个元素 L0 始终是第一个。 24 | * 前半部分链表尾部需要置 NULL。 25 | -------------------------------------------------------------------------------- /Linked List/Reverse Linked List/README.md: -------------------------------------------------------------------------------- 1 | ## Reverse Linked List「LeetCode 206」 2 | 3 | 题目要求:反转一个单链表,倒置链表。 4 | 5 | 1->2->3->4->5 6 |     || 7 | 5->4->3->2->1 8 | 9 | ``` 10 | Hint: 11 | A linked list can be reversed either iteratively or recursively. Could you implement both? 12 | 13 | /** 14 | * Definition for singly-linked list. 15 | * struct ListNode { 16 | * int val; 17 | * ListNode *next; 18 | * ListNode(int x) : val(x), next(NULL) {} 19 | * }; 20 | */ 21 | class Solution { 22 | public: 23 | ListNode* reverseList(ListNode* head) { 24 | 25 | } 26 | }; 27 | ``` 28 | 29 | 解题思路: 30 | 31 | 递归和迭代两个版本。 32 | 33 | **迭代版本:** 34 | 35 | 1. 使用三个指针,prev 初始指向空,cur 初始指向 head,next 初始指向 cur->next 36 | 2. 判断终止条件,cur 不为空,cur 一直向遍历到尾部 37 | 3. 从头节点开始,一个个节点进行反转 38 | 39 | **递归版本:** 40 | 41 | 对于递归实现,首先反转从第二个结点到最后一个结点的链表,然后再将头结点放到已反转链表的最后,函数返回新链表的头结点。 42 | 43 | ## Reverse Linked List II「LeetCode 92」 44 | 45 | 题目:一个单链表,给定要倒序的起始位置,将起始位置进行倒序。 46 | 47 | ``` 48 | Reverse a linked list from position m to n. Do it in-place and in one-pass. 49 | 50 | For example: 51 | Given 1->2->3->4->5->NULL, m = 2 and n = 4, 52 | 53 | return 1->4->3->2->5->NULL. 54 | 55 | Note: 56 | Given m, n satisfy the following condition: 57 | 1 ≤ m ≤ n ≤ length of list. 58 | ``` 59 | 60 | 解题思路:头插法 61 | 62 | 1. 借用哑节点,首先遍历到第 m 位置前一个节点,新建一个指针指向它 63 | 2. 两个指针,一前一后,对 m 到 n 位置的节点开始使用头插入 64 | 65 | 66 | -------------------------------------------------------------------------------- /Linked List/Reverse Linked List/ReverseLinkedList.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | // 迭代版本 10 | class Solution { 11 | public: 12 | ListNode* reverseList(ListNode* head) { 13 | if (!head || !(head->next)) { 14 | return head; 15 | } 16 | 17 | ListNode *prev = NULL; 18 | ListNode *cur = head; 19 | 20 | while (cur) { 21 | ListNode *nextNode = cur->next; 22 | cur->next = prev; 23 | prev = cur; 24 | cur = nextNode; 25 | } 26 | 27 | return prev; 28 | } 29 | }; 30 | 31 | // 递归版本 32 | /** 33 | * Definition for singly-linked list. 34 | * struct ListNode { 35 | * int val; 36 | * ListNode *next; 37 | * ListNode(int x) : val(x), next(NULL) {} 38 | * }; 39 | */ 40 | class Solution { 41 | public: 42 | ListNode* reverseList(ListNode* head) { 43 | if (!head || !(head->next)) { 44 | return head; 45 | } 46 | 47 | ListNode *ret = reverseList(head->next); 48 | head->next->next = head; 49 | head->next = NULL; 50 | 51 | return ret; 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /Linked List/Reverse Linked List/ReverseLinkedListII.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* reverseBetween(ListNode* head, int m, int n) { 12 | if (!head || !(head->next)) { 13 | return head; 14 | } 15 | 16 | ListNode dummy(-1); 17 | 18 | dummy.next = head; 19 | 20 | ListNode *head1 = &dummy; 21 | 22 | // 遍历完后,head1指向 m 位置的前一个节点 23 | for (int i = 1; i < m; i++) { 24 | head1 = head1->next; 25 | } 26 | 27 | ListNode *prev = head1->next; // prev 指向 m 位置 28 | 29 | ListNode *cur = prev->next; 30 | 31 | // 头插法 32 | for (int i = m; i < n; i++) { 33 | prev->next = cur->next; 34 | cur->next = head1->next; 35 | head1->next = cur; 36 | cur = prev->next; 37 | } 38 | 39 | return dummy.next; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /Linked List/Reverse Nodes in k-Group/README.md: -------------------------------------------------------------------------------- 1 | ## Reverse Nodes in k-Group「LeetCode 25」 2 | 3 | 题目:每k个一组进行翻转 4 | 5 | ``` 6 | Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. 7 | 8 | k is a positive integer and is less than or equal to the length of the linked list. 9 | 10 | If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is. 11 | 12 | You may not alter the values in the nodes, only nodes itself may be changed. 13 | 14 | Only constant memory is allowed. 15 | 16 | For example, 17 | Given this linked list: 1->2->3->4->5 18 | 19 | For k = 2, you should return: 2->1->4->3->5 20 | 21 | For k = 3, you should return: 3->2->1->4->5 22 | ``` 23 | 24 | 解题思路:分 k 组,局部翻转 25 | 26 | 1. 引入 dummy 哑节点,遍历,引入计数,当计数值等于 k,就局部翻转;否则继续遍历 27 | 2. 局部翻转操作 28 | 29 | -------------------------------------------------------------------------------- /Linked List/Reverse Nodes in k-Group/ReverseNodesInk-Group.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* reverseKGroup(ListNode* head, int k) { 12 | if (!head || k == 1) { 13 | return head; 14 | } 15 | 16 | ListNode dummy(-1); 17 | ListNode *prev = &dummy; 18 | ListNode *cur = head; 19 | dummy.next = head; 20 | 21 | int count = 0; 22 | 23 | while (cur) { 24 | ++count; 25 | 26 | if (count % k == 0) { 27 | prev = reverseGroup(prev, cur->next); 28 | cur = prev->next; 29 | } else { 30 | cur = cur->next; 31 | } 32 | } 33 | 34 | return dummy.next; 35 | } 36 | 37 | private: 38 | ListNode* reverseGroup(ListNode* prev, ListNode* next) { 39 | ListNode *cur = prev->next; 40 | ListNode *curNext = cur->next; 41 | 42 | while (curNext != next) { 43 | cur->next = curNext->next; 44 | curNext->next = prev->next; 45 | prev->next = curNext; 46 | curNext = cur->next; 47 | } 48 | 49 | return cur; // 局部反转后的最后一个节点 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /Linked List/Rotate List/README.md: -------------------------------------------------------------------------------- 1 | ## Rotate List 「LeetCode 61」 2 | 3 | 题目:旋转链表,将链表向右旋转 k 个位置,k 为非负数。 4 | 5 | ``` 6 | Given a list, rotate the list to the right by k places, where k is non-negative. 7 | 8 | For example: 9 | Given 1->2->3->4->5->NULL and k = 2, 10 | return 4->5->1->2->3->NULL. 11 | ``` 12 | 13 | 解题思路: 14 | 15 | 1. 考虑特殊情况,链表为空或者 k 为 0 时,直接返回该链表 16 | 2. 求链表的长度 17 | 2. k 并没有指定大小,所以很可能大于链表的长度,所以旋转 k 次,k = k % len 18 | 3. 首尾相连,遍历指针 cur 指向首部 head,就形成一个环 19 | 4. 遍历指针 cur 继续遍历 len - k 步,停止再断环,就可以达到要求 20 | -------------------------------------------------------------------------------- /Linked List/Rotate List/RotateList.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* rotateRight(ListNode* head, int k) { 12 | if (!head || !(head->next) || k == 0) { 13 | return head; 14 | } 15 | 16 | ListNode *cur = head; 17 | 18 | int len = 1; 19 | 20 | // 求出链表的长度 21 | while (cur->next) { 22 | ++len; 23 | cur = cur->next; 24 | } 25 | 26 | k = k % len; 27 | 28 | // 首尾相连 29 | cur->next = head; 30 | 31 | // 继续遍历 len - k 步 32 | for (int i = 0; i < len - k; i++) { 33 | cur = cur->next; 34 | } 35 | 36 | // 断环操作,先获取链表的头节点 37 | head = cur->next; 38 | cur->next = NULL; 39 | 40 | return head; 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /Linked List/Sort List/README.md: -------------------------------------------------------------------------------- 1 | ## Sort List「LeetCode 148」 2 | 3 | 题目:使用常数级的空间复杂度,时间复杂度为 O(nlogn) 排序一个链表。 4 | 5 | ``` 6 | Sort a linked list in O(n log n) time using constant space complexity. 7 | ``` 8 | 9 | 解题思路: 10 | 11 | 1. 排序算法时间复杂度为 O(nlogn),可以使用归并排序、快速排序、堆排序实现 12 | 2. 此题使用归并排序求解,之前针对数组使用归并排序,空间复杂度 O(N),需要复制出相等的空间来进行赋值归并。 13 | 14 | 由于链表进行归并排序,根据链表特性,并不需要复制相等的空间进行赋值归并: 15 | 16 | 1. 如何找出链表的中间点 17 | 2. 两部分递归,递归完后,两部分已排序 18 | 3. 最后对两个已排序链表进行合并操作(LeetCode 21:Merge Two Sorted Lists) 19 | 20 | 21 | -------------------------------------------------------------------------------- /Linked List/Swap Nodes in Pairs/README.md: -------------------------------------------------------------------------------- 1 | ## Swap Nodes in Pairs「LeetCode 24」 2 | 3 | 题目:对链表中,每相邻的两个节点进行交换, 4 | 5 | ``` 6 | Given a linked list, swap every two adjacent nodes and return its head. 7 | 8 | For example, 9 | Given 1->2->3->4, you should return the list as 2->1->4->3. 10 | 11 | Your algorithm should use only constant space. 12 | 13 | You may not modify the values in the list, only nodes itself can be changed. 14 | ``` 15 | 16 | 解题思路: 17 | 18 | 1. 遍历一遍链表,时间复杂度为 O(n) 19 | 2. 借用哑节点 dummy,链表操作 20 | -------------------------------------------------------------------------------- /Linked List/Swap Nodes in Pairs/SwapNodesInPairs.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* swapPairs(ListNode* head) { 12 | if (!head) { 13 | return NULL; 14 | } 15 | 16 | if (!(head->next)) { 17 | return head; 18 | } 19 | 20 | ListNode dummy(-1); 21 | 22 | dummy.next = head; 23 | 24 | ListNode *pre = &dummy; 25 | ListNode *cur = head; 26 | 27 | // 链表操作 28 | while (cur && cur->next) { 29 | ListNode *nextNode = cur->next; 30 | 31 | cur->next = nextNode->next; 32 | nextNode->next = cur; 33 | pre->next = nextNode; 34 | 35 | pre = cur; 36 | cur = cur->next; 37 | } 38 | 39 | return dummy.next; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /Math/README.md: -------------------------------------------------------------------------------- 1 | ## Math 2 | 3 | -------------------------------------------------------------------------------- /Math/Reverse Integer/README.md: -------------------------------------------------------------------------------- 1 | ## Reverse Integer 2 | 3 | ``` 4 | Given a 32-bit signed integer, reverse digits of an integer. 5 | 6 | Example 1: 7 | 8 | Input: 123 9 | Output: 321 10 | Example 2: 11 | 12 | Input: -123 13 | Output: -321 14 | Example 3: 15 | 16 | Input: 120 17 | Output: 21 18 | 19 | Note: 20 | Assume we are dealing with an environment which could only hold integers within the 32-bit signed integer range. 21 | For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows. 22 | ``` 23 | 24 | 解题思路: 25 | 26 | 1. 对 32 位有符号的整形,进行翻转,翻转的值定义 64 位,防止翻转后的值溢出 27 | 28 | 2. 求余,获得个位 29 | 30 | 3. 求商,获得新的数 31 | 32 | -------------------------------------------------------------------------------- /Math/Reverse Integer/ReverseInteger.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int reverse(int x) { 4 | long long res = 0; // 返回值定义64位,防止原始旋转后溢出 5 | 6 | while (x) { 7 | res = res * 10 + x % 10; 8 | 9 | x = x / 10; 10 | } 11 | 12 | return (INT_MIN > res || res > INT_MAX) ? 0 : res; 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /Queue/Moving Average from Data Stream/MovingAverageFromDataStream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class MovingAverage { 4 | public: 5 | MovingAverage(int size) : len(size), sum(0){ 6 | } 7 | 8 | double next(int val) { 9 | if (q.size() > len) { 10 | sum -= q.front(); 11 | q.pop(); 12 | } 13 | 14 | sum += val; 15 | q.push(val); 16 | 17 | return sum / q.size(); 18 | } 19 | private: 20 | queue q; 21 | int len; 22 | double sum; 23 | }; 24 | -------------------------------------------------------------------------------- /Queue/Moving Average from Data Stream/README.md: -------------------------------------------------------------------------------- 1 | ## Moving Average from Data Stream「346」 2 | 3 | 题目:从数据流中移动平均值,给定一个滑动窗口值,计算在滑动窗口下,求所有值的平均值。 4 | 5 | ``` 6 | Given a stream of integers and a window size, calculate the moving average of all integers in the sliding window. 7 | 8 | For example, 9 | MovingAverage m = new MovingAverage(3); 10 | m.next(1) = 1 11 | m.next(10) = (1 + 10) / 2 12 | m.next(3) = (1 + 10 + 3) / 3 13 | m.next(5) = (10 + 3 + 5) / 3 14 | ``` 15 | 16 | 解题思路: 17 | 18 | 1. 给定一个固定值,每次读入一个数字,如果加上这个数字后总个数大于限制的个数,那么我们移除最早进入的数字,然后返回更新后的平均数 19 | 2. 使用 queue 来存储,当队列中元素个数大于限定个数,就移除队列首元素,并且 sum 要减去移除元素,如果没有大于限定个数,就累加 sum 20 | -------------------------------------------------------------------------------- /Queue/README.md: -------------------------------------------------------------------------------- 1 | ## Queue 2 | 3 | queue 是一种先进先出的数据结构。 4 | 5 | queue 允许新增元素、移除元素、从最底端加入元素、从最顶端取出元素。 6 | 7 | ```c++ 8 | // STL C++ 9 | push(x): 将 x 入队列的末端。 10 | 11 | pop(): 弹出队列的第一个元素。 12 | 13 | front(): 访问队首元素。 14 | 15 | back(): 访问队尾元素。 16 | 17 | empty(): 判断队列空。 18 | 19 | size(): 队列中的元素个数。 20 | ``` 21 | 22 | > **为什么 C++ STL queue 需要 front/pop ?** 23 | 24 | C++ STL的 std::queue 类是个容器适配器,即由其它容器(deque)包装而成的特殊数据结构。 25 | 26 | pop 和 front 这两个成员函数,一个删除队首顶素,一个获得队首元素,在绝大多数情况下,必须联合使用才能完成我们需要的动作。 27 | 因为我们在使用队列时,最常用的操作就是把队首元素从队列中“取”出来并进行处理。 28 | 29 | ```c++ 30 | #include 31 | 32 | queue q; 33 | 34 | // 基于 pop 返回的对象来构造对象 a,这是拷贝构造;如 A 类的拷贝构造函数抛出了异常,不符合关于异常安全的 “强保证” 要求。 35 | A a = q.pop(); 36 | ``` 37 | 38 | 所以 STL std::queue 结合 front 和 pop 两个函数,在其元素类型的拷贝构造函数可能抛出异常的情况下,仍然能达到强异常安全级别。 39 | 40 | ## LeetCode Queue 41 | 42 | * [Moving Average from Data Stream](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Queue/Moving%20Average%20from%20Data%20Stream) 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Data-Structures-And-Algorithms 2 | Solutions for some common data structure and algorithm problems written in C++ and Java. 3 | 4 | ## [Linked List](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Linked%20List) 5 | 6 | ## [Array](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Array) 7 | 8 | ## [String](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/String) 9 | 10 | ## [Stack](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Stack) 11 | 12 | ## [Queue](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Queue) 13 | 14 | ## [Bit Manipulation](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Bit%20Manipulation) 15 | 16 | ## [Math](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Math) 17 | 18 | ## [Sort](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Sort) 19 | 20 | ## [Tree](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Tree) 21 | 22 | ## [Union Find](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Union%20Find) 23 | 24 | ## [Graph](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Graph) 25 | 26 | ## [Hash Table](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Hash%20Table) 27 | 28 | # Practice 29 | 30 | ## [《剑指Offer》](https://github.com/steveLauwh/Algorithms/tree/master/sfo) 31 | 32 | # Reference 33 | 34 | * coursera: [Algorithms, Part I](https://www.coursera.org/learn/algorithms-part1) 35 | * LeetCode:http://blog.csdn.net/linhuanmars 36 | -------------------------------------------------------------------------------- /Sort/BubbleSort/Cpp/BubbleSort.cpp: -------------------------------------------------------------------------------- 1 | /* Bubble Sort: 下沉式冒泡,时间平均复杂度 O(N^2),空间复杂度 O(1),可以使用在已接近有序的数组情况下 */ 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | template 8 | void bubbleSort(T arr[], int n) 9 | { 10 | bool swapped = true; 11 | 12 | while (swapped) 13 | { 14 | swapped = false; // 交换标志 15 | 16 | for (int i = 0; i < n - 1; i++) 17 | { 18 | for (int j = 0; j < n - i - 1; j++) 19 | { 20 | if (arr[j] > arr[j + 1]) 21 | { 22 | swap(arr[j], arr[j + 1]); 23 | swapped = true; 24 | } 25 | } 26 | } 27 | } 28 | } 29 | 30 | template 31 | void bubbleSort2(T arr[], int n) 32 | { 33 | bool swapped = true; 34 | 35 | while (swapped) 36 | { 37 | swapped = false; 38 | 39 | for (int i = 1; i < n; i++) 40 | { 41 | if (arr[i - 1] > arr[i]) 42 | { 43 | swap(arr[i - 1], arr[i]); 44 | swapped = true; 45 | } 46 | } 47 | 48 | n--; // 每优化一趟,最大的元素放在最后的位置,所以最后元素不用在排序 49 | } 50 | } 51 | 52 | int main() 53 | { 54 | int arr[] = {2, 5, 10, 4, 3, 1, 6, 8, 7, 9}; 55 | 56 | int arrLength = sizeof(arr) / sizeof(arr[0]); 57 | 58 | bubbleSort2(arr, arrLength); 59 | 60 | for (int i = 0; i < arrLength; i++) 61 | { 62 | cout << arr[i] << " "; 63 | } 64 | 65 | cout << endl; 66 | } 67 | -------------------------------------------------------------------------------- /Sort/BubbleSort/Java/BubbleSort.java: -------------------------------------------------------------------------------- 1 | package com.sort.bubblesort; 2 | 3 | public class BubbleSort { 4 | 5 | private BubbleSort() {} 6 | 7 | public static void sort(int[] arr) { 8 | int arrLength = arr.length; 9 | 10 | boolean swapped = true; 11 | 12 | while (swapped) { 13 | swapped = false; 14 | 15 | for (int i = 1; i < arrLength; i++) { 16 | if (arr[i - 1] > arr[i]) { 17 | swap(arr, i - 1, i); 18 | swapped = true; 19 | } 20 | } 21 | 22 | arrLength--; 23 | } 24 | } 25 | 26 | public static void swap(int[] arr, int i, int j) { 27 | int temp = arr[i]; 28 | arr[i] = arr[j]; 29 | arr[j] = temp; 30 | } 31 | 32 | public static void main(String[] args) { 33 | int[] arr = {2, 5, 10, 4, 3, 1, 6, 8, 7, 9}; 34 | 35 | sort(arr); 36 | 37 | for (int item : arr) { 38 | System.out.println(item + " "); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sort/HeapSort/Java/MaxHeapSort.java: -------------------------------------------------------------------------------- 1 | package com.sort.maxheapsort; 2 | 3 | import com.sort.maxheapsort.MaxHeap; 4 | 5 | public class MaxHeapSort { 6 | private MaxHeapSort() {} 7 | 8 | // 对整个arr数组使用HeapSort1排序 9 | // HeapSort1, 将所有的元素依次添加到堆中, 在将所有元素从堆中依次取出来, 即完成了排序 10 | // 无论是创建堆的过程, 还是从堆中依次取出元素的过程, 时间复杂度均为O(nlogn) 11 | // 整个堆排序的整体时间复杂度为O(nlogn) 12 | public static void heapSort1(int[] arr) { 13 | int arrLength = arr.length; 14 | 15 | MaxHeap maxHeap = new MaxHeap(arrLength); 16 | 17 | for (int i = 0; i < arrLength; i++) { 18 | maxHeap.insert(arr[i]); 19 | } 20 | 21 | for (int i = arrLength - 1; i >= 0; i--) { 22 | arr[i] = maxHeap.extractMax(); 23 | } 24 | } 25 | 26 | // 对整个arr数组使用 HeapSort2 排序 27 | // HeapSort2, 借助我们的 heapify 过程创建堆 28 | // 此时, 创建堆的过程时间复杂度为O(n), 将所有元素依次从堆中取出来, 实践复杂度为O(nlogn) 29 | // 堆排序的总体时间复杂度依然是O(nlogn), 但是比HeapSort1性能更优, 因为创建堆的性能更优 30 | public static void heapSort2(int[] arr) { 31 | int arrLength = arr.length; 32 | 33 | MaxHeap maxHeap = new MaxHeap(arr); 34 | 35 | for (int i = arrLength - 1; i >= 0; i--) { 36 | arr[i] = maxHeap.extractMax(); 37 | } 38 | } 39 | 40 | public static void main(String[] args) { 41 | int[] arr = {2, 5, 11, 16, 3, 4, 19, 40, 23}; 42 | 43 | heapSort1(arr); 44 | 45 | for (int item : arr) { 46 | System.out.print(item + " "); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Sort/HeapSort/Java/MinHeapSort.java: -------------------------------------------------------------------------------- 1 | package com.sort.minheapsort; 2 | 3 | import com.sort.minheapsort.MinHeap; 4 | 5 | public class MinHeapSort { 6 | private MinHeapSort() {} 7 | 8 | // 对整个arr数组使用HeapSort1排序 9 | // HeapSort1, 将所有的元素依次添加到堆中, 在将所有元素从堆中依次取出来, 即完成了排序 10 | // 无论是创建堆的过程, 还是从堆中依次取出元素的过程, 时间复杂度均为O(nlogn) 11 | // 整个堆排序的整体时间复杂度为O(nlogn) 12 | public static void heapSort1(int[] arr) { 13 | int arrLength = arr.length; 14 | 15 | MinHeap minHeap = new MinHeap(arrLength); 16 | 17 | for (int i = 0; i < arrLength; i++) { 18 | minHeap.insert(arr[i]); 19 | } 20 | 21 | for (int i = 0; i < arrLength; i++) { 22 | arr[i] = minHeap.extractMin(); 23 | } 24 | } 25 | 26 | // 对整个arr数组使用 HeapSort2 排序 27 | // HeapSort2, 借助我们的 heapify 过程创建堆 28 | // 此时, 创建堆的过程时间复杂度为O(n), 将所有元素依次从堆中取出来, 实践复杂度为O(nlogn) 29 | // 堆排序的总体时间复杂度依然是O(nlogn), 但是比HeapSort1性能更优, 因为创建堆的性能更优 30 | public static void heapSort2(int[] arr) { 31 | int arrLength = arr.length; 32 | 33 | MinHeap minHeap = new MinHeap(arr); 34 | 35 | for (int i = 0; i < arrLength; i++) { 36 | arr[i] = minHeap.extractMin(); 37 | } 38 | } 39 | 40 | public static void main(String[] args) { 41 | int[] arr = {2, 5, 11, 16, 3, 4, 19, 40, 23}; 42 | 43 | heapSort2(arr); 44 | 45 | for (int item : arr) { 46 | System.out.print(item + " "); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Sort/InsertionSort/Cpp/InsertionSort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | // 插入排序,时间复杂度O(N^2),需用到O(1)的额外空间,在小数据量和已接近排序的数据量情况下,使用插入排序比较高效 6 | template 7 | void insertionSort(T arr[], int n) 8 | { 9 | for (int i = 1; i < n; i++) 10 | { 11 | // 待排序的元素 12 | T temp = arr[i]; 13 | 14 | // j 最后保存元素 temp 应该插入的位置 15 | int j = i; 16 | 17 | while (j > 0 && arr[j - 1] > temp) 18 | { 19 | arr[j] = arr[j - 1]; 20 | j--; 21 | } 22 | 23 | arr[j] = temp; 24 | } 25 | } 26 | 27 | int main() 28 | { 29 | int arr[] = {2, 5, 10, 4, 3, 1, 6, 8, 7, 9}; 30 | 31 | int arrLength = sizeof(arr) / sizeof(arr[0]); 32 | 33 | insertionSort(arr, arrLength); 34 | 35 | for (int i = 0; i < arrLength; i++) 36 | { 37 | cout << arr[i] << " "; 38 | } 39 | 40 | cout << endl; 41 | } 42 | -------------------------------------------------------------------------------- /Sort/InsertionSort/Java/InsertionSort.java: -------------------------------------------------------------------------------- 1 | package com.sort.insertionsort; 2 | 3 | /* InsertionSort 4 | * 核心:通过构建有序序列,对于未排序序列,在已排序序列中从后向前扫描(对于单向链表则只能从前往后 5 | 遍历),找到相应位置并插入。实现上通常使用in-place排序(需用到O(1)的额外空间) 6 | */ 7 | 8 | public class InsertionSort { 9 | 10 | private InsertionSort() {} 11 | 12 | public static void sort(int[] arr) { 13 | int arrLength = arr.length; 14 | 15 | for (int i = 1; i < arrLength; i++) { 16 | int temp = arr[i]; 17 | 18 | int j = i; 19 | 20 | while (j > 0 && arr[j - 1] > temp) { 21 | arr[j] = arr[j - 1]; 22 | j--; 23 | } 24 | 25 | arr[j] = temp; 26 | } 27 | } 28 | 29 | public static void main(String[] args) { 30 | int[] arr = {6, 7, 1, 3, 2, 5, 4, 8, 9, 10}; 31 | 32 | sort(arr); 33 | 34 | System.out.println("After the Insertion Sort: "); 35 | for (int item : arr) { 36 | System.out.print(item + " "); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sort/SelectionSort/Cpp/SelectionSort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | // an in-place comparison sort,O(N^2),不适合大数据量 6 | template 7 | void selectionSort(T arr[], int n) 8 | { 9 | for (int i = 0; i < n; i++) 10 | { 11 | int index = i; 12 | 13 | // 从待排序中,找到元素值最小的索引 14 | for (int j = i + 1; j < n; j++) 15 | { 16 | if (arr[j] < arr[index]) 17 | { 18 | index = j; 19 | } 20 | } 21 | 22 | // 将待排序的第一个元素与待排序中最小元素进行交换 23 | swap(arr[index], arr[i]); 24 | } 25 | } 26 | 27 | int main() 28 | { 29 | int arr[] = {2, 5, 10, 4, 3, 1, 6, 8, 7, 9}; 30 | 31 | int arrLength = sizeof(arr) / sizeof(arr[0]); 32 | 33 | selectionSort(arr, arrLength); 34 | 35 | for (int i = 0; i < arrLength; i++) 36 | { 37 | cout << arr[i] << " "; 38 | } 39 | 40 | cout << endl; 41 | } 42 | -------------------------------------------------------------------------------- /Sort/SelectionSort/Java/SelectionSort.java: -------------------------------------------------------------------------------- 1 | /* SelectionSort 2 | * 核心:不断地选择剩余元素中的最小者。 3 | 1. 找到数组中最小元素并将其和数组第一个元素交换位置。 4 | 2. 在剩下的元素中找到最小元素并将其与数组第二个元素交换,直到整个数组排序。 5 | */ 6 | 7 | package com.sort.selectionsort; 8 | 9 | public class SelectionSort { 10 | 11 | private SelectionSort() {} 12 | 13 | public static void sort(int[] arr) { 14 | int arrLength = arr.length; 15 | 16 | for (int i = 0; i < arrLength; i++) { 17 | int index = i; 18 | 19 | for (int j = i+1; j < arrLength; j++) { 20 | if (arr[j] < arr[index]) { 21 | index = j; 22 | } 23 | } 24 | 25 | swap(arr, i, index); 26 | } 27 | } 28 | 29 | public static void swap(int[] arr, int i, int j) { 30 | int temp = arr[i]; 31 | arr[i] = arr[j]; 32 | arr[j] = temp; 33 | } 34 | 35 | public static void main(String[] args) { 36 | int[] arr = {6, 7, 1, 3, 2, 5, 4, 8, 9, 10}; 37 | 38 | sort(arr); 39 | 40 | System.out.println("After the Selection Sort: "); 41 | for (int item : arr) { 42 | System.out.print(item + " "); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sort/ShellSort/Cpp/ShellSort.cpp: -------------------------------------------------------------------------------- 1 | /* Shell Sort: 插入排序的扩展,将待排序的数组按照步长 gap 进行分组,然后将每组的元素利用插入排序的方法进行排序,直到 gap 为 1,利用插入完成排序。 2 | */ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | template 9 | void shellsort(T arr[], int n) 10 | { 11 | int gap = 1; 12 | 13 | // gap = 1, 4, 13, 40..... 14 | while (gap < n / 3) 15 | { 16 | gap = gap * 3 + 1; // 步长 gap 17 | } 18 | 19 | while (gap >= 1) 20 | { 21 | for (int i = gap; i < n; i++) 22 | { 23 | T temp = arr[i]; 24 | 25 | int j = i; 26 | 27 | while (j >= gap && arr[j - gap] > temp) 28 | { 29 | arr[j] = arr[j - gap]; 30 | j = j - gap; 31 | } 32 | 33 | arr[j] = temp; 34 | } 35 | 36 | gap = gap / 3; 37 | } 38 | } 39 | 40 | int main() 41 | { 42 | int arr[] = {2, 5, 10, 4, 3, 1, 6, 8, 7, 9}; 43 | 44 | int arrLength = sizeof(arr) / sizeof(arr[0]); 45 | 46 | shellsort(arr, arrLength); 47 | 48 | for (int i = 0; i < arrLength; i++) { 49 | cout << arr[i] << " "; 50 | } 51 | 52 | cout << endl; 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /Sort/ShellSort/Java/ShellSort.java: -------------------------------------------------------------------------------- 1 | /* Shell Sort 2 | * 核心: 基于插入排序,使数组中任意间隔为h的元素都是有序的,即将全部元素分为h个区域使用插入排 3 | 序。其实现可类似于插入排序但使用不同增量。更高效的原因是它权衡了子数组的规模和有序性。 4 | */ 5 | 6 | package com.sort.shellsort; 7 | 8 | public class ShellSort { 9 | private ShellSort() {} 10 | 11 | public static void sort(int[] arr) { 12 | int gap = 1; 13 | 14 | int arrLength = arr.length; 15 | 16 | while (gap < arrLength / 3) { 17 | gap = gap * 3 + 1; 18 | } 19 | 20 | while (gap >= 1) { 21 | 22 | for (int i = gap; i < arrLength; i++) { 23 | 24 | int temp = arr[i]; 25 | int j = i; 26 | 27 | while (j >= gap && arr[j - gap] > temp) { 28 | arr[j] = arr[j - gap]; 29 | j = j - gap; 30 | } 31 | 32 | arr[j] = temp; 33 | } 34 | 35 | gap = gap / 3; 36 | } 37 | } 38 | 39 | public static void main(String[] args) { 40 | int[] arr = {2, 5, 10, 4, 3, 1, 6, 8, 7, 9}; 41 | 42 | sort(arr); 43 | 44 | System.out.println("After the shell sort : "); 45 | 46 | for (int item : arr) { 47 | System.out.print(item + " "); 48 | } 49 | } 50 | } 51 | 52 | 53 | -------------------------------------------------------------------------------- /Stack/Min Stack/MinStack.cpp: -------------------------------------------------------------------------------- 1 | class MinStack { 2 | public: 3 | /** initialize your data structure here. */ 4 | MinStack() { 5 | 6 | } 7 | 8 | void push(int x) { 9 | st.push(x); 10 | 11 | if (minst.empty() || x <= minst.top()) { 12 | minst.push(x); 13 | } 14 | } 15 | 16 | void pop() { 17 | if (st.top() == minst.top()) { 18 | minst.pop(); 19 | } 20 | 21 | st.pop(); 22 | } 23 | 24 | int top() { 25 | return st.top(); 26 | } 27 | 28 | int getMin() { 29 | return minst.top(); 30 | } 31 | 32 | private: 33 | stack st, minst; 34 | }; 35 | 36 | /** 37 | * Your MinStack object will be instantiated and called as such: 38 | * MinStack obj = new MinStack(); 39 | * obj.push(x); 40 | * obj.pop(); 41 | * int param_3 = obj.top(); 42 | * int param_4 = obj.getMin(); 43 | */ 44 | -------------------------------------------------------------------------------- /Stack/Min Stack/README.md: -------------------------------------------------------------------------------- 1 | ## 最小栈 Min Stack「LeetCode 155」 2 | 3 | 题目: 4 | ``` 5 | Design a stack that supports push, pop, top, and retrieving the minimum element in constant time. 6 | 7 | push(x) -- Push element x onto stack. 8 | pop() -- Removes the element on top of the stack. 9 | top() -- Get the top element. 10 | getMin() -- Retrieve the minimum element in the stack. 11 | Example: 12 | MinStack minStack = new MinStack(); 13 | minStack.push(-2); 14 | minStack.push(0); 15 | minStack.push(-3); 16 | minStack.getMin(); --> Returns -3. 17 | minStack.pop(); 18 | minStack.top(); --> Returns 0. 19 | minStack.getMin(); --> Returns -2. 20 | ``` 21 | 保证时间复杂度都是 O(1)。 22 | 23 | 题解: 24 | 25 | 栈是一种先入后出的数据结构。 26 | 27 | 最小栈比原有的栈 stack 多了一个功能,获取栈的最小值。 28 | 29 | **创建一个辅助栈 B,辅助栈 B 的栈顶元素始终是原有栈 A 的最小值。** 30 | 31 | 当第一个元素进入原有栈 A,也让新元素也进入辅助栈 B。这个唯一的元素就是原有栈 A 的当前最小值。 32 | 33 | 入栈 push:每当有新元素 x 进入原有栈 A,将新元素 x 与辅助栈 B 的栈顶元素比较,如果小,则就可以入辅助栈 B,否则就不入辅助栈 B。 34 | 35 | 出栈 pop:每当原有栈 A 有元素出栈,如果出栈元素是原有栈 A 当前最小值,那么让辅助栈 B 的栈顶元素也出栈。 36 | 37 | 获取栈顶元素 top:获取原有栈 A 的栈顶元素。 38 | 39 | 获取栈的最小值 getMin:获取辅助栈 B 的栈顶元素。 40 | 41 | -------------------------------------------------------------------------------- /Stack/README.md: -------------------------------------------------------------------------------- 1 | ## Stack 2 | 3 | 栈 是限制插入和删除只能在一个位置上进行的表,该位置是表的末端,叫做栈的顶(top)。 4 | 5 | 栈的特点是先进后出。 6 | 7 | 栈是一个表,任何实现表的方法都能实现栈。通常两种实现方法:链表和数组。 8 | 9 | ```c++ 10 | // STL C++ 11 | push(): 入栈 12 | 13 | pop(): 出栈 14 | 15 | top():指向栈顶元素 16 | ``` 17 | 18 | 栈的应用: 19 | 20 | * 平衡符号 21 | * 后缀表达式 22 | * 中缀到后缀的转换 23 | * 二叉树的非递归遍历 24 | 25 | ## LeetCode Stack 26 | 27 | * [Min Stack](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Stack/Min%20Stack) 28 | * [Valid Parentheses](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Stack/Valid%20Parentheses) 29 | -------------------------------------------------------------------------------- /Stack/Valid Parentheses/README.md: -------------------------------------------------------------------------------- 1 | ## Valid Parentheses「LeetCode 20」 2 | 3 | 题目:给定一个字符串,只包含'(', ')', '{', '}', '[' and ']';判断字符串中的括号匹配是否合法。 4 | 5 | ``` 6 | Given a string containing just the characters '(', ')', '{', '}', '[' and ']', 7 | 8 | determine if the input string is valid. 9 | 10 | The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and "([)]" are not. 11 | ``` 12 | 13 | 解题思路:栈顶元素反映了在嵌套的层次关系中,最近的需要匹配的元素。 14 | 15 | 使用栈。 16 | 17 | 1. 如果字符是 '{' 或 '(' 或 '[',就入栈 18 | 2. 如果该字符不是 '{' 或 '(' 或 '[',那么先获取栈顶元素,判断栈顶元素与当前字符的匹配字符是否相等。 19 | 20 | -------------------------------------------------------------------------------- /Stack/Valid Parentheses/ValidParentheses.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isValid(string s) { 4 | stack st; 5 | 6 | for (int i = 0; i < s.size(); i++) { 7 | if (s[i] == '(' || s[i] == '[' || s[i] == '{') { 8 | st.push(s[i]); 9 | } else { 10 | if (st.size() == 0) { 11 | return false; 12 | } 13 | 14 | char c = st.top(); 15 | st.pop(); 16 | 17 | char match; 18 | 19 | if (s[i] == ')') { 20 | match = '('; 21 | } else if (s[i] == '}') { 22 | match = '{'; 23 | } else { 24 | assert(s[i] == ']'); 25 | match = '['; 26 | } 27 | 28 | if (c != match) { 29 | return false; 30 | } 31 | } 32 | } 33 | 34 | if (st.size() != 0) { 35 | return false; 36 | } 37 | 38 | return true; 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /String/Add Binary/AddBinary.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string addBinary(string a, string b) { 4 | string ret; 5 | 6 | int aLength = a.size() - 1; 7 | int bLength = b.size() - 1; 8 | int carry = 0; 9 | 10 | while (aLength >= 0 || bLength >= 0) { 11 | // 三目运算符 12 | int m = (aLength >= 0 ? a[aLength--] - '0': 0); 13 | int n = (bLength >= 0 ? b[bLength--] - '0': 0); 14 | 15 | int sum = m + n + carry; 16 | 17 | ret = to_string(sum % 2) + ret; 18 | 19 | carry = sum / 2; 20 | } 21 | 22 | return carry == 1 ? "1" + ret : ret; 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /String/Add Binary/README.md: -------------------------------------------------------------------------------- 1 | ## Add Binary「LeetCode 67」 2 | 3 | 题目:两个字符串由二进制表示,求出和,也是由二进制表示 4 | 5 | ``` 6 | Given two binary strings, return their sum (also a binary string). 7 | 8 | For example, 9 | a = "11" 10 | b = "1" 11 | Return "100". 12 | ``` 13 | 14 | 解题思路: 15 | 16 | 考虑情况: 17 | 18 | * 两个字符串可能不相等 19 | * 考虑进位 carry 20 | * 从两个字符串的末位开始,一一相加,字符串取出的是字符,需要转换数字;无法取出,按 0 处理 21 | * 最后相加完,还要判断 carry 是否有进位 22 | 23 | 1. 对两个字符串遍历,从末位开始,每次取出一个字符,转为数字,相加 24 | 2. 相加和对 2 求余,为结果,对 2 求商,为进位 25 | 3. 最后还要判断下 carry,如果为 1 的话,要在结果最前面加上一个 1 26 | -------------------------------------------------------------------------------- /String/Add Strings/AddStrings.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string addStrings(string num1, string num2) { 4 | string &shortString = (num1.size() <= num2.size()) ? num1 : num2; 5 | string &longString = (num1.size() > num2.size()) ? num1 : num2; 6 | string result; 7 | 8 | int shortLength = shortString.size(); 9 | int longLength = longString.size(); 10 | 11 | int carry = 0; 12 | 13 | for (int i = shortLength - 1, j = longLength - 1; j >= 0 ; i--, j--) { 14 | int sum = 0; 15 | if (i >= 0) { 16 | sum = shortString[i] - '0' + longString[j] - '0' + carry; 17 | } else { 18 | sum = longString[j] - '0' + carry; 19 | } 20 | 21 | carry = sum / 10; // 进位 22 | result = char(sum % 10 + '0') + result; // 字符串连接 23 | } 24 | 25 | if (carry) { 26 | result = char(carry + '0') + result; 27 | } 28 | 29 | return result; 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /String/Add Strings/README.md: -------------------------------------------------------------------------------- 1 | ## 两个字符串相加「LeetCode 415」 2 | 3 | 题目:两个字符串是由两个非负整数(每位由0~9)构成,求出两个字符串之和。 4 | 5 | Given two non-negative numbers num1 and num2 represented as string, return the sum of num1 and num2. 6 | 7 | Note: 8 | The length of both num1 and num2 is < 5100. 9 | Both num1 and num2 contains only digits 0-9. 10 | Both num1 and num2 does not contain any leading zero. 11 | You must not use any built-in BigInteger library or convert the inputs to integer directly. 12 | 13 | 题解: 14 | 15 | * 两个字符串的长度可能不同,所以需要求出两个字符串长度; 16 | * 两个字符串相加,字符串的末尾是个位,两个字符串从末尾向前两两相加; 17 | * 相加考虑进位 carry; 18 | * 虽然每个字符串中的每个字符是由 0~9 构成,但是要获取其值,需要 s[i]-'0'; 最后数字转换字符,需要 s[i]+'0'; 19 | * 注意循环判定条件; 20 | 21 | -------------------------------------------------------------------------------- /String/Implement strStr/ImplementstrStr.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int strStr(string haystack, string needle) { 4 | if (needle.empty()) { 5 | return 0; 6 | } 7 | 8 | int m = haystack.size(); 9 | 10 | int n = needle.size(); 11 | 12 | if (m < n) { 13 | return -1; 14 | } 15 | 16 | for (int i = 0; i <= m - n; i++) { 17 | int j = 0; 18 | 19 | for (j = 0; j < n; j++) { 20 | if (haystack[i+j] != needle[j]) { 21 | break; 22 | } 23 | } 24 | 25 | if (j == n) { 26 | return i; 27 | } 28 | } 29 | 30 | return -1; 31 | 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /String/Implement strStr/README.md: -------------------------------------------------------------------------------- 1 | ## Implement strStr()「LeetCode 28」 2 | 3 | 题目:实现 strStr(string str1, string str2)函数, 4 | 5 | 功能:从字符串 str1 中查找是否有字符串 str2, 如果有,从 str1 中的 str2 位置起,返回 str1 的指针,如果没有,返回 null。 6 | 7 | ``` 8 | Implement strStr(). 9 | 10 | Returns the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack. 11 | ``` 12 | 13 | 实现strstr(). 返回 needle(关键字) 在 haystack(字符串) 中第一次出现的位置,如果 needle 不在 haystack 中,则返回 -1。 14 | 15 | 注:strstr() 是 c++ 中的一个函数 16 | 17 | 解题思路: 18 | 19 | 暴力解法 和 KMP 算法 20 | 21 | 字符串匹配问题 22 | 23 | 1. 字符串 str1 的长度为 m,字符串 str2 的长度为 n 24 | 2. 从 str1 从匹配 str2,如果匹配,返回 str2 在 str1 的第一次出现位置,暴力解法,双 for 循环,第一层 for 循环的终止条件小于等于 m - n;并不需要 25 | 整个 str1 都遍历完 26 | 3. 第二层循环,遍历 一遍 str2 字符串,str1 和 str2 的一个个字符对应比较,如果对应位置有不等的,则跳出循环,如果一直都没有跳出循环,则说明子字符串出现了,则返回起始位置即可 27 | -------------------------------------------------------------------------------- /String/README.md: -------------------------------------------------------------------------------- 1 | ## 字符串 2 | 3 | 合理使用 string,set,map 解决字符串处理问题。 4 | 5 | * [Reverse String](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/String/Reverse%20String) 6 | * [Add Strings](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/String/Add%20Strings) 7 | * [Valid Palindrome](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/String/Valid%20Palindrome) 8 | * [Implement strStr](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/String/Implement%20strStr) 9 | * [Valid Anagram](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/String/Valid%20Anagram) 10 | -------------------------------------------------------------------------------- /String/Reverse String/README.md: -------------------------------------------------------------------------------- 1 | ## 旋转字符串 Reverse String I「LeetCode 344」 2 | 3 | Write a function that takes a string as input and returns the string reversed. 4 | 5 | Example: 6 | Given s = "hello", return "olleh". 7 | 8 | 题解: 9 | 10 | 将一个字符串进行倒序输出。 11 | 12 | 其实就是首尾字符进行两两交换,第二个与倒数第二个进行两两交换,终止条件为中间字符。 13 | 14 | ## 旋转字符串 Reverse String II「LeetCode 541」 15 | 16 | 题目: 17 | 18 | ``` 19 | Given a string and an integer k, 20 | you need to reverse the first k characters for every 2k characters counting from the start of the string. 21 | If there are less than k characters left, reverse all of them. 22 | If there are less than 2k but greater than or equal to k characters, 23 | then reverse the first k characters and left the other as original. 24 | 25 | Example: 26 | Input: s = "abcdefg", k = 2 27 | Output: "bacdfeg" 28 | 29 | Restrictions: 30 | The string consists of lower English letters only. 31 | Length of the given string and k will in the range [1, 10000] 32 | ``` 33 | 34 | 题解: 35 | 36 | 给定一个字符串和一个整形 k,从字符串开始,每 2k 个字符,旋转前 k 个字符;当字符串不足 k 个字符,就全部旋转;当字符串小于 2k 个字符,但是大于 k 个字符,就只旋转前 k 个字符。 37 | 38 | C++ STL:旋转 `reverse   [first, last)` 39 | 40 | 每 2k 个字符进行遍历,`[i, i+k)`区间旋转,但是考虑到不足 2k 个字符就旋转前 k 个字符,所以翻转尾位置 `i+k 和 end()` 进行比较,每次取小者。 41 | -------------------------------------------------------------------------------- /String/Reverse String/ReverseStringI.cpp: -------------------------------------------------------------------------------- 1 | // 首尾两两交换 2 | 3 | class Solution { 4 | public: 5 | string reverseString(string s) { 6 | int length = s.size(); 7 | 8 | for (int i = 0; i < length/2; i++) { 9 | char temp = s[i]; 10 | s[i] = s[length - 1 -i]; 11 | s[length - 1 -i] = temp; 12 | } 13 | 14 | return s; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /String/Reverse String/ReverseStringII.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string reverseStr(string s, int k) { 4 | int length = s.size(); 5 | 6 | for (int i = 0; i < length; i += 2 * k) { 7 | reverse(s.begin() + i, min(s.begin() + i + k, s.end())); 8 | } 9 | 10 | return s; 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /String/Valid Anagram/README.md: -------------------------------------------------------------------------------- 1 | ## Valid Anagram「LeetCode 242」 2 | 3 | 题目:已知一个单词 s,给一个字符串 t,求 t 是否可以 d 颠倒组合成单词 s。 4 | 5 | ``` 6 | Given two strings s and t, write a function to determine if t is an anagram of s. 7 | 8 | For example, 9 | s = "anagram", t = "nagaram", return true. 10 | s = "rat", t = "car", return false. 11 | 12 | Note: 13 | You may assume the string contains only lowercase alphabets. 14 | 15 | Follow up: 16 | What if the inputs contain unicode characters? How would you adapt your solution to such case? 17 | ``` 18 | 19 | 解题思路: 20 | 21 | 考虑特殊条件 22 | 23 | 方法一: 24 | 25 | 分别对字符串 s 和字符串 t,排序,然后比较是否相等,如果相等,说明 t 可以颠倒顺序成 s。 26 | 27 | 方法二: 28 | 29 | 1. 字符串 s 和 字符串 t 包含都是小写字母,字符串 t 经过颠倒能够成为字符串 s,说明字符串 s 和字符串 t 的包含的每个单词数是相等的 30 | 2. 用 unordered_map 关联性容器,第一个参数表示单词,第二个参数表示单词在字符串中出现次数 31 | 3. 对字符串 s 遍历,单词出现就累加,对字符串 t 遍历,单词出现就累减 32 | 4. 如果两个字符串的组合单词完全相同,则最后 unordered_map 的第二个属性就等于 0 33 | 34 | ```C++ 35 | class Solution { 36 | public: 37 | bool isAnagram(string s, string t) { 38 | if (s.length() != t.length()) return false; 39 | int count[26] = {0}; 40 | for (int i = 0; i < s.length(); i++) { 41 | count[s[i] - 'a']++; 42 | count[t[i] - 'a']--; 43 | } 44 | 45 | for (int i : count) { 46 | if (i) return false; 47 | } 48 | return true; 49 | } 50 | }; 51 | ``` 52 | -------------------------------------------------------------------------------- /String/Valid Anagram/ValidAnagram.cpp: -------------------------------------------------------------------------------- 1 | // sort 2 | class Solution { 3 | public: 4 | bool isAnagram(string s, string t) { 5 | if (s.empty() && t.empty()) { 6 | return true; 7 | } 8 | 9 | if (s.size() != t.size()) { 10 | return false; 11 | } 12 | 13 | sort(s.begin(), s.end()); 14 | sort(t.begin(), t.end()); 15 | 16 | return s == t; 17 | } 18 | }; 19 | 20 | // 计数 21 | class Solution { 22 | public: 23 | bool isAnagram(string s, string t) { 24 | if (s.empty() && t.empty()) { 25 | return true; 26 | } 27 | 28 | if (s.size() != t.size()) { 29 | return false; 30 | } 31 | 32 | unordered_map count; 33 | 34 | for (int i = 0; i < s.size(); i++) { 35 | count[s[i]]++; 36 | count[t[i]]--; 37 | } 38 | 39 | unordered_map::iterator it; 40 | 41 | for (it = count.begin(); it != count.end(); it++) { 42 | // 第二属性必须等于0,才是 Anagram 43 | if (it->second) { 44 | return false; 45 | } 46 | } 47 | 48 | return true; 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /String/Valid Palindrome/README.md: -------------------------------------------------------------------------------- 1 | ## Valid Palindrome「LeetCode 125」 2 | 3 | 题目:判断字符串是否是有效回文,只考虑字母和数字,忽略大小写。 4 | 5 | ``` 6 | Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases. 7 | 8 | For example, 9 | "A man, a plan, a canal: Panama" is a palindrome. 10 | "race a car" is not a palindrome. 11 | 12 | Note: 13 | Have you consider that the string might be empty? This is a good question to ask during an interview. 14 | 15 | For the purpose of this problem, we define empty string as valid palindrome. 16 | ``` 17 | 18 | 解题思路: 19 | 20 | 1. 由于只用考虑字母和数字,忽略其它字符,比如空格等 21 | 2. 两个碰撞指针,分别指向首尾,遍历整个字符串 22 | 3. 如果遇到非字母数字的字符就跳过,继续往下找,直到找到下一个字母数字或者结束遍历,如果遇到大写字母,就将其转为小写 23 | 4. 等左右指针都找到字母数字时,比较这两个字符,若相等,则继续比较下面两个分别找到的字母数字,若不相等,直接返回false 24 | 25 | ## Valid Palindrome II「LeetCode 680」 26 | 27 | 题目:在允许可以删除一个字符的情况下,判断该字符串是否为回文。 28 | 29 | ```c 30 | Given a non-empty string s, you may delete at most one character. Judge whether you can make it a palindrome. 31 | 32 | Example 1: 33 | Input: "aba" 34 | Output: True 35 | 36 | Example 2: 37 | Input: "abca" 38 | Output: True 39 | 40 | Explanation: You could delete the character 'c'. 41 | Note: 42 | The string will only contain lowercase characters a-z. The maximum length of the string is 50000. 43 | ``` 44 | 45 | 解题思路:递归 46 | 47 | 1. 字符串只包含小写字符 a-z,方法类似 Valid Palindrome 48 | 2. 两个指针分别指向首尾,如果两头的字符不一致,则需要删除前者或者后者,完成删除后判断剩余字符串是否为回文。 49 | -------------------------------------------------------------------------------- /String/Valid Palindrome/ValidPalindrome.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isPalindrome(string s) { 4 | int left = 0, right = s.size() - 1; 5 | 6 | while (left < right) { 7 | if (!isAlphaNum(s[left])) { 8 | left++; 9 | } else if (!isAlphaNum(s[right])) { 10 | right--; 11 | } else if ((s[left] + 32 - 'a') % 32 != (s[right] + 32 - 'a') % 32) { 12 | return false; 13 | } else { 14 | left++; 15 | right--; 16 | } 17 | } 18 | 19 | return true; 20 | } 21 | private: 22 | bool isAlphaNum(char &c) { 23 | return ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || ( c >= '0' && c <= '9' ); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /String/Valid Palindrome/ValidPalindromeII.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool validPalindrome(string s) { 4 | int left = 0, right = s.size() - 1; 5 | 6 | while (left < right) { 7 | if (s[left] != s[right]) { 8 | return isPalindrome(s, left+1, right) || isPalindrome(s, left, right-1); 9 | } 10 | 11 | left++; 12 | right--; 13 | } 14 | 15 | return true; 16 | } 17 | 18 | private: 19 | bool isPalindrome(string& s, int start, int end) { 20 | while (start < end) { 21 | if (s[start++] != s[end--]) { 22 | return false; 23 | } 24 | } 25 | 26 | return true; 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /Tree/B Tree/B-树和B+树的应用.md: -------------------------------------------------------------------------------- 1 | 2 | ## 参考 3 | 4 | * [B-树和B+树的应用:数据搜索和数据库索引](http://blog.csdn.net/hguisu/article/details/7786014) 5 | -------------------------------------------------------------------------------- /Tree/B Tree/README.md: -------------------------------------------------------------------------------- 1 | ## B Tree(Balance Tree) 2 | 3 | B树 就是 B-树,中间的横线并不是减号。 4 | 5 | 如果数据量太多,内存装不下,意味着必须把数据结构放到磁盘上,那么如果减少磁盘 I/O 访问次数,引入 B树 概念。 6 | 7 | B树(B-树) 是一种多路平衡查找树,它的每一个节点最多包含 k 个孩子,k 被称为 B树 的阶。k 的大小取决于磁盘页的大小。 8 | 9 | 一个 m 阶的 B树 具有如下几个特征: 10 | 11 | * 根节点至少有两个孩子 12 | * 每个中间节点都包含 k-1 个元素和 k 个孩子,其中 m/2 <= k <= m 13 | * 每一个叶子节点都包含 k-1 个元素,其中 m/2 <= k <= m 14 | * 所有的叶子节点都位于同一层 15 | * 每个节点中的元素从小到大排列,节点当中 k-1 元素正好是 k 个孩子包含的元素的值域划分 16 | 17 | 磁盘 I/O 访问次数是由树的高度决定。 18 | 19 | 只要树的高度足够低,磁盘 I/O 访问次数足够少,就可以提升查找性能。 20 | 21 | B树 的实际应用:主要应用于文件系统以及部分数据库索引,比如非关系数据库 MongoDB。 22 | 23 | ## B+ Tree 24 | 25 | MySQL 数据库索引就是用 B+ 树结构存储。 26 | 27 | B+ 树是基于 B- 树的一种变体,有着比 B- 树更高的查询性能。 28 | 29 | 一个 m 阶的 B+树 具有如下几个特征: 30 | 31 | * 把 k 个子树的中间节点包含有 k 个元素,每个元素不保存数据,只用来索引,所有数据都保存在叶子节点 32 | * 所有的叶子节点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子节点本身依关键字的大小 自小而大 有序连接 33 | * 所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。 34 | 35 | B+树 每一个父节点的元素都出现在子节点中,是子节点的最大(最小)元素。无论插入删除元素,始终要保持最大元素在根节点当中。 36 | 所有叶子节点包含了全部元素的信息,并且每一个叶子节点都带有指向下一个节点的指针,形成了一个有序链表。 37 | 38 | B+树 还有一个显著的特点,「卫星数据」的位置,只有叶子节点带有卫星数据,其余中间节点仅仅是索引,没有任何数据关联。 39 | 40 | 「卫星数据」指的是索引元素所指向的数据记录。比如数据库中的某一行。在 B树 中,无论中间节点还是叶子节点都带有卫星数据。 41 | 42 | B+树 的好处主要体现在查询性能上。因为其中间节点没有卫星数据,所以同样大小的磁盘页可以容纳更多的节点元素。 43 | 44 | 数据量相同的情况下,B+树 的结构比 B树 更加 “矮胖”,因此查询时 I/O 次数也更少。 45 | 46 | B+树的查询必须最终查找到叶子节点,而 B树 只要找到匹配元素即可,无论匹配元素处于中间点还是叶子节点。 47 | 48 | 因此,B树 的查找性能并不稳定(最好情况是查到根节点,最坏情况是查到叶子节点),而 B+树 的每一次查找都是稳定的。 49 | 50 | B树 的范围查询依靠中序遍历,而 B+树 的范围查询只需要在链表上做遍历即可。 51 | 52 | ## B Tree 与 B+ Tree 对比 53 | 54 | B+树 比 B树 的优势在于: 55 | 56 | * 单一节点存储更多的元素,使得查询 I/O 次数更少 57 | * 所有查询都要查找到叶子节点,查询性能稳定 58 | * 所有叶子节点形成有序链表,便于范围查询 59 | 60 | B树 的好处:虽然查询性能不稳定,但平均的查询速度快一些,不用每次都查找到叶子节点为止。 61 | -------------------------------------------------------------------------------- /Tree/Binary Search Tree/Binary Search Method/Java/BinarySearchMethod.java: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tree/Binary Search Tree/Binary Search Tree/Java/BinarySearchTree.java: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tree/IndexHeap/IndexMaxHeap/Java/IndexMaxHeap.java: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tree/IndexHeap/IndexMinHeap/Java/IndexMinHeap.java: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tree/IndexHeap/README.md: -------------------------------------------------------------------------------- 1 | ## 索引堆「Index Heap」 2 | 3 | 堆本质是树的数据结构,经常用来实现优先队列。最常见的是二叉堆(Binary Heap),由于是完全二叉树,所以可以用数组来高效实现。普通堆两个不足之处: 4 | 5 | * 在构造堆过程中,当元素为复杂的结构,经常性地移动元素是很低效的。 6 | * 在堆的使用过程中,当要改变堆中元素的值,普通堆很难实现。 7 | 8 | 为了解决这些问题,引入索引堆概念。 9 | 10 | 索引堆是堆中存储不是元素,而是元素所在数组中的`索引(下标)`,当堆中的元素发生改变,那么移动的是该元素的下标。 11 | 12 | 索引堆的实现:在普通堆的基础上,开辟一个存放索引的数组,始终保持存放索引的数组为堆。 13 | 14 | 最大索引堆和最小索引堆的实现,区别在于 shiftUp 和 shiftDown 操作。 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Balanced Binary Tree/README.md: -------------------------------------------------------------------------------- 1 | ## Balanced Binary Tree「LeetCode 110」 2 | 3 | 题目:判断一个二叉树是否是平衡二叉树 4 | 5 | ``` 6 | Given a binary tree, determine if it is height-balanced. 7 | 8 | For this problem, a height-balanced binary tree is defined as a binary tree 9 | 10 | in which the depth of the two subtrees of every node never differ by more than 1. 11 | ``` 12 | 13 | 解题思路:递归思想,运用 Maximum Depth of Binary Tree 14 | 15 | 方法一: 16 | 17 | 1. 平衡二叉树的左右子树的高度相差不超过 1 18 | 2. 使用递归实现求各个节点深度的函数 19 | 3. 以根节点为起点,先比较其左右子树的深度差 20 | 4. 继续递归判断节点的左右子树是否平衡 21 | 22 | 方法二:(优化) 23 | 24 | 1. 方法一是求出每个节点深度,现在方法二是发现子树不平衡,则不计算具体的深度,而是直接返回-1 25 | 2. 对于每一个节点,我们通过 checkDepth 方法递归获得左右子树的深度,如果子树是平衡的,则返回真实的深度,若不平衡,直接返回-1 26 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Binary Tree Inorder Traversal/BinaryTreeInorderTraversal.cpp: -------------------------------------------------------------------------------- 1 | // 借助栈实现 2 | /** 3 | * Definition for a binary tree node. 4 | * struct TreeNode { 5 | * int val; 6 | * TreeNode *left; 7 | * TreeNode *right; 8 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 9 | * }; 10 | */ 11 | class Solution { 12 | public: 13 | vector inorderTraversal(TreeNode* root) { 14 | vector res; 15 | stack stack; 16 | 17 | while (root || !stack.empty()) { 18 | while (root) { 19 | stack.push(root); 20 | 21 | root = root->left; 22 | } 23 | 24 | root = stack.top(); 25 | stack.pop(); 26 | 27 | res.push_back(root->val); 28 | root = root->right; 29 | } 30 | 31 | return res; 32 | } 33 | 34 | }; 35 | 36 | class Solution { 37 | public: 38 | vector inorderTraversal(TreeNode* root) { 39 | vector res; 40 | 41 | if (!root) { 42 | return vector(); 43 | } 44 | 45 | __inorderTraversal(root, res); 46 | 47 | return res; 48 | } 49 | 50 | private: 51 | void __inorderTraversal(TreeNode* root, vector &res) { 52 | if (root) { 53 | __inorderTraversal(root->left, res); 54 | res.push_back(root->val); 55 | __inorderTraversal(root->right, res); 56 | } 57 | } 58 | }; 59 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Binary Tree Inorder Traversal/README.md: -------------------------------------------------------------------------------- 1 | ## Binary Tree Inorder Traversal「LeetCode 94」 2 | 3 | 题目:二叉树的中序遍历 4 | 5 | ``` 6 | Given a binary tree, return the inorder traversal of its nodes' values. 7 | 8 | For example: 9 | Given binary tree [1,null,2,3], 10 | 1 11 | \ 12 | 2 13 | / 14 | 3 15 | return [1,3,2]. 16 | 17 | Note: Recursive solution is trivial, could you do it iteratively? 18 | ``` 19 | 20 | 解题思路: 21 | 22 | 递归思想: 23 | 24 | 算法的时间复杂度是 O(n), 而空间复杂度则是递归栈的大小,即O(logn)。 25 | 26 | 1. 比较简单,先访问左边,再访问根节点,最后访问右边节点。 27 | 28 | 非递归思想 29 | 30 | 使用栈来实现迭代。 31 | 32 | 1. 从根节点开始,先将根节点压入栈,然后再将其所有左子结点压入栈,直到左子树节点为空 33 | 2. 然后取出栈顶节点,保存节点值,再将当前指针移到其右子节点上,若存在右子节点,则在下次循环时又可将其所有左子结点压入栈中。 34 | 35 | 这样就保证了访问顺序为 左-根-右。 36 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Binary Tree Level Order Traversal/BinaryTreeLevelOrderTraversal.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | vector > levelOrder(TreeNode *root) { 13 | vector> res; 14 | 15 | if (!root) { 16 | return res; 17 | } 18 | 19 | queue q; 20 | 21 | q.push(root); 22 | 23 | while (!q.empty()) { 24 | vector levelRes; 25 | 26 | int n = q.size(); 27 | 28 | for (int i = 0; i < n; i++) { 29 | TreeNode *node = q.front(); 30 | 31 | q.pop(); 32 | 33 | levelRes.push_back(node->val); 34 | 35 | if (node->left) { 36 | q.push(node->left); 37 | } 38 | 39 | if (node->right) { 40 | q.push(node->right); 41 | } 42 | } 43 | 44 | res.push_back(levelRes); 45 | } 46 | 47 | return res; 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Binary Tree Level Order Traversal/README.md: -------------------------------------------------------------------------------- 1 | ## Binary Tree Level Order Traversal「LeetCode 102」 2 | 3 | 题目: 二叉树层序遍历 4 | 5 | ``` 6 | Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level). 7 | 8 | For example: 9 | Given binary tree {3,9,20,#,#,15,7}, 10 | 11 | 3 12 | / \ 13 | 9 20 14 | / \ 15 | 15 7 16 | 17 | 18 | return its level order traversal as: 19 | 20 | [ 21 | [3], 22 | [9,20], 23 | [15,7] 24 | ] 25 | ``` 26 | 27 | 解题思路: 28 | 29 | 1. 二叉树的层序遍历是典型的 BFS 应用,建立一个队列 queue 30 | 2. 先把根节点放入到队列中,while 循环判断队列是否为空,不为空,先从队列中取出根节点,然后判断根节点是否有左右子节点 31 | 3. 如果有左右子节点,分别入队列;每次从队列中取出一个节点,看该节点是否有左右子节点,有入队列 32 | 4. 此题涉及到二维向量存储,每次 for 遍历当前队列,存储到一维向量,遍历完后,把一维向量存储到二维向量中 33 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Binary Tree Postorder Traversal/README.md: -------------------------------------------------------------------------------- 1 | ## Binary Tree Postorder Traversal「LeetCode 145」 2 | 3 | 题目:二叉树的后序遍历 4 | 5 | ``` 6 | Given a binary tree, return the postorder traversal of its nodes' values. 7 | 8 | For example: 9 | Given binary tree {1,#,2,3}, 10 | 1 11 | \ 12 | 2 13 | / 14 | 3 15 | return [3,2,1]. 16 | 17 | Note: Recursive solution is trivial, could you do it iteratively? 18 | ``` 19 | 20 | 解题思路: 21 | 22 | 递归思想 23 | 24 | 1. 先访问左子树节点,再访问右子树节点,后访问根节点。 25 | 26 | 迭代思想 27 | 28 | 使用栈实现迭代。 29 | 30 | 1. 根节点先入栈,当栈顶节点的左右子节点都没有,就把栈顶节点存储到向量中 31 | 2. 如果有左右子节点,先入右节点,再入左节点 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Binary Tree Preorder Traversal/BinaryTreePreorderTraversal.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | vector preorderTraversal(TreeNode* root) { 13 | vector res; 14 | 15 | __preorderTraversal(root, res); 16 | 17 | return res; 18 | } 19 | 20 | private: 21 | void __preorderTraversal(TreeNode* root, vector &res) { 22 | if (root) { 23 | res.push_back(root->val); 24 | 25 | __preorderTraversal(root->left, res); 26 | __preorderTraversal(root->right, res); 27 | } 28 | } 29 | }; 30 | 31 | // 迭代,借助栈 32 | class Solution { 33 | public: 34 | vector preorderTraversal(TreeNode* root) { 35 | TreeNode* temp = root; 36 | vector res; 37 | stack st; 38 | 39 | if (!temp) { 40 | return vector(); 41 | } 42 | 43 | while (temp || !st.empty()) { 44 | if (temp) { 45 | st.push(temp); 46 | res.push_back(temp->val); 47 | temp = temp->left; 48 | } else { 49 | temp = st.top(); 50 | st.pop(); 51 | temp = temp->right; 52 | } 53 | } 54 | 55 | return res; 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Binary Tree Preorder Traversal/README.md: -------------------------------------------------------------------------------- 1 | ## Binary Tree Preorder Traversal「LeetCode 144」 2 | 3 | 题目:二叉树的前序遍历 4 | 5 | ``` 6 | Given a binary tree, return the preorder traversal of its nodes' values. 7 | 8 | For example: 9 | Given binary tree {1,#,2,3}, 10 | 1 11 | \ 12 | 2 13 | / 14 | 3 15 | return [1,2,3]. 16 | 17 | Note: Recursive solution is trivial, could you do it iteratively? 18 | ``` 19 | 20 | 解题思路: 21 | 22 | 两种实现方式,递归和借助栈。 23 | 24 | 解法一:递归思想 25 | 26 | 1. 先访问根节点,再分别递归访问左子树,访问右子树。 27 | 28 | 解法二:迭代,借助栈 29 | 30 | 利用栈模拟递归实现。 31 | 32 | 1. 根节点先入栈,存储到向量 vector 33 | 2. 判断栈是否为空,不为空,判断入栈的节点是否有左子节点,如果有,入栈,存储到向量 34 | 3. 如果没有左子节点,说明根节点的左子树的左节点都入栈或判断完 35 | 4. 没有左子节点,出栈,判断出栈的节点是否有右子节点,有,把右子节点入栈和存储向量 36 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Convert Sorted Array to Binary Search Tree/ConvertSortedArrayToBinarySearchTree.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | TreeNode* sortedArrayToBST(vector& nums) { 13 | if (nums.empty()) { 14 | return NULL; 15 | } 16 | 17 | int left = 0, right = nums.size() - 1; 18 | 19 | return sortedArrayToBST(nums, left, right); 20 | } 21 | 22 | private: 23 | TreeNode* sortedArrayToBST(vector& nums, int left, int right) { 24 | TreeNode *res = NULL; 25 | 26 | if (left == right) { 27 | return new TreeNode(nums[left]); 28 | } else if (left < right) { 29 | int mid = left + (right - left) / 2; 30 | 31 | res = new TreeNode(nums[mid]); 32 | 33 | res->left = sortedArrayToBST(nums, left, mid - 1); 34 | res->right = sortedArrayToBST(nums, mid + 1, right); 35 | } else { 36 | return NULL; 37 | } 38 | 39 | return res; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Convert Sorted Array to Binary Search Tree/README.md: -------------------------------------------------------------------------------- 1 | ## Convert Sorted Array to Binary Search Tree「LeetCode 108」 2 | 3 | 题目:把一个排序的数组转换成二叉搜索树 4 | 5 | ``` 6 | Given an array where elements are sorted in ascending order, convert it to a height balanced BST. 7 | ``` 8 | 9 | 解题思路: 10 | 11 | 1. 二叉搜索树的特点是,根节点的值大于左子树节点的值,小于右子树节点的值 12 | 2. 由于有序的数组是从小到大存储,那么中间的元素作为二叉树的根 13 | 3. 从中间分开,分成左右两个有序数组,在分别找出其中间点作为原中间点的左右两个子节点 14 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Invert Binary Tree/InvertBinaryTree.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | TreeNode* invertTree(TreeNode* root) { 13 | if(root == NULL) 14 | { 15 | return NULL; 16 | } 17 | TreeNode* tmpNode = root->left; 18 | root->left = invertTree(root->right); 19 | root->right = invertTree(tmpNode); 20 | return root; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Invert Binary Tree/README.md: -------------------------------------------------------------------------------- 1 | ## Invert Binary Tree「LeetCode 226」 2 | 3 | 题目:二叉树的反转 4 | 5 | ``` 6 | Invert a binary tree. 7 | 8 | 4 9 | / \ 10 | 2 7 11 | / \ / \ 12 | 1 3 6 9 13 | 14 | to 15 | 16 | 4 17 | / \ 18 | 7 2 19 | / \ / \ 20 | 9 6 3 1 21 | ``` 22 | 23 | 解题思路:递归思想 24 | 25 | 1. 遍历二叉树的每个节点,然后将每个节点的左右孩子对调 26 | 2. 从根节点开始,对其左子树和右子树对调 27 | 3. 左子树和右子树递归 28 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Longest Univalue Path/LongestUnivaluePath.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | int longestUnivaluePath(TreeNode* root) { 13 | if (!root) { 14 | return 0; 15 | } 16 | 17 | int res = 0; 18 | 19 | dfs(root, res); 20 | 21 | return res; 22 | } 23 | 24 | private: 25 | int dfs(TreeNode* root, int& res) { 26 | if (!root) { 27 | return 0; 28 | } 29 | 30 | int left = dfs(root->left, res); 31 | int right = dfs(root->right, res); 32 | 33 | int arrowLeft = 0, arrowRight = 0; 34 | 35 | if (root->left && root->left->val == root->val) { 36 | arrowLeft = 1 + left; 37 | } 38 | 39 | if (root->right && root->right->val == root->val) { 40 | arrowRight = 1 + right; 41 | } 42 | 43 | res = max(res, arrowLeft + arrowRight); 44 | 45 | return max(arrowLeft, arrowRight); 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Longest Univalue Path/README.md: -------------------------------------------------------------------------------- 1 | ## Longest Univalue Path「LeetCode 687」 2 | 3 | 题目:求出最长路径的长度,最长路径中的每个节点都相等,最长路径不一定从根节点通过。两个节点之间的路径长度由它们之间的边数表示。 4 | 5 | ``` 6 | Given a binary tree, find the length of the longest path where each node in the path has the same value. 7 | 8 | This path may or may not pass through the root. 9 | 10 | Note: The length of path between two nodes is represented by the number of edges between them. 11 | 12 | Example 1: 13 | 14 | Input: 15 | 16 | 5 17 | / \ 18 | 4 5 19 | / \ \ 20 | 1 1 5 21 | Output: 22 | 23 | 2 24 | Example 2: 25 | 26 | Input: 27 | 28 | 1 29 | / \ 30 | 4 5 31 | / \ \ 32 | 4 4 5 33 | Output: 34 | 35 | 2 36 | Note: The given binary tree has not more than 10000 nodes. The height of the tree is not more than 1000. 37 | ``` 38 | 39 | 解题思路:递归思想 40 | 41 | 1. 对于根节点,先递归分别求出左右子树的最长路径长度 42 | 2. 如果根节点的值等于左子树节点的值或等于右子树节点的值,就在基础上加 1 43 | 3. 递归函数返回左右子树的最长路径长度 44 | 4. 特别注意,最长路径之和 45 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Maximum Depth of Binary Tree/README.md: -------------------------------------------------------------------------------- 1 | ## Maximum Depth of Binary Tree「LeetCode 104」 2 | 3 | 题目:求二叉树的最长深度。 4 | 5 | ``` 6 | Given a binary tree, find its maximum depth. 7 | 8 | The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. 9 | ``` 10 | 11 | 解题思路: 12 | 13 | 方法一:递归思想 14 | 15 | 1. 从根节点开始,对其左子树的最长深度和右子树的最长深度进行比较,求出最长深度,然后加上根节点那层 16 | 2. 如何求出左子树的最长深度和右子树的最长深度,又进行递归 17 | 18 | 方法二:非递归思想,层序遍历二叉树(BFS),然后计数总层数,借助 queue 19 | 20 | 1. 首选根节点入队列,判断当前队列是否为空 21 | 2. 不为空,那么层数加 1,循环操作,把队列的节点(一层上的节点)都出列,如果出列的节点有左右节点,就入队列 22 | 3. 每次判断当前队列是否为空,不为空就把层数加1 23 | 24 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Merge Two Binary Trees/MergeTwoBinaryTrees.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) { 13 | if (!t1 && !t2) { 14 | return NULL; 15 | } 16 | 17 | if (!t1) { 18 | return t2; 19 | } 20 | 21 | if (!t2) { 22 | return t1; 23 | } 24 | 25 | // 两个二叉树节点的值相加 26 | TreeNode* t = new TreeNode(t1->val + t2->val); 27 | t->left = mergeTrees(t1->left, t2->left); 28 | t->right = mergeTrees(t1->right, t2->right); 29 | 30 | return t; 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Merge Two Binary Trees/README.md: -------------------------------------------------------------------------------- 1 | ## Merge Two Binary Trees「LeetCode 617」 2 | 3 | 题目:合并两个二叉树,都存在的结点,就将结点值加起来,否则空的位置就由另一个树的结点来代替。 4 | 5 | ``` 6 | Given two binary trees and imagine that when you put one of them to cover the other, 7 | 8 | some nodes of the two trees are overlapped while the others are not. 9 | 10 | You need to merge them into a new binary tree. The merge rule is that if two nodes overlap, 11 | 12 | then sum node values up as the new value of the merged node. Otherwise, 13 | 14 | the NOT null node will be used as the node of new tree. 15 | 16 | Example 1: 17 | Input: 18 | Tree 1 Tree 2 19 | 1 2 20 | / \ / \ 21 | 3 2 1 3 22 | / \ \ 23 | 5 4 7 24 | Output: 25 | Merged tree: 26 | 3 27 | / \ 28 | 4 5 29 | / \ \ 30 | 5 4 7 31 | Note: The merging process must start from the root nodes of both trees. 32 | ``` 33 | 34 | 解题思路:递归思想 35 | 36 | 1. 两个二叉树,如果两个二叉树,都有节点,就相加,如果一边没有,另一边有,就用有的代替 37 | 2. 如果 t1 不存在,则直接返回 t2,反之,如果 t2 不存在,则直接返回 t1 38 | 3. 如果上面两种情况都不满足,那么以 t1 和 t2 的结点值之和建立新结点 t 39 | 4. 然后对 t1 和 t2 的左子结点调用递归并赋给t的左子结点,再对 t1 和 t2 的右子结点调用递归并赋给 t 的右子结点,返回t结点即可 40 | 41 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Minimum Depth of Binary Tree/MinimumDepthOfBinaryTree.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | int minDepth(TreeNode* root) { 13 | if (!root) { 14 | return 0; 15 | } 16 | 17 | if (!root->left && !root->right) { 18 | return 1; 19 | } 20 | 21 | if (!root->left) { 22 | return minDepth(root->right) + 1; 23 | } else if (!root->right) { 24 | return minDepth(root->left) + 1; 25 | } else { 26 | return min(minDepth(root->left), minDepth(root->right)) + 1; 27 | } 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Minimum Depth of Binary Tree/README.md: -------------------------------------------------------------------------------- 1 | ## Minimum Depth of Binary Tree「LeetCode 111」 2 | 3 | 题目:求二叉树的最小深度。 4 | 5 | ``` 6 | Given a binary tree, find its minimum depth. 7 | 8 | The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node. 9 | ``` 10 | 11 | 解题思路:递归思想 12 | 13 | 1. 与 Maximum Depth of Binary Tree 类似 14 | 2. 从根节点开始,当左子树为 NULL,需要求解右子树的最小深度 15 | 3. 当右子树为 NULL,需要求解左子树的最小深度 16 | 4. 当都不为 NULL,比较左子树和右子树的最小深度,求出最小深度后加 1 17 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Path Sum/PathSum.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | bool hasPathSum(TreeNode* root, int sum) { 13 | if (!root) { 14 | return false; 15 | } 16 | 17 | // 递归的终止条件 18 | if (!root->left && !root->right && root->val == sum) { 19 | return true; 20 | } 21 | 22 | return hasPathSum(root->left, sum - root->val) || hasPathSum(root->right, sum - root->val); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Path Sum/PathSumII.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | vector> pathSum(TreeNode* root, int sum) { 13 | vector> ret; 14 | 15 | if (!root) { 16 | return ret; 17 | } 18 | 19 | vector temp; 20 | 21 | dfs(root, sum, temp, ret); 22 | 23 | return ret; 24 | } 25 | 26 | private: 27 | void dfs(TreeNode* root, int sum, vector& temp, vector>& ret) { 28 | if (!root) { 29 | return; 30 | } 31 | 32 | // 节点入一维 vector 33 | temp.push_back(root->val); 34 | 35 | // 递归终止条件 36 | if (sum == root->val && !root->left && !root->right) { 37 | ret.push_back(temp); 38 | } 39 | 40 | dfs(root->left, sum - root->val, temp, ret); 41 | dfs(root->right, sum - root->val, temp, ret); 42 | 43 | // 不属于路径和,删除,返回上一个节点 44 | temp.pop_back(); 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Path Sum/PathSumIII.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | int pathSum(TreeNode* root, int sum) { 13 | int res = 0; 14 | vector out; 15 | 16 | dfs(root, sum, 0, out, res); 17 | 18 | return res; 19 | } 20 | 21 | private: 22 | void dfs(TreeNode* root, int sum, int curSum, vector& out, int& res) { 23 | if (!root) { 24 | return; 25 | } 26 | 27 | curSum += root->val; 28 | 29 | out.push_back(root); 30 | 31 | if (curSum == sum) { 32 | ++res; 33 | } 34 | 35 | int t = curSum; 36 | 37 | for (int i = 0; i < out.size() - 1; i++) { 38 | t -= out[i]->val; 39 | 40 | if (t == sum) { 41 | ++res; 42 | } 43 | } 44 | 45 | dfs(root->left, sum, curSum, out, res); 46 | dfs(root->right, sum, curSum, out, res); 47 | 48 | out.pop_back(); 49 | } 50 | 51 | }; 52 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Same Tree/README.md: -------------------------------------------------------------------------------- 1 | ## Same Tree「LeetCode 100」 2 | 3 | 题目:判断两个二叉树是否相同,其结构和每个节点的值都相同。 4 | 5 | ``` 6 | Given two binary trees, write a function to check if they are equal or not. 7 | 8 | Two binary trees are considered equal if they are structurally identical and the nodes have the same value. 9 | ``` 10 | 11 | ```cpp 12 | /** 13 | * Definition for a binary tree node. 14 | * struct TreeNode { 15 | * int val; 16 | * TreeNode *left; 17 | * TreeNode *right; 18 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 19 | * }; 20 | */ 21 | ``` 22 | 23 | 解题思路:递归思想 24 | 25 | 1. 根节点相等 26 | 2. 左子树相等 27 | 3. 右子树相等 28 | -------------------------------------------------------------------------------- /Tree/LeetCode-Tree/Same Tree/SameTree.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | bool isSameTree(TreeNode* p, TreeNode* q) { 13 | if (!p && !q) { 14 | return true; 15 | } 16 | 17 | if (!p || !q) { 18 | return false; 19 | } 20 | 21 | return (p->val == q->val) && isSameTree(p->left, q->left) && isSameTree(p->right, q->right); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /Tree/README.md: -------------------------------------------------------------------------------- 1 | ## 基本的数据结构——树 2 | 3 | 树的大部分操作的运行时间都是 O(logN)。 4 | 5 | * [IndexHeap](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Tree/IndexHeap) 6 | * [Binary Search Tree](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Tree/Binary%20Search%20Tree) 7 | * [RB-tree](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Tree/RB-tree) 8 | * [AVL Tree](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Tree/AVL%20Tree) 9 | * [B Tree](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Tree/B%20Tree) 10 | 11 | ## [LeetCode Tree](https://github.com/steveLauwh/Data-Structures-And-Algorithms/tree/master/Tree/LeetCode-Tree) 12 | 13 | -------------------------------------------------------------------------------- /Tree/image/Binary Search Method.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveLauwh/Algorithms/e8ce0c5cc2a54fbe9700ed8c02acf0f758243eaa/Tree/image/Binary Search Method.PNG -------------------------------------------------------------------------------- /image/Linked List(I).PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveLauwh/Algorithms/e8ce0c5cc2a54fbe9700ed8c02acf0f758243eaa/image/Linked List(I).PNG -------------------------------------------------------------------------------- /image/Linked List(II).PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveLauwh/Algorithms/e8ce0c5cc2a54fbe9700ed8c02acf0f758243eaa/image/Linked List(II).PNG -------------------------------------------------------------------------------- /image/Linked List(III).PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveLauwh/Algorithms/e8ce0c5cc2a54fbe9700ed8c02acf0f758243eaa/image/Linked List(III).PNG -------------------------------------------------------------------------------- /sfo/1. 2D array search.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序, 5 | 每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 6 | ``` 7 | 8 | ```cpp 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | class Solution { 15 | public: 16 | bool Find(int target, vector > array) { 17 | if (array.empty() || array.size() == 0) { 18 | return false; 19 | } 20 | 21 | for (int i = 0; i < array.size(); i++) { 22 | int begin = 0; 23 | int end = array[i].size() - 1; 24 | 25 | while (begin <= end) 26 | { 27 | int mid = (begin + end) / 2; 28 | 29 | if (target > array[i][mid]) { 30 | begin = mid + 1; 31 | } else if (target < array[i][mid]) { 32 | end = mid - 1; 33 | } else { 34 | return true; 35 | } 36 | } 37 | } 38 | 39 | return false; 40 | } 41 | }; 42 | 43 | int main() 44 | { 45 | vector > v; 46 | 47 | vector B; 48 | 49 | B.push_back(0); 50 | B.push_back(1); 51 | B.push_back(2); 52 | B.push_back(3); 53 | v.push_back(B); 54 | 55 | B.clear(); 56 | 57 | B.push_back(4); 58 | B.push_back(5); 59 | B.push_back(6); 60 | B.push_back(7); 61 | v.push_back(B); 62 | 63 | Solution s; 64 | 65 | if (s.Find(5, v) == true) { 66 | cout << "find success!" << endl; 67 | } else { 68 | cout << "find failed!" << endl; 69 | } 70 | } 71 | ``` 72 | -------------------------------------------------------------------------------- /sfo/10. number of 1.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。 5 | ``` 6 | 7 | ```cpp 8 | #include 9 | using namespace std; 10 | 11 | class Solution { 12 | public: 13 | int NumberOf1(int n) { 14 | int count = 0; 15 | int flag = 1; 16 | 17 | while (flag != 0) { 18 | if ((n & flag) != 0) { 19 | count++; 20 | } 21 | 22 | flag = flag << 1; 23 | } 24 | 25 | return count; 26 | } 27 | }; 28 | 29 | int main(int argc, char const *argv[]) 30 | { 31 | Solution s; 32 | cout << s.NumberOf1(15) << endl; 33 | 34 | return 0; 35 | } 36 | 37 | 38 | ``` 39 | -------------------------------------------------------------------------------- /sfo/11. find kth to tail.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 输入一个链表,输出该链表中倒数第k个结点。 5 | ``` 6 | 7 | ```cpp 8 | #include 9 | using namespace std; 10 | 11 | struct ListNode { 12 | int val; 13 | struct ListNode *next; 14 | ListNode(int x) : val(x), next(NULL) {} 15 | }; 16 | 17 | class Solution { 18 | public: 19 | ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) { 20 | if (pListHead == NULL || k == 0) { 21 | return NULL; 22 | } 23 | 24 | ListNode *fast = pListHead; 25 | ListNode *slow = pListHead; 26 | 27 | int i = 0; 28 | 29 | while (fast != NULL) { 30 | if (i < k) { 31 | fast = fast->next; 32 | i++; 33 | } else { 34 | fast = fast->next; 35 | slow = slow->next; 36 | } 37 | } 38 | 39 | if (i < k) { 40 | return NULL; 41 | } 42 | 43 | return slow; 44 | } 45 | 46 | void display(ListNode* pListHead) { 47 | ListNode *list; 48 | for (list = pListHead; list != NULL; list = list->next) { 49 | cout << list->val << " "; 50 | } 51 | 52 | cout << endl; 53 | } 54 | }; 55 | 56 | int main(int argc, char *argv[]) 57 | { 58 | ListNode *head = new ListNode(0); 59 | ListNode *p; 60 | p = head; 61 | 62 | for (int i = 1; i < 10; i++) { 63 | ListNode *temp = new ListNode(i); 64 | p->next = temp; 65 | p = temp; 66 | } 67 | 68 | Solution s; 69 | s.display(head); 70 | 71 | cout << s.FindKthToTail(head, 5)->val << endl; 72 | 73 | return 0; 74 | } 75 | ``` 76 | -------------------------------------------------------------------------------- /sfo/12. reverse list.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 输入一个链表,反转链表后,输出新链表的表头。 5 | ``` 6 | 7 | ```cpp 8 | #include 9 | using namespace std; 10 | 11 | struct ListNode { 12 | int val; 13 | struct ListNode *next; 14 | ListNode(int x) : val(x), next(NULL) {} 15 | }; 16 | 17 | class Solution { 18 | public: 19 | ListNode* ReverseList(ListNode* pHead) { 20 | if (pHead == NULL) { 21 | return NULL; 22 | } 23 | 24 | ListNode *reverseHead = NULL; 25 | ListNode *prevNode = NULL; 26 | ListNode *currentNode = pHead; 27 | 28 | while (currentNode != NULL) { 29 | ListNode *nextNode = currentNode->next; 30 | 31 | if (nextNode == NULL) { 32 | reverseHead = currentNode; 33 | } 34 | 35 | currentNode->next = prevNode; 36 | prevNode = currentNode; 37 | currentNode = nextNode; 38 | } 39 | 40 | return reverseHead; 41 | } 42 | }; 43 | 44 | int main(int argc, char *argv[]) 45 | { 46 | ListNode *node1 = new ListNode(1); 47 | ListNode *node2 = new ListNode(3); 48 | ListNode *node3 = new ListNode(5); 49 | ListNode *node4 = new ListNode(7); 50 | ListNode *node5 = new ListNode(9); 51 | 52 | node1->next = node2; 53 | node2->next = node3; 54 | node3->next = node4; 55 | node4->next = node5; 56 | 57 | Solution s; 58 | 59 | ListNode *newNode = s.ReverseList(node1); 60 | 61 | for (; newNode != NULL; ) { 62 | cout << newNode->val << " "; 63 | newNode = newNode->next; 64 | } 65 | 66 | cout << endl; 67 | 68 | return 0; 69 | } 70 | ``` 71 | -------------------------------------------------------------------------------- /sfo/13. rect cover.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 5 | 6 | 比如n=3时,2*3的矩形块有3种覆盖方法: 7 | ``` 8 | ![](https://github.com/steveLauwh/Algorithms/raw/master/sfo/13.PNG) 9 | 10 | ```cpp 11 | #include 12 | using namespace std; 13 | 14 | class Solution { 15 | public: 16 | int rectCover(int number) { 17 | if (number < 1) { 18 | return 0; 19 | } else if (number <= 2) { 20 | return number; 21 | } else { 22 | return rectCover(number - 1) + rectCover(number - 2); 23 | } 24 | } 25 | }; 26 | 27 | int main(int argc, char *argv[]) 28 | { 29 | Solution s; 30 | cout << s.rectCover(4) << endl; 31 | 32 | return 0; 33 | } 34 | ``` 35 | -------------------------------------------------------------------------------- /sfo/13.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveLauwh/Algorithms/e8ce0c5cc2a54fbe9700ed8c02acf0f758243eaa/sfo/13.PNG -------------------------------------------------------------------------------- /sfo/14. reorder array.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 输入一个整数数组,实现一个函数来调整该数组中数字的顺序, 5 | 使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。 6 | ``` 7 | 8 | ```cpp 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | class Solution { 15 | public: 16 | void reOrderArray(vector &array) { 17 | vector arr; 18 | 19 | for (int i = 0; i < array.size(); i++) { 20 | if (array[i] % 2 == 1) { 21 | arr.push_back(array[i]); 22 | } 23 | } 24 | 25 | for (int i = 0; i < array.size(); i++) { 26 | if (array[i] % 2 == 0) { 27 | arr.push_back(array[i]); 28 | } 29 | } 30 | 31 | for (int i = 0; i < arr.size(); i++) { 32 | array[i] = arr[i]; 33 | } 34 | } 35 | }; 36 | 37 | int main(int argc, char *argv[]) 38 | { 39 | Solution s; 40 | vector a = {5, 10, 3, 7, 12, 11, 19}; 41 | 42 | s.reOrderArray(a); 43 | 44 | for (int i = 0; i < a.size(); i++) { 45 | cout << a[i] << " "; 46 | } 47 | 48 | cout << endl; 49 | 50 | return 0; 51 | } 52 | ``` 53 | -------------------------------------------------------------------------------- /sfo/15. power.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 5 | 6 | 保证base和exponent不同时为0 7 | ``` 8 | 9 | ```cpp 10 | #include 11 | using namespace std; 12 | 13 | class Solution { 14 | public: 15 | double Power(double base, int exponent) { 16 | if (exponent == 0) { 17 | return 1; 18 | } 19 | 20 | if (exponent == 1) { 21 | return base; 22 | } 23 | 24 | if (exponent > 1) { 25 | double result = Power(base, exponent >> 1); 26 | 27 | result = result * result; 28 | 29 | if ((exponent & 1) == 1) { 30 | result = result * base; 31 | } 32 | 33 | return result; 34 | } 35 | 36 | if (exponent < 0) { 37 | exponent = -exponent; 38 | double result = Power(base, exponent); 39 | 40 | return 1 / result; 41 | } 42 | 43 | return -1; 44 | } 45 | }; 46 | 47 | int main(int argc, char *argv[]) 48 | { 49 | double base = 5.2; 50 | int exponent = 5; 51 | 52 | Solution s; 53 | 54 | cout << s.Power(base, exponent) << endl; 55 | 56 | return 0; 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /sfo/2. replace space.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 请实现一个函数,将一个字符串中的每个空格替换成“%20”。 5 | 例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 6 | ``` 7 | 8 | ```cpp 9 | #include 10 | 11 | using namespace std; 12 | 13 | class Solution { 14 | public: 15 | void replaceSpace(char *str, int length) { 16 | if (str == NULL) { 17 | return; 18 | } 19 | 20 | int blanks = 0; 21 | int original = 0; 22 | int replace = 0; 23 | 24 | for (int i = 0; str[i] != '\0'; i++) { 25 | if (str[i] == ' ') { 26 | blanks++; 27 | } 28 | original++; 29 | } 30 | 31 | replace = original + 2 * blanks; 32 | 33 | if (replace + 1 > length) { 34 | return; 35 | } 36 | 37 | char *p1 = str + original; 38 | char *p2 = str + replace; 39 | 40 | while (p1 != p2) { 41 | if (*p1 != ' ') { 42 | *p2-- = *p1; 43 | } else { 44 | *p2-- = '0'; 45 | *p2-- = '2'; 46 | *p2-- = '%'; 47 | } 48 | p1--; 49 | } 50 | } 51 | }; 52 | 53 | int main(int argc, char *argv[]) 54 | { 55 | char str[] = "We Are Happy."; 56 | 57 | Solution s; 58 | 59 | s.replaceSpace(str, 30); 60 | 61 | cout << "replace space : " << str << endl; 62 | 63 | return 0; 64 | } 65 | ``` 66 | -------------------------------------------------------------------------------- /sfo/20. is pop order.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。 5 | 假设压入栈的所有数字均不相等。 6 | 例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列, 7 | 但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的) 8 | ``` 9 | 10 | ```cpp 11 | #include 12 | using namespace std; 13 | 14 | class Solution { 15 | public: 16 | bool IsPopOrder(vector pushV, vector popV) { 17 | if (pushV.size() == 0) { 18 | return false; 19 | } 20 | 21 | stack st; 22 | 23 | for (int i = 0, j = 0; i < pushV.size(); ) { 24 | st.push(pushV[i++]); 25 | 26 | while (j < popV.size() && st.top() == popV[j]) { 27 | st.pop(); 28 | j++; 29 | } 30 | } 31 | 32 | return st.empty(); 33 | } 34 | }; 35 | 36 | int main(int argc, char *argv[]) 37 | { 38 | vector v1 = {1, 2, 3, 4, 5}; 39 | vector v2 = {4, 5, 3, 2, 1}; 40 | 41 | Solution s; 42 | 43 | if (s.IsPopOrder(v1, v2) == true) { 44 | cout << "Yes!" << endl; 45 | } else { 46 | cout << "No!" << endl; 47 | } 48 | 49 | return 0; 50 | } 51 | 52 | ``` 53 | -------------------------------------------------------------------------------- /sfo/21. min stack.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。 5 | 注意:保证测试中不会当栈为空的时候,对栈调用pop()或者min()或者top()方法。 6 | ``` 7 | 8 | ```cpp 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | class Solution { 14 | public: 15 | void push(int value) { 16 | ordStack.push(value); 17 | 18 | if (minStack.empty()) { 19 | minStack.push(value); 20 | } else if (value <= minStack.top()) { 21 | minStack.push(value); 22 | } 23 | } 24 | 25 | void pop() { 26 | if (ordStack.empty()) { 27 | return; 28 | } 29 | 30 | if (ordStack.top() == minStack.top()) { 31 | minStack.pop(); 32 | } 33 | 34 | ordStack.pop(); 35 | } 36 | 37 | int top() { 38 | return ordStack.top(); 39 | } 40 | 41 | int min() { 42 | return minStack.top(); 43 | } 44 | 45 | private: 46 | stack ordStack; 47 | stack minStack; 48 | }; 49 | 50 | int main(int argc, char *argv[]) 51 | { 52 | Solution s; 53 | 54 | s.push(5); 55 | s.push(2); 56 | s.push(10); 57 | s.push(1); 58 | 59 | cout << s.min() << endl; 60 | 61 | s.pop(); 62 | 63 | cout << s.min() << endl; 64 | 65 | return 0; 66 | } 67 | ``` 68 | -------------------------------------------------------------------------------- /sfo/23. more than half num.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。 5 | 由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。 6 | ``` 7 | 8 | ```cpp 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | class Solution { 15 | public: 16 | int MoreThanHalfNum_Solution(vector numbers) { 17 | int ans = numbers[0]; 18 | 19 | int flag = 1; 20 | 21 | for (int i = 1; i < numbers.size(); i++) { 22 | if (flag > 0) { 23 | if (ans == numbers[i]) { 24 | flag++; 25 | } else { 26 | flag--; 27 | } 28 | } else { 29 | flag = 1; 30 | ans = numbers[i]; 31 | } 32 | } 33 | 34 | int num = 0; 35 | 36 | for (int i = 0; i < numbers.size(); i++) { 37 | if (ans == numbers[i]) { 38 | num++; 39 | } 40 | } 41 | 42 | if (num > (numbers.size()/2)) { 43 | return ans; 44 | } else { 45 | return 0; 46 | } 47 | } 48 | 49 | }; 50 | 51 | int main(int argc, char const *argv[]) 52 | { 53 | vector numbers = {1, 2, 3, 2, 2, 2, 5, 2, 4}; 54 | 55 | Solution s; 56 | 57 | cout << s.MoreThanHalfNum_Solution(numbers) << endl; 58 | 59 | return 0; 60 | } 61 | ``` 62 | -------------------------------------------------------------------------------- /sfo/24. verify squence of BST.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。 5 | 如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。 6 | ``` 7 | 8 | ```cpp 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | class Solution { 14 | public: 15 | bool VerifySquenceOfBST(vector sequence) { 16 | return bst(sequence, 0, sequence.size()-1); 17 | } 18 | 19 | private: 20 | bool bst(vector seq, int begin, int end) { 21 | if (seq.empty() || begin > end) { 22 | return false; 23 | } 24 | 25 | // 划分左右子树,并判断左右子树和根节点的关系 26 | int i = begin; 27 | 28 | for (; i < end; i++) { 29 | if (seq[i] > seq[end]) { 30 | break; 31 | } 32 | } 33 | 34 | int j = i; 35 | 36 | for (; j < end; j++) { 37 | if (seq[j] < seq[end]) { 38 | return false; 39 | } 40 | } 41 | 42 | // 判断左子树是不是二叉搜索树 43 | bool left = true; 44 | if (i > begin) { 45 | left = bst(seq, begin, i-1); 46 | } 47 | 48 | // 判断右子树是不是二叉搜索树 49 | bool right = true; 50 | if (i < end) { 51 | right = bst(seq, i, end-1); 52 | } 53 | 54 | return left && right; 55 | } 56 | }; 57 | 58 | int main(int argc, char const *argv[]) 59 | { 60 | vector seq = {5, 7, 6, 9, 11, 10, 8}; 61 | 62 | Solution s; 63 | 64 | if (s.VerifySquenceOfBST(seq) == 1) { 65 | cout << "True" << endl; 66 | } else { 67 | cout << "False" << endl; 68 | } 69 | 70 | return 0; 71 | } 72 | ``` 73 | -------------------------------------------------------------------------------- /sfo/25. get least numbers.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。 5 | ``` 6 | 7 | ```cpp 8 | #include 9 | #include 10 | #include 11 | #include 12 | using namespace std; 13 | 14 | class Solution { 15 | public: 16 | vector GetLeastNumbers_Solution(vector input, int k) { 17 | vector result; 18 | 19 | int length = input.size(); 20 | 21 | if (length == 0 || length < k || k <= 0) { 22 | return result; 23 | } 24 | 25 | sort(input.begin(), input.end()); 26 | 27 | for (int i = 0; i < k; i++) { 28 | result.push_back(input[i]); 29 | } 30 | 31 | return result; 32 | } 33 | }; 34 | 35 | int main(int argc, char const *argv[]) 36 | { 37 | vector v = {12, 1, 3, 9, 7, 2, 11}; 38 | 39 | Solution s; 40 | 41 | vector result = s.GetLeastNumbers_Solution(v, 5); 42 | 43 | for (int i = 0; i < result.size(); i++) { 44 | cout << result[i] << endl; 45 | } 46 | 47 | return 0; 48 | } 49 | ``` 50 | -------------------------------------------------------------------------------- /sfo/28. tree depth.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 输入一棵二叉树,求该树的深度。 5 | 从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。 6 | ``` 7 | 8 | ```cpp 9 | #include 10 | using namespace std; 11 | 12 | struct TreeNode { 13 | int val; 14 | struct TreeNode *left; 15 | struct TreeNode *right; 16 | TreeNode(int x) : val(x), left(NULL), right(NULL) {} 17 | }; 18 | 19 | class Solution { 20 | public: 21 | int TreeDepth(TreeNode* pRoot) { 22 | if (pRoot == NULL) { 23 | return 0; 24 | } 25 | 26 | int left_length = TreeDepth(pRoot->left); 27 | int right_lenth = TreeDepth(pRoot->right); 28 | 29 | return 1 + max(left_length, right_lenth); 30 | } 31 | }; 32 | 33 | int main(int argc, char const *argv[]) 34 | { 35 | TreeNode *head = new TreeNode(2); 36 | TreeNode *node1 = new TreeNode(3); 37 | TreeNode *node2 = new TreeNode(4); 38 | TreeNode *node3 = new TreeNode(5); 39 | TreeNode *node4 = new TreeNode(6); 40 | TreeNode *node5 = new TreeNode(7); 41 | TreeNode *node6 = new TreeNode(8); 42 | TreeNode *node7 = new TreeNode(9); 43 | 44 | head->left = node1; 45 | head->right = node2; 46 | 47 | node1->left = node3; 48 | node1->right = node4; 49 | 50 | node2->left = node5; 51 | node2->right = node6; 52 | 53 | node5->right = node7; 54 | 55 | Solution s; 56 | 57 | cout << s.TreeDepth(head) << endl; 58 | 59 | return 0; 60 | } 61 | ``` 62 | -------------------------------------------------------------------------------- /sfo/29. first not repeating char.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 5 | 如果没有则返回 -1(需要区分大小写). 6 | ``` 7 | 8 | ```cpp 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | class Solution { 16 | public: 17 | int FirstNotRepeatingChar(string str) { 18 | if (str.size() == 0) { 19 | return -1; 20 | } 21 | 22 | unordered_map countMap; 23 | 24 | for (int i = 0; i < str.size(); i++) { 25 | if (countMap.find(str[i]) == countMap.end()) { 26 | countMap[str[i]] = 1; 27 | } else { 28 | countMap[str[i]]++; 29 | } 30 | } 31 | 32 | int pos = -1; 33 | 34 | for (int i = 0; i < str.size(); i++) { 35 | if (countMap[str[i]] == 1) { 36 | pos = i; 37 | break; 38 | } 39 | } 40 | 41 | return pos; 42 | } 43 | }; 44 | 45 | int main(int argc, char const *argv[]) 46 | { 47 | Solution s; 48 | 49 | string str1 = "ABACCDEFF"; 50 | string str2 = "cbachbd"; 51 | 52 | int res1 = s.FirstNotRepeatingChar(str1); 53 | int res2 = s.FirstNotRepeatingChar(str2); 54 | 55 | cout << res1 << endl; 56 | cout << res2 << endl; 57 | 58 | return 0; 59 | } 60 | ``` 61 | -------------------------------------------------------------------------------- /sfo/3. print list from tail to head.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 输入一个链表,按链表从尾到头的顺序返回一个ArrayList。 5 | ``` 6 | 7 | ```cpp 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | struct ListNode { 15 | int val; 16 | struct ListNode *next; 17 | ListNode(int x) : val(x), next(NULL) { 18 | } 19 | }; 20 | 21 | // use stack 22 | class Solution { 23 | public: 24 | vector printListFromTailToHead(ListNode* head) { 25 | stack s; 26 | vector v; 27 | 28 | ListNode *pNode = head; 29 | while (pNode != NULL) { 30 | s.push(pNode); 31 | pNode = pNode->next; 32 | } 33 | 34 | while (!s.empty()) { 35 | pNode = s.top(); 36 | s.pop(); 37 | v.push_back(pNode->val); 38 | } 39 | 40 | return v; 41 | } 42 | }; 43 | 44 | int main(int argc, char *argv[]) 45 | { 46 | Solution s; 47 | ListNode *pHead = new ListNode(0); 48 | ListNode *pNew, *pTemp; 49 | 50 | pTemp = pHead; 51 | for (int i = 1; i < 5; i++) { 52 | pNew = new ListNode(i); 53 | pTemp->next = pNew; 54 | pTemp = pNew; 55 | } 56 | 57 | vector obj = s.printListFromTailToHead(pHead); 58 | vector::iterator it; 59 | 60 | for (it = obj.begin(); it != obj.end(); it++) { 61 | cout << *it << " "; 62 | } 63 | 64 | cout << endl; 65 | 66 | return 0; 67 | } 68 | ``` 69 | -------------------------------------------------------------------------------- /sfo/30. permutation.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc, 5 | 则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 6 | 7 | 输入描述: 8 | 输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。 9 | ``` 10 | 11 | ```cpp 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | using namespace std; 18 | 19 | class Solution { 20 | public: 21 | vector Permutation(string str) { 22 | if (str.size() == 0) { 23 | return {}; 24 | } 25 | 26 | Permu(str, 0, vec); 27 | 28 | sort(vec.begin(), vec.end()); 29 | 30 | return vec; 31 | } 32 | 33 | void Permu(string str, int begin, vector &v) { 34 | if (begin == str.size()-1) { 35 | v.push_back(str); 36 | return; 37 | } 38 | 39 | for (int i = begin; i < str.size(); i++) { 40 | if (i != begin && str[i] == str[begin]) { 41 | continue; 42 | } 43 | 44 | swap(str[i], str[begin]); 45 | 46 | Permu(str, begin+1, v); 47 | 48 | swap(str[i], str[begin]); 49 | } 50 | } 51 | 52 | private: 53 | vector vec; 54 | }; 55 | 56 | int main(int argc, char const *argv[]) 57 | { 58 | Solution s; 59 | 60 | string str = "abc"; 61 | 62 | vector vec = s.Permutation(str); 63 | 64 | for (int i = 0; i < vec.size(); i++) { 65 | cout << vec[i] << endl; 66 | } 67 | 68 | return 0; 69 | } 70 | ``` 71 | -------------------------------------------------------------------------------- /sfo/31. sum.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。 5 | ``` 6 | 7 | ```cpp 8 | #include 9 | using namespace std; 10 | 11 | class Solution { 12 | public: 13 | int Sum_Solution(int n) { 14 | int sum = n; 15 | 16 | (n > 0) && (sum += Sum_Solution(n-1)); 17 | 18 | return sum; 19 | } 20 | }; 21 | 22 | int main(int argc, char *argv[]) 23 | { 24 | Solution s; 25 | 26 | cout << s.Sum_Solution(100) << endl; 27 | 28 | return 0; 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /sfo/32. duplicate.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的, 5 | 但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 6 | 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。 7 | ``` 8 | 9 | ```cpp 10 | #include 11 | #include 12 | using namespace std; 13 | 14 | class Solution { 15 | public: 16 | // Parameters: 17 | // numbers: an array of integers 18 | // length: the length of array numbers 19 | // duplication: (Output) the duplicated number in the array number 20 | // Return value: true if the input is valid, and there are some duplications in the array number 21 | // otherwise false 22 | bool duplicate(int numbers[], int length, int* duplication) { 23 | vector vec; 24 | 25 | vec.resize(length); 26 | 27 | for (int i = 0; i < length; i++) { 28 | vec[numbers[i]]++; 29 | } 30 | 31 | for (int i = 0; i < length; i++) { 32 | if (1 != vec[numbers[i]]) { 33 | *duplication = numbers[i]; 34 | return true; 35 | } 36 | } 37 | 38 | return false; 39 | } 40 | }; 41 | 42 | int main(int argc, char *argv[]) 43 | { 44 | Solution s; 45 | 46 | int duplication = -1; 47 | 48 | int numbers[] = {2, 3, 1, 0, 2, 5, 3}; 49 | 50 | if (s.duplicate(numbers, 7, &duplication) == 1) { 51 | cout << duplication << endl; 52 | cout << "True" << endl; 53 | } else { 54 | cout << "False" << endl; 55 | } 56 | 57 | return 0; 58 | } 59 | ``` 60 | -------------------------------------------------------------------------------- /sfo/34. get number of k.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 统计一个数字在排序数组中出现的次数。 5 | ``` 6 | 7 | ```cpp 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | class Solution { 14 | public: 15 | int GetNumberOfK(vector data, int k) { 16 | if (data.empty()) { 17 | return 0; 18 | } 19 | 20 | int l = lower_bound(data.begin(), data.end(), k); 21 | int r = upper_bound(data.begin(), data.end(), k); 22 | 23 | return r - l; 24 | } 25 | }; 26 | 27 | int main(int argc, char *argv[]) 28 | { 29 | Solution s; 30 | 31 | vector vec = {1, 5, 6, 6, 6, 6, 7, 8, 8, 9, 10}; 32 | 33 | cout << s.GetNumberOfK(vec, 6) << endl; 34 | 35 | return 0; 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /sfo/36. find nums appear once.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。 5 | ``` 6 | 7 | ```cpp 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | class Solution { 15 | public: 16 | void FindNumsAppearOnce(vector data, int* num1, int* num2) { 17 | bool firstOnce = false; 18 | 19 | map num; 20 | 21 | for (int i = 0; i < data.size(); i++) { 22 | num[data[i]]++; 23 | } 24 | 25 | for (map::iterator itr = num.begin(); itr != num.end(); itr++) { 26 | if (itr->second == 1) { 27 | if (firstOnce == false) { 28 | *num1 = itr->first; 29 | firstOnce = true; 30 | } else { 31 | *num2 = itr->first; 32 | break; 33 | } 34 | } 35 | } 36 | } 37 | }; 38 | 39 | int main(int argc, char* argv[]) 40 | { 41 | vector data = {2, 5, 5, 1, 1, 7, 3, 3}; 42 | 43 | int num1 = -1; 44 | int num2 = -1; 45 | 46 | Solution s; 47 | 48 | s.FindNumsAppearOnce(data, &num1, &num2); 49 | 50 | cout << num1 << endl; 51 | cout << num2 << endl; 52 | 53 | return 0; 54 | } 55 | 56 | ``` 57 | -------------------------------------------------------------------------------- /sfo/37. print min number.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 输入一个正整数数组,把数组里所有数字拼接起来排成一个数, 5 | 打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。 6 | ``` 7 | 8 | ```cpp 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | class Solution { 17 | public: 18 | string PrintMinNumber(vector numbers) { 19 | vector sortedNumbers; 20 | 21 | for (auto &i : numbers) { 22 | sortedNumbers.push_back(to_string(i)); 23 | } 24 | 25 | sort(sortedNumbers.begin(), sortedNumbers.end(), [](string &s1, string &s2){return s1+s2 < s2+s1;}); 26 | 27 | string res = ""; 28 | for (auto &s : sortedNumbers) { 29 | res += s; 30 | } 31 | 32 | return res; 33 | } 34 | }; 35 | 36 | int main(int argc, char* argv[]) 37 | { 38 | Solution s; 39 | 40 | vector num = {3, 32, 321}; 41 | 42 | cout << s.PrintMinNumber(num) << endl; 43 | 44 | return 0; 45 | } 46 | ``` 47 | -------------------------------------------------------------------------------- /sfo/38. get ugly number.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 把只包含质因子2、3和5的数称作丑数(Ugly Number)。 5 | 例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。 6 | ``` 7 | 8 | ```cpp 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | class Solution { 16 | public: 17 | int GetUglyNumber_Solution(int index) { 18 | if (index < 7) { 19 | return index; 20 | } 21 | 22 | vector num(index); 23 | 24 | num[0] = 1; 25 | 26 | int M2 = 0, M3 = 0, M5 = 0; 27 | 28 | for (int i = 1; i < index; i++) { 29 | num[i] = min(num[M2] * 2, min(num[M3] * 3, num[M5] * 5)); 30 | 31 | if (num[i] == num[M2] * 2) { 32 | M2++; 33 | } 34 | 35 | if (num[i] == num[M3] * 3) { 36 | M3++; 37 | } 38 | 39 | if (num[i] == num[M5] * 5) { 40 | M5++; 41 | } 42 | } 43 | 44 | return num[index - 1]; 45 | } 46 | }; 47 | 48 | int main(int argc, char* argv[]) 49 | { 50 | Solution s; 51 | 52 | int x; 53 | 54 | cout << "index: "; 55 | 56 | while (cin >> x) { 57 | cout << " ugly number : " << s.GetUglyNumber_Solution(x) << endl; 58 | cout << "index: "; 59 | } 60 | 61 | return 0; 62 | } 63 | 64 | ``` 65 | -------------------------------------------------------------------------------- /sfo/39. find numbers with sum.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。 5 | 6 | 返回值描述: 7 | 对应每个测试案例,输出两个数,小的先输出。 8 | ``` 9 | 10 | ```cpp 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | class Solution { 17 | public: 18 | vector FindNumbersWithSum(vector array, int sum) { 19 | vector list; 20 | 21 | int length = array.size(); 22 | 23 | int i = 0; 24 | int j = length - 1; 25 | 26 | while (i < j) { 27 | if (array[i] + array[j] == sum) { 28 | list.push_back(array[i]); 29 | list.push_back(array[j]); 30 | break; 31 | } 32 | 33 | if (array[i] + array[j] > sum) { 34 | j--; 35 | } 36 | 37 | if (array[i] + array[j] < sum) { 38 | i++; 39 | } 40 | } 41 | 42 | return list; 43 | } 44 | }; 45 | 46 | int main(int argc, char* argv[]) 47 | { 48 | Solution s; 49 | 50 | vector arr = {0, 1, 3, 5, 7, 11, 12, 14, 18}; 51 | 52 | vector result = s.FindNumbersWithSum(arr, 12); 53 | 54 | for (int i = 0; i < result.size(); i++) { 55 | cout << result[i] << " "; 56 | } 57 | 58 | cout << endl; 59 | 60 | return 0; 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /sfo/4. fibonacci.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。 5 | n<=39 6 | ``` 7 | 8 | ```cpp 9 | #include 10 | using namespace std; 11 | 12 | class Solution { 13 | public: 14 | int Fibonacci(int n) { 15 | int a = 1, b = 1; 16 | int c; 17 | 18 | if (n == 0) { 19 | return 0; 20 | } else if (n == 1 || n == 2) { 21 | return 1; 22 | } else { 23 | for (int i = 3; i <= n; i++) { 24 | c = a + b; 25 | a = b; 26 | b = c; 27 | } 28 | } 29 | 30 | return c; 31 | } 32 | }; 33 | 34 | 35 | int main(int argc, char *argv[]) 36 | { 37 | Solution s; 38 | 39 | cout << s.Fibonacci(30) << endl; 40 | 41 | return 0; 42 | } 43 | ``` 44 | -------------------------------------------------------------------------------- /sfo/40. number of 1 between 1 and N.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数? 5 | 为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。 6 | ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。 7 | ``` 8 | 9 | ```cpp 10 | #include 11 | using namespace std; 12 | 13 | class Solution { 14 | public: 15 | int NumberOf1Between1AndN_Solution(int n) { 16 | int count = 0; 17 | 18 | for (int i = 0; i <= n; i++) { 19 | int temp = i; 20 | 21 | while (temp != 0) { 22 | if (temp % 10 == 1) { 23 | count++; 24 | } 25 | 26 | temp = temp / 10; 27 | } 28 | } 29 | 30 | return count; 31 | } 32 | }; 33 | 34 | int main(int argc, char* argv[]) 35 | { 36 | Solution s; 37 | 38 | cout << s.NumberOf1Between1AndN_Solution(534) << endl; 39 | 40 | return 0; 41 | } 42 | ``` 43 | -------------------------------------------------------------------------------- /sfo/41. left rotate string.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。 5 | 对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”, 6 | 要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它! 7 | ``` 8 | 9 | ```cpp 10 | #include 11 | #include 12 | using namespace std; 13 | 14 | class Solution { 15 | public: 16 | string LeftRotateString(string str, int n) { 17 | if (n == 0 || str.size() == 0) { 18 | return str; 19 | } 20 | 21 | if (n > str.size()) { 22 | n %= str.size(); 23 | } 24 | 25 | string s1 = str.substr(0, n); 26 | string s2 = str.substr(n); 27 | 28 | string res = s2 + s1; 29 | 30 | return res; 31 | } 32 | }; 33 | 34 | int main(int argc, char* argv[]) 35 | { 36 | Solution s; 37 | 38 | string str = "abcXYZ"; 39 | 40 | cout << s.LeftRotateString(str, 3) << endl; 41 | 42 | return 0; 43 | } 44 | ``` 45 | -------------------------------------------------------------------------------- /sfo/42. reverse sentence.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。 5 | 同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。 6 | 例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了, 7 | 正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么? 8 | ``` 9 | 10 | ```cpp 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | class Solution { 16 | public: 17 | string ReverseSentence(string str) { 18 | string res = ""; 19 | string tmp = ""; 20 | 21 | for (int i = 0; i < str.size(); i++) { 22 | if (str[i] == ' ') { 23 | res = " " + tmp + res; 24 | tmp = ""; 25 | } else { 26 | tmp += str[i]; 27 | } 28 | } 29 | 30 | if (tmp.size()) { 31 | res = tmp + res; 32 | } 33 | 34 | return res; 35 | } 36 | }; 37 | 38 | int main(int argc, char* argv[]) 39 | { 40 | string str = "student. a am I"; 41 | Solution s; 42 | 43 | cout << s.ReverseSentence(str) << endl; 44 | 45 | return 0; 46 | } 47 | 48 | 49 | ``` 50 | -------------------------------------------------------------------------------- /sfo/45. find continuous sequence.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。 5 | 但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。 6 | 没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你, 7 | 你能不能也很快的找出所有和为S的连续正数序列? Good Luck! 8 | 9 | 返回值描述: 10 | 输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序 11 | ``` 12 | 13 | ```cpp 14 | #include 15 | #include 16 | 17 | using namespace std; 18 | 19 | class Solution { 20 | public: 21 | vector > FindContinuousSequence(int sum) { 22 | vector > allRes; 23 | 24 | int low = 1; 25 | int high = 2; 26 | 27 | while (low < high) { 28 | int cur = (high + low) * (high - low + 1) / 2; 29 | 30 | if (cur < sum) { 31 | high++; 32 | } else if (cur == sum) { 33 | vector res; 34 | 35 | for (int i = low; i <= high; i++) { 36 | res.push_back(i); 37 | } 38 | 39 | allRes.push_back(res); 40 | low++; 41 | } else { 42 | low++; 43 | } 44 | } 45 | 46 | return allRes; 47 | } 48 | }; 49 | 50 | int main(int argc, char* argv[]) 51 | { 52 | Solution s; 53 | 54 | vector > allRes = s.FindContinuousSequence(100); 55 | 56 | for (int i = 0; i < allRes.size(); i++) { 57 | for (int j = 0; j < allRes[i].size(); j++) { 58 | cout << allRes[i][j] << " "; 59 | } 60 | 61 | cout << endl; 62 | } 63 | 64 | return 0; 65 | } 66 | ``` 67 | -------------------------------------------------------------------------------- /sfo/46. add.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。 5 | ``` 6 | 7 | ```cpp 8 | #include 9 | using namespace std; 10 | 11 | class Solution { 12 | public: 13 | int Add(int num1, int num2) { 14 | while (num2 != 0) { 15 | int temp = num1 ^ num2; 16 | num2 = (num1 & num2) << 1; 17 | num1 = temp; 18 | } 19 | 20 | return num1; 21 | } 22 | }; 23 | 24 | 25 | int main(int argc, char *argv[]) 26 | { 27 | Solution s; 28 | 29 | cout << s.Add(5, 12) << endl; 30 | 31 | return 0; 32 | } 33 | ``` 34 | -------------------------------------------------------------------------------- /sfo/49. str to int.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0. 5 | 6 | 输入描述: 7 | 输入一个字符串,包括数字字母符号,可以为空 8 | 返回值描述: 9 | 如果是合法的数值表达则返回该数字,否则返回0 10 | 11 | 输入 12 | +2147483647 13 | 1a33 14 | 返回值 15 | 2147483647 16 | 0 17 | ``` 18 | 19 | ```cpp 20 | #include 21 | #include 22 | using namespace std; 23 | 24 | class Solution { 25 | public: 26 | int StrToInt(string str) { 27 | if (str.size() == 0) { 28 | return 0; 29 | } 30 | 31 | int flag = 0; 32 | if (str[0] == '+') { 33 | flag = 1; 34 | } else if (str[0] == '-') { 35 | flag = 2; 36 | } 37 | 38 | int start = flag > 0 ? 1 : 0; 39 | 40 | long res = 0; 41 | 42 | while (start < str.size()) { 43 | if (str[start] > '9' || str[start] < '0') { 44 | return 0; 45 | } 46 | 47 | res = res * 10 + (str[start] - '0'); 48 | start++; 49 | } 50 | 51 | return flag == 2 ? -(int)res : (int)res; 52 | } 53 | }; 54 | 55 | int main(int argc, char* argv[]) 56 | { 57 | Solution s; 58 | 59 | string str = "+234563367"; 60 | 61 | cout << s.StrToInt(str) << endl; 62 | 63 | return 0; 64 | } 65 | ``` 66 | -------------------------------------------------------------------------------- /sfo/5. jump floor.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。 5 | ``` 6 | 7 | ```cpp 8 | #include 9 | using namespace std; 10 | 11 | class Solution { 12 | public: 13 | int jumpFloor(int number) { 14 | if (number == 1) { 15 | return 1; 16 | } 17 | 18 | if (number == 2) { 19 | return 2; 20 | } 21 | 22 | int a = 1; 23 | int b = 2; 24 | int c; 25 | 26 | for (int i = 3; i <= number; i++) { 27 | c = a + b; 28 | a = b; 29 | b = c; 30 | } 31 | 32 | return c; 33 | } 34 | }; 35 | 36 | int main(int argc, char *argv[]) 37 | { 38 | Solution s; 39 | 40 | cout << s.jumpFloor(10) << endl; 41 | 42 | return 0; 43 | } 44 | ``` 45 | -------------------------------------------------------------------------------- /sfo/50. is symmetrical.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。 5 | ``` 6 | 7 | ```cpp 8 | #include 9 | using namespace std; 10 | 11 | struct TreeNode { 12 | int val; 13 | struct TreeNode *left; 14 | struct TreeNode *right; 15 | TreeNode(int x) : 16 | val(x), left(NULL), right(NULL) { 17 | } 18 | }; 19 | 20 | class Solution { 21 | public: 22 | bool isSymmetrical(TreeNode* pRoot) 23 | { 24 | return judge(pRoot, pRoot); 25 | } 26 | 27 | private: 28 | bool judge(TreeNode* pRoot1, TreeNode* pRoot2) { 29 | if (pRoot1 == NULL && pRoot2 == NULL) { 30 | return true; 31 | } 32 | 33 | if (pRoot1 == NULL || pRoot2 == NULL) { 34 | return false; 35 | } 36 | 37 | if (pRoot1->val != pRoot2->val) { 38 | return false; 39 | } 40 | 41 | return judge(pRoot1->left, pRoot2->right) && judge(pRoot1->right, pRoot2->left); 42 | } 43 | }; 44 | 45 | int main(int argc, char* argv[]) 46 | { 47 | TreeNode *head = new TreeNode(1); 48 | TreeNode *node1 = new TreeNode(2); 49 | TreeNode *node2 = new TreeNode(3); 50 | TreeNode *node3 = new TreeNode(4); 51 | TreeNode *node4 = new TreeNode(5); 52 | 53 | head->left = node1; 54 | head->right = node2; 55 | node1->left = node3; 56 | node2->right = node4; 57 | 58 | Solution s; 59 | 60 | if (s.isSymmetrical(head) == 1) { 61 | cout << "True" << endl; 62 | } else { 63 | cout << "False" << endl; 64 | } 65 | 66 | return 0; 67 | } 68 | ``` 69 | -------------------------------------------------------------------------------- /sfo/53. last remaining.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。 5 | HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的: 6 | 首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。 7 | 每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中, 8 | 从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友, 9 | 可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1) 10 | 11 | 如果没有小朋友,请返回-1 12 | ``` 13 | 14 | ```cpp 15 | #include 16 | using namespace std; 17 | 18 | class Solution { 19 | public: 20 | int LastRemaining_Solution(int n, int m) 21 | { 22 | if (m < 1 || n < 1) { 23 | return -1; 24 | } 25 | 26 | if (n == 1) { 27 | return 0; 28 | } else { 29 | return (LastRemaining_Solution(n-1, m) + m) % n; 30 | } 31 | } 32 | }; 33 | 34 | int main(int argc, char* argv[]) 35 | { 36 | Solution s; 37 | 38 | cout << s.LastRemaining_Solution(1, 5) << endl; 39 | cout << s.LastRemaining_Solution(8, 5) << endl; 40 | cout << s.LastRemaining_Solution(6, 6) << endl; 41 | 42 | return 0; 43 | } 44 | ``` 45 | -------------------------------------------------------------------------------- /sfo/54. multiply.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1], 5 | 其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。 6 | (注意:规定B[0] = A[1] * A[2] * ... * A[n-1],B[n-1] = A[0] * A[1] * ... * A[n-2];) 7 | 对于A长度为1的情况,B无意义,故而无法构建,因此该情况不会存在。 8 | ``` 9 | 10 | ```cpp 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | class Solution { 16 | public: 17 | vector multiply(const vector& A) { 18 | vector B(A); 19 | 20 | int length = A.size(); 21 | 22 | if (length <= 1) { 23 | vector B; 24 | 25 | return B; 26 | } else { 27 | B[0] = 1; 28 | 29 | for (int i = 1; i < length; i++) { 30 | B[i] = B[i - 1] * A[i - 1]; 31 | } 32 | 33 | int temp = 1; 34 | for (int i = length - 2; i >= 0; i--) { 35 | temp *= A[i + 1]; 36 | B[i] *= temp; 37 | } 38 | } 39 | 40 | return B; 41 | } 42 | }; 43 | 44 | int main(int argc, char* argv[]) 45 | { 46 | vector A = {2, 3, 4, 5}; 47 | 48 | Solution s; 49 | 50 | vector B = s.multiply(A); 51 | 52 | for (int i = 0; i < B.size(); i++) { 53 | cout << B[i] << " " << endl; 54 | } 55 | 56 | cout << endl; 57 | 58 | return 0; 59 | } 60 | ``` 61 | -------------------------------------------------------------------------------- /sfo/6. implement a queue with two stacks.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。 5 | ``` 6 | 7 | ```cpp 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | class Solution { 13 | public: 14 | void push(int node) { 15 | stack1.push(node); 16 | } 17 | 18 | int pop() { 19 | if (stack2.empty()) { 20 | while (!stack1.empty()) { 21 | stack2.push(stack1.top()); 22 | stack1.pop(); 23 | } 24 | } 25 | 26 | int ret = stack2.top(); 27 | stack2.pop(); 28 | 29 | return ret; 30 | } 31 | 32 | bool empty() { 33 | return stack1.empty() && stack2.empty(); 34 | } 35 | 36 | private: 37 | stack stack1; 38 | stack stack2; 39 | }; 40 | 41 | int main(int argc, char *argv[]) 42 | { 43 | Solution s; 44 | s.push(1); 45 | cout << s.pop() << endl; 46 | s.push(2); 47 | cout << s.pop() << endl; 48 | s.push(3); 49 | s.push(4); 50 | s.push(5); 51 | cout << s.pop() << endl; 52 | 53 | return 0; 54 | } 55 | ``` 56 | -------------------------------------------------------------------------------- /sfo/62. match.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符, 5 | 而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。 6 | 例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配 7 | 8 | 示例1 9 | 输入 10 | "aaa","a*a" 11 | 返回值 12 | true 13 | ``` 14 | 15 | ```cpp 16 | #include 17 | using namespace std; 18 | 19 | class Solution { 20 | public: 21 | bool match(char* str, char* pattern) 22 | { 23 | return help(str, pattern); 24 | } 25 | 26 | private: 27 | bool help(char *str, char *pattern) 28 | { 29 | if (*str == '\0' && *pattern == '\0') { 30 | return true; 31 | } 32 | 33 | if (*pattern == '\0') { 34 | return false; 35 | } 36 | 37 | if (*(pattern + 1) == '*') { 38 | if (*str == *pattern || (*pattern == '.' && *str != '\0')) { 39 | return help(str, pattern + 2) || help(str + 1, pattern + 2) || help(str + 1, pattern); 40 | } else { 41 | return help(str, pattern + 2); 42 | } 43 | } 44 | 45 | if (*str == *pattern || (*pattern == '.' && *str != '\0')) { 46 | return help(str + 1, pattern + 1); 47 | } 48 | 49 | return false; 50 | } 51 | }; 52 | 53 | int main(int argc, char* argv[]) 54 | { 55 | Solution s; 56 | 57 | char *str1 = "aaa"; 58 | char *str2 = "a*a"; 59 | 60 | if (s.match(str1, str2) == true) { 61 | cout << "str1 match str2" << endl; 62 | } else { 63 | cout << "str1 not match str2" << endl; 64 | } 65 | 66 | return 0; 67 | } 68 | ``` 69 | -------------------------------------------------------------------------------- /sfo/64. get median.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。 5 | 如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。 6 | 我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。 7 | ``` 8 | 9 | ```cpp 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | class Solution { 16 | public: 17 | void Insert(int num) 18 | { 19 | if (max.empty() || num <= max.top()) { 20 | max.push(num); 21 | } else { 22 | min.push(num); 23 | } 24 | 25 | if (max.size() == min.size() + 2) { 26 | min.push(max.top()); 27 | max.pop(); 28 | } 29 | 30 | if (max.size() + 1 == min.size()) { 31 | max.push(min.top()); 32 | min.pop(); 33 | } 34 | } 35 | 36 | double GetMedian() 37 | { 38 | if (max.size() == min.size()) { 39 | return (max.top() + min.top()) / 2.0; 40 | } else { 41 | return max.top(); 42 | } 43 | } 44 | 45 | private: 46 | priority_queue, less > max; // 从大到小,最大堆 47 | priority_queue, greater > min; // 从小到大,最小堆 48 | }; 49 | 50 | int main(int argc, char *argv[]) 51 | { 52 | Solution s; 53 | 54 | for (int i = 0; i < 25; i += 3) { 55 | s.Insert(i); 56 | } 57 | 58 | cout << "Get Median = " << s.GetMedian() << endl; 59 | 60 | return 0; 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /sfo/67. cut rope.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n), 5 | 每段绳子的长度记为k[1],...,k[m]。请问k[1]x...xk[m]可能的最大乘积是多少? 6 | 例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。 7 | 输入描述: 8 | 输入一个数n,意义见题面。(2 <= n <= 60) 9 | 返回值描述: 10 | 输出答案。 11 | 12 | 示例1 13 | 输入 14 | 8 15 | 返回值 16 | 18 17 | ``` 18 | 19 | ```cpp 20 | #include 21 | using namespace std; 22 | 23 | class Solution { 24 | public: 25 | int cutRope(int number) { 26 | if (number < 2) { 27 | return 0; 28 | } 29 | 30 | if (number == 2) { 31 | return 1; 32 | } 33 | 34 | if (number == 3) { 35 | return 2; 36 | } 37 | 38 | int *product = new int[number+1]; 39 | 40 | product[0] = 0; 41 | product[1] = 1; 42 | product[2] = 2; 43 | product[3] = 3; 44 | 45 | int max = 0; 46 | 47 | for (int i = 4; i <= number; i++) { 48 | for (int j = 1; j <= i / 2; j++) { 49 | int temp = product[j] * product[i - j]; 50 | if (temp > max) { 51 | max = temp; 52 | } 53 | } 54 | product[i] = max; 55 | } 56 | 57 | int res = product[number]; 58 | delete[] product; 59 | return res; 60 | } 61 | }; 62 | 63 | int main(int argc, char *argv[]) 64 | { 65 | Solution s; 66 | cout << s.cutRope(8) << endl; 67 | 68 | return 0; 69 | } 70 | ``` 71 | -------------------------------------------------------------------------------- /sfo/7. min number in rotate array.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 5 | 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 6 | 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 7 | NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。 8 | ``` 9 | 10 | ```cpp 11 | // 二分查找变种 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | class Solution { 18 | public: 19 | int minNumberInRotateArray(vector rotateArray) { 20 | if(rotateArray.empty()) 21 | return 0; 22 | 23 | int low = 0; 24 | int high = rotateArray.size() - 1; 25 | int mid = 0; 26 | 27 | while(low < high){ 28 | if (rotateArray[low] < rotateArray[high]) 29 | return rotateArray[low]; 30 | 31 | mid = low + (high - low) / 2; 32 | 33 | if(rotateArray[mid] > rotateArray[low]) 34 | low = mid + 1; 35 | else if(rotateArray[mid] < rotateArray[high]) 36 | high = mid; 37 | else low++; 38 | } 39 | 40 | return rotateArray[low]; 41 | } 42 | }; 43 | 44 | int main(int argc, char *argv[]) 45 | { 46 | vector arr = {3, 4, 5, 6, 7, 1, 2}; 47 | 48 | Solution s; 49 | 50 | cout << s.minNumberInRotateArray(arr) << endl; 51 | 52 | return 0; 53 | } 54 | ``` 55 | -------------------------------------------------------------------------------- /sfo/8. jump floor ii.md: -------------------------------------------------------------------------------- 1 | ## 题目描述 2 | 3 | ``` 4 | 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 5 | ``` 6 | 7 | ``` 8 | 由于f(n) = f(n - 1) + .. + f(2) + f(1), 那么我们容易得出f(n - 1) = f(n - 2) + .. + f(2) + f(1) 。 9 | 将后者代入前者,我们得到:f(n) = f(n - 1) + f(n - 1),即f(n) = 2 * f(n - 1), 10 | 这是一个等比数列,因此直接使用等比数列的通项公式aq^(n - 1)即可,在本题中a(首项)为1,q为2(公比)。 11 | ``` 12 | 13 | ```cpp 14 | #include 15 | using namespace std; 16 | 17 | class Solution { 18 | public: 19 | int jumpFloorII(int number) { 20 | if (number == 0) { 21 | return 0; 22 | } 23 | 24 | return 1 << (number - 1); 25 | } 26 | }; 27 | 28 | int main(int argc, char *argv[]) 29 | { 30 | Solution s; 31 | cout << s.jumpFloorII(4) << endl; 32 | 33 | return 0; 34 | } 35 | 36 | ``` 37 | --------------------------------------------------------------------------------