diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4eecc56 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +*.idea/workspace.xml +*.out/ + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* \ No newline at end of file diff --git a/.idea/junitgenerator-prj-settings.xml b/.idea/junitgenerator-prj-settings.xml new file mode 100644 index 0000000..d73e792 --- /dev/null +++ b/.idea/junitgenerator-prj-settings.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 0baf590..f048155 100644 --- a/README.md +++ b/README.md @@ -4,20 +4,23 @@ Easy --- -题号|题目|Tags|star| ---- |--- |--- |--- | +题号|题目|Tags|Star|Company| +--- |--- |--- |--- |---| [1](https://leetcode.com/problems/two-sum/description/) | [Two Sum](/src/Q1TwoSum.java) | HashMap | :star: :star: :star: [7](https://leetcode.com/problems/reverse-integer/) | [Reverse Integer](/src/Q7ReverseInteger.java) | Integer | :star: :star: [14](https://leetcode.com/problems/longest-common-prefix/description/) | [Longest Common Prefix](/src/Q14LongestCommonPrefix.java) | String | :star: [20](https://leetcode.com/problems/valid-parentheses/description/) | [Valid Parentheses](/src/Q20ValidParentheses.java) | String、Stack | :star: :star: :star: -[21](https://leetcode.com/problems/merge-two-sorted-lists/description/) | [Merge Two Sorted Lists](/src/Q21MergeTwoSortedLists.java) | LinkedList | :star: :star: :star: -[53](https://leetcode.com/problems/maximum-subarray/description/) | [Maximum Subarray](/src/Q53MaximumSubarray.java) | Array、DP | :star: :star: :star: :star: +[21](https://leetcode.com/problems/merge-two-sorted-lists/description/) | [Merge Two Sorted Lists](/src/Q21MergeTwoSortedLists.java) | LinkedList | :star: :star: :star: :star: +[53](https://leetcode.com/problems/maximum-subarray/description/) | [Maximum Subarray](/src/Q53MaximumSubarray.java) | Array、DP | :star: :star: :star: +[83](https://leetcode.com/problems/remove-duplicates-from-sorted-list/) | [Remove Duplicates from Sorted List](src/Q83RemoveDuplicatesfromSortedList.java) | ListNode | :star: :star: :star: | ByteDance [88](https://leetcode.com/problems/merge-sorted-array/description/) | [Merge Sorted Array](/src/Q88MergeSortedArray.java) | Array、双指针 [100](https://leetcode.com/problems/same-tree/) | [Same Tree](/src/Q100SameTree.java) | Tree | :star: :star: :star: [101](https://leetcode.com/problems/symmetric-tree/) | [Symmetric Tree](/src/Q101SymmetricTree.java) | Tree | :star: :star: :star: [104](https://leetcode.com/problems/maximum-depth-of-binary-tree/description/) | [Maximum Depth of Binary Tree](/src/Q104MaximumDepthofBinaryTree.java) | Tree | :star: :star: :star: [105](https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) | [Construct Binary Tree from Preorder and Inorder Traversal](/src/Q105ConstructBinaryTreefromPreorderandInorderTraversal.java) | Tree | :star: :star: :star: -[108](https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/) | [Convert Sorted Array to Binary Search Tree](/src/Q108ConvertSortedArraytoBinarySearchTree.java) | Tree | :star: :star: :star: +[107](https://leetcode.com/problems/binary-tree-level-order-traversal-ii/submissions/) | [Binary Tree Level Order Traversal II](/src/Q107BinaryTreeLevelOrderTraversalII.java) | Tree | :star: :star: +[108](https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/) | [Convert Sorted Array to Binary Search Tree](/src/Q108ConvertSortedArraytoBinarySearchTree.java) | BST | :star: :star: :star: +[110](https://leetcode.com/problems/balanced-binary-tree/) | [Balanced Binary Tree](/src/Q110BalancedBinaryTree.java) | Tree,DFS | :star: :star: :star: :star: [111](https://leetcode.com/problems/minimum-depth-of-binary-tree/) | [Minimum Depth of Binary Tree](/src/Q111MinimumDepthofBinaryTree.java) | Tree、递归 | :star: :star: :star: [112](https://leetcode.com/problems/path-sum/) | [Path Sum](/src/Q112PathSum.java) | Tree | :star: :star: [115](https://leetcode.com/problems/min-stack/) | [Min Stack](/src/Q155MinStack.java) | Stack | :star: :star: :star: @@ -27,16 +30,18 @@ Easy [122](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/) | [Best Time to Buy and Sell Stock II](/src/Q122BestTimetoBuyandSellStockII.java) | DP | :star: [136](https://leetcode.com/problems/single-number/description/) | [Single Number](/src/Q136SingleNumber.java) | Array、二进制 | :star: :star: :star: [141](https://leetcode.com/problems/linked-list-cycle/description/) | [Linked List Cycle](/src/Q141LinkedListCycle.java) | LinkedList、双指针 | :star: :star: :star: -[148](https://leetcode.com/problems/sort-list/) | [Sort List](/src/Q148SortList.java) | LinkedList、MergeSort | :star: :star: :star: -[160](https://leetcode.com/problems/intersection-of-two-linked-lists/description/) | [Intersection of Two Linked Lists](/src/Q160IntersectionofTwoLinkedLists.java) | LinkedList、双指针 | :star: :star: :star: +[148](https://leetcode.com/problems/sort-list/) | [Sort List](/src/Q148SortList.java) | LinkedList、MergeSort | :star: :star: :star: :star: |ByteDance +[160](https://leetcode.com/problems/intersection-of-two-linked-lists/description/) | [Intersection of Two Linked Lists](/src/Q160IntersectionofTwoLinkedLists.java) | LinkedList、双指针 | :star: :star: :star: :star: | ByteDance [169](https://leetcode.com/problems/majority-element/description/) | [Majority Element](/src/Q169MajorityElement.java) | Array | :star: :star: [198](https://leetcode.com/problems/house-robber/description/) | [House Robber](/src/Q198HouseRobber.java) | Array、DP | :star: :star: :star: [200](https://leetcode.com/problems/number-of-islands/) | [Number of Islands](/src/Q200NumberofIslands.java) | DFS、BFS | :star: :star: :star: -[206](https://leetcode.com/problems/reverse-linked-list/description/) | [Reverse Linked List](/src/Q206ReverseLinkedList.java) | ListNode | :star: :star: :star: +[206](https://leetcode.com/problems/reverse-linked-list/description/) | [Reverse Linked List](/src/Q206ReverseLinkedList.java) | ListNode | :star: :star: :star: :star: [207](https://leetcode.com/problems/course-schedule/) | [Course Schedule](/src/Q207CourseSchedule.java) | DFS、BFS | :star: :star: :star: [217](https://leetcode.com/problems/contains-duplicate/description/) | [Contains Duplicate](/src/Q217ContainsDuplicate.java) | Array、HashTable | :star: [226](https://leetcode.com/problems/invert-binary-tree/) | [Invert Binary Tree](/src/Q226InvertBinaryTree.java) | Tree | :star: :star: :star: [234](https://leetcode.com/problems/palindrome-linked-list/description/) | [Palindrome Linked List](/src/Q234PalindromeLinkedList.java) | LinkedList、双指针 | :star: :star: :star: +[235](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/) | [Lowest Common Ancestor of a Binary Search Tree](/src/Q235LowestCommonAncestorofaBinarySearchTree.java) | 递归 | :star: :star: :star: +[257](https://leetcode.com/problems/binary-tree-paths/) | [Binary Tree Paths](/src/Q257BinaryTreePaths.java) | Tree, String | :star: :star: :star: :star: [338](https://leetcode.com/problems/counting-bits/) | [Counting Bits](/src/Q338CountingBits.java) | bits | :star: :star: :star: [401](https://leetcode.com/problems/binary-watch/description/) | [Binary Watch](/src/Q401BinaryWatch.java) | 递归 | :star: [437](https://leetcode.com/problems/path-sum-iii/) | [Path Sum III](/src/Q437PathSumIII.java) | HashMap,Tree | :star: :star: :star: @@ -44,16 +49,17 @@ Easy [461](https://leetcode.com/problems/hamming-distance/) | [Hamming Distance](/src/Q461HammingDistance.java) | bits | :star: :star: :star: [538](https://leetcode.com/problems/convert-bst-to-greater-tree/) | [Convert BST to Greater Tree](/src/Q538ConvertBSTtoGreaterTree.java) | 二叉搜索树 | :star: :star: :star: [543](https://leetcode.com/problems/diameter-of-binary-tree/) | [ Diameter of Binary Tree](/src/Q543DiameterofBinaryTree.java) | Tree、递归 | :star: :star: :star: -[572](https://leetcode.com/problems/subtree-of-another-tree/) | [Subtree of Another Tree](/src/Q572SubtreeofAnotherTree.java) | Tree | :star: :star: :star: +[572](https://leetcode.com/problems/subtree-of-another-tree/) | [Subtree of Another Tree](/src/Q572SubtreeofAnotherTree.java) | Tree | :star: :star: :star: :star: [581](https://leetcode.com/problems/shortest-unsorted-continuous-subarray/description/) | [Shortest Unsorted Continuous Subarray](/src/Q581ShortestUnsortedContinuousSubarray.java) | Array | :star: :star: :star: [617](https://leetcode.com/problems/merge-two-binary-trees/) | [Merge Two Binary Trees](/src/Q617MergeTwoBinaryTrees.java) | Tree | :star: :star: :star: [628](https://leetcode.com/problems/maximum-product-of-three-numbers/description/) | [Maximum Product of Three Numbers](/src/Q628MaximumProductofThreeNumbers.java) | Array | :star: +[637](https://leetcode.com/problems/average-of-levels-in-binary-tree/) | [Average of Levels in Binary Tree](/src/Q637AverageofLevelsinBinaryTree.java) | Tree | :star: :star: [771](https://leetcode.com/problems/jewels-and-stones/) | [Jewels and Stones](/src/Q771JewelsandStones.java) | String | :star: Medium --- -题号|题目|Tags|star| ----|---|--- |--- | +题号|题目|Tags|Star|Company| +---|---|--- |--- | --- | [2](https://leetcode.com/problems/add-two-numbers/description/) | [Add Two Numbers](/src/Q2AddTwoNumbers.java) | LinkedList | :star: :star: :star: [3](https://leetcode.com/problems/longest-substring-without-repeating-characters/description/) | [Longest Substring Without Repeating Characters](/src/Q3LongestSubstringWithoutRepeatingCharacters.java) | 双指针 | :star: :star: :star: [5](https://leetcode.com/problems/longest-palindromic-substring/) | [Longest Palindromic Substring](/src/Q5LongestPalindromicSubstring.java) | String、动态规划 | :star: :star: :star: @@ -61,6 +67,7 @@ Medium [15](https://leetcode.com/problems/3sum/description/) | [3Sum](/src/Q153Sum.java) | Array、双指针 | :star: :star: :star: [17](https://leetcode.com/problems/letter-combinations-of-a-phone-number/description/) | [Letter Combinations of a Phone Number](/src/Q17LetterCombinationsofaPhoneNumber.java) | 递归 | :star: :star: :star: [19](https://leetcode.com/problems/remove-nth-node-from-end-of-list/description/) | [Remove Nth Node From End of List](/src/Q19RemoveNthNodeFromEndofList.java) | 双指针 | :star: :star: :star: +[21](https://leetcode.com/problems/merge-two-sorted-lists/) | [Merge Two Sorted Lists](/src/Q21MergeTwoSortedLists.java) | List,递归 | :star: :star: :star: :star: [22](https://leetcode.com/problems/generate-parentheses/) | [Generate Parentheses](/src/Q22GenerateParentheses.java) | String、回溯法 | :star: :star: :star: [24](https://leetcode.com/problems/swap-nodes-in-pairs/description/) | [Swap Nodes in Pairs](/src/Q24SwapNodesinPairs.java) | LinkedList | :star: :star: :star: [34](https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/description/) | [Find First and Last Position of Element in Sorted Array](/src/Q34FindFirstandLastPositionofElementinSortedArray.java) | Array、BinarySearch | :star: :star: :star: @@ -70,12 +77,13 @@ Medium [47](https://leetcode.com/problems/permutations-ii/description/) | [PermutationsII](/src/Q47PermutationsII.java) | 回溯法 | :star: :star: :star: [48](https://leetcode.com/problems/rotate-image/description/) | [Rotate Image](/src/Q48RotateImage.java) | 二维数组 | :star: :star: [49](https://leetcode.com/problems/group-anagrams/description/) | [Group Anagrams](/src/Q49GroupAnagrams.java) | ArrayList, HashMap | :star: :star: :star: +[54](https://leetcode.com/problems/spiral-matrix/) | [Spiral Matrix](/src/Q54SpiralMatrix.java) | 细节问题 | :star: :star: [56](https://leetcode.com/problems/merge-intervals/description/) | [Merge Intervals](/src/Q56MergeIntervals.java) | 迭代器,自写比较函数 | :star: :star: :star: [60](https://leetcode.com/problems/permutation-sequence/description/) | [Permutation Sequence](/src/Q60PermutationSequence.java) | Array、感觉像是递归 [61](https://leetcode.com/problems/rotate-list/description/) | [Rotate List](/src/Q61RotateList.java) | LinkedList、双指针 | :star: [62](https://leetcode.com/problems/unique-paths/description/) | [Unique Paths](/src/Q62UniquePaths.java) | 二维数组、动态规划 | :star: :star: :star: [63](https://leetcode.com/problems/unique-paths-ii/description/) | [Unique Paths II](/src/Q63UniquePathsII.java) | 二维数组、动态规划 | :star: :star: :star: -[64](https://leetcode.com/problems/minimum-path-sum/description/) | [Minimum Path Sum](/src/Q64MinimumPathSum.java) | 二维数组、动态规划 | :star: :star: :star: +[64](https://leetcode.com/problems/minimum-path-sum/description/) | [Minimum Path Sum](/src/Q64MinimumPathSum.java) | 二维数组、动态规划 | :star: :star: :star: :star: [74](https://leetcode.com/problems/search-a-2d-matrix/) | [Search a 2D Matrix](/src/Q74Searcha2DMatrix.java) | 二分查找 | :star: :star: [77](https://leetcode.com/problems/combinations/description/) | [Combinations](/src/Q77Combinations.java) | 回溯法 | :star: :star: :star: [78](https://leetcode.com/problems/subsets/description/) | [Subsets](/src/Q78Subsets.java) | Array、回溯法 | :star: :star: :star: @@ -85,21 +93,29 @@ Medium [90](https://leetcode.com/problems/subsets-ii/description/) | [SubsetsII](/src/Q90SubsetsII.java) | Array、回溯法 | :star: :star: :star: [92](https://leetcode.com/problems/reverse-linked-list-ii/) | [Reverse Linked List II](/src/Q92ReverseLinkedListII.java) | LinkedList | :star: :star: :star: [94](https://leetcode.com/problems/binary-tree-inorder-traversal/description/) | [Binary Tree Inorder Traversal](/src/Q94BinaryTreeInorderTraversal.java) | Tree | :star: :star: :star: -[96](https://leetcode.com/problems/unique-binary-search-trees/) | [Unique Binary Search Trees](/src/Q96UniqueBinarySearchTrees.java) | BST, 递归 | :star: :star: :star: +[95](https://leetcode.com/problems/unique-binary-search-trees-ii/) | [Unique Binary Search Trees II](/src/Q95UniqueBinarySearchTreesII.java) | BST | :star: :star: :star: +[96](https://leetcode.com/problems/unique-binary-search-trees/) | [Unique Binary Search Trees](/src/Q96UniqueBinarySearchTrees.java) | BST | :star: :star: :star: +[98](https://leetcode.com/problems/validate-binary-search-tree/) | [Validate Binary Search Tree](/src/Q98ValidateBinarySearchTree.java) | BST | :star: :star: :star: | ByteDance [102](https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/) | [Binary Tree Level Order Traversal](/src/Q102BinaryTreeLevelOrderTraversal.java) | Tree | :star: :star: :star: -[103](https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/) | [Binary Tree Zigzag Level Order Traversal](/src/Q103BinaryTreeZigzagLevelOrderTraversal.java) | Tree | :star: :star: :star: +[103](https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/) | [Binary Tree Zigzag Level Order Traversal](/src/Q103BinaryTreeZigzagLevelOrderTraversal.java) | Tree | :star: :star: :star: | ByteDance +[109](https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/) | [Convert Sorted List to Binary Search Tree](/src/Q109ConvertSortedListtoBinarySearchTree.java) | BST | :star: :star: :star: :star [113](https://leetcode.com/problems/path-sum-ii/) | [Path Sum II](/src/Q113PathSumII.java) | Tree | :star: :star: -[114](https://leetcode.com/problems/flatten-binary-tree-to-linked-list/) | [Flatten Binary Tree to Linked List](/src/Q114FlattenBinaryTreetoLinkedList.java) | Tree | :star: :star: :star: -[120](https://leetcode.com/problems/triangle/) | [Triangle](/src/Q120Triangle.java) | DP | :star: :star: :star: +[114](https://leetcode.com/problems/flatten-binary-tree-to-linked-list/) | [Flatten Binary Tree to Linked List](/src/Q114FlattenBinaryTreetoLinkedList.java) | Tree、递归 | :star: :star: :star: :star | ByteDance +[120](https://leetcode.com/problems/triangle/) | [Triangle](/src/Q120Triangle.java) | DP | :star: :star: :star: :star: +[138](https://leetcode.com/problems/copy-list-with-random-pointer/) | [Copy List with Random Pointer](/src/Q138CopyListwithRandomPointer.java) | List | :star: :star: :star: [139](https://leetcode.com/problems/word-break/) | [Word Break](/src/Q139WordBreak.java) | DP | :star: :star: :star: [142](https://leetcode.com/problems/linked-list-cycle-ii/description/) | [Linked List Cycle II](/src/Q142LinkedListCycleII.java) | LinkedList、双指针 | :star: :star: :star: [143](https://leetcode.com/problems/reorder-list/) | [Reorder List](/src/Q143ReorderList.java) | LinkedList | :star: :star: :star: -[152](https://leetcode.com/problems/maximum-product-subarray/description/) | [Maximum Product Subarray](/src/Q152MaximumProductSubarray.java) | Array、 DP | :star: :star: :star: +[152](https://leetcode.com/problems/maximum-product-subarray/description/) | [Maximum Product Subarray](/src/Q152MaximumProductSubarray.java) | Array、 DP | :star: :star: :star: +[173](https://leetcode.com/problems/binary-search-tree-iterator/) | [Binary Search Tree Iterator](/src/Q173BinarySearchTreeIterator.java) | BST | :star: :star: :star: +[199](https://leetcode.com/problems/binary-tree-right-side-view/) | [Binary Tree Right Side View](/src/Q199BinaryTreeRightSideView.java) | Tree,递归 | :star: :star: :star: :star: | ByteDance [209](https://leetcode.com/problems/minimum-size-subarray-sum/description/) | [Minimum Size Subarray Sum](/src/Q209MinimumSizeSubarraySum.java) | Array、滑动窗口 [213](https://leetcode.com/problems/house-robber-ii/) | [House Robber II](/src/Q213HouseRobberII.java) | 动态规划 | :star: :star: -[215](https://leetcode.com/problems/kth-largest-element-in-an-array/description/) | [Kth Largest Element in an Array](/src/Q215KthLargestElementinanArray.java) | Array、快速选择算法 | :star: :star: :star: :star: +[215](https://leetcode.com/problems/kth-largest-element-in-an-array/description/) | [Kth Largest Element in an Array](/src/Q215KthLargestElementinanArray.java) | Array、快速选择算法 | :star: :star: :star: :star: | ihandy,ByteDance [216](https://leetcode.com/problems/combination-sum-iii/description/) | [CombinationSumIII](/src/Q216CombinationSumIII.java) | Array、回溯法 | :star: :star: :star: [221](https://leetcode.com/problems/maximal-square/) | [Maximal Square](/src/Q221MaximalSquare.java) | DP | :star: :star: :star: +[230](https://leetcode.com/problems/kth-smallest-element-in-a-bst/) | [Kth Smallest Element in a BST](/src/Q230KthSmallestElementinaBST.java) | BST | :star: :star: :star: :star: +[236](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/) | [Lowest Common Ancestor of a Binary Tree](/src/Q236LowestCommonAncestorofaBinaryTree.java) | 递归 | :star: :star: :star: :star: | ByteDance [238](https://leetcode.com/problems/product-of-array-except-self/description/) | [Product of Array Except Self](/src/Q238ProductofArrayExceptSelf.java) | Array [240](https://leetcode.com/problems/search-a-2d-matrix-ii/) | [Search a 2D Matrix II](/src/Q240Searcha2DMatrixII.java) | | :star: :star: :star: [264](https://leetcode.com/problems/ugly-number-ii/) | [Ugly NumberII](/src/Q264UglyNumberII.java) | DP | :star: :star: @@ -107,10 +123,14 @@ Medium [287](https://leetcode.com/problems/find-the-duplicate-number/description/) | [Find the Duplicate Number](/src/Q287FindtheDuplicateNumber.java) | Array、双指针 | :star: :star: :star: [300](https://leetcode.com/problems/longest-increasing-subsequence/) | [Longest Increasing Subsequence](/src/Q300LongestIncreasingSubsequence.java) | DP、Binary Search | :star: :star: :star: [309](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) | [Best Time to Buy and Sell Stock with Cooldown](/src/Q309BestTimetoBuyandSellStockwithCooldown.java) | DP、状态机 | :star: :star: :star: +[322](https://leetcode.com/problems/coin-change/) | [Coin Change](/src/Q322CoinChange.java) | DP | :star: :star: :star: :star: +[328](https://leetcode.com/problems/odd-even-linked-list/) | [Odd Even Linked List](/src/Q328OddEvenLinkedList.java) | ListNode | :star: :star: [334](https://leetcode.com/problems/increasing-triplet-subsequence/) | [Increasing Triplet Subsequence](/src/Q334IncreasingTripletSubsequence.java) | | :star: :star: -[337](https://leetcode.com/problems/house-robber-iii/) | [House Robber III](/src/Q337HouseRobberIII.java) | HashMap、DP | :star: :star: :star: -[347](https://leetcode.com/problems/top-k-frequent-elements/) | [Top K Frequent Elements](/src/Q347TopKFrequentElements.java) | HashMap | :star: :star: :star: -[357](https://leetcode.com/problems/count-numbers-with-unique-digits/description/) | [Count Numbers with Unique Digits](/src/Q357CountNumberswithUniqueDigits.java) | DP、回溯 | :star: :star: :star: +[337](https://leetcode.com/problems/house-robber-iii/) | [House Robber III](/src/Q337HouseRobberIII.java) | HashMap、DP | :star: :star: :star: +[343](https://leetcode.com/problems/integer-break/) | [Integer Break](/src/Q343IntegerBreak.java) | DP | :star: :star: +[347](https://leetcode.com/problems/top-k-frequent-elements/) | [Top K Frequent Elements](/src/Q347TopKFrequentElements.java) | HashMap | :star: :star: :star: :star: +[357](https://leetcode.com/problems/count-numbers-with-unique-digits/description/) | [Count Numbers with Unique Digits](/src/Q357CountNumberswithUniqueDigits.java) | DP、回溯 | :star: :star: :star: +[416](https://leetcode.com/problems/partition-equal-subset-sum/) | [Partition Equal Subset Sum](/src/Q416PartitionEqualSubsetSum.java) | DP | :star: :star: :star: :star: [438](https://leetcode.com/problems/find-all-anagrams-in-a-string/) | [Find All Anagrams in a String](/src/Q438FindAllAnagramsinaString.java) | HashTable、滑动窗口 | :star: :star: :star: [442](https://leetcode.com/problems/find-all-duplicates-in-an-array/description/) | [Find All Duplicates in an Array](/src/Q442FindAllDuplicatesinanArray.java) | Array | :star: :star: :star: [526](https://leetcode.com/problems/beautiful-arrangement/description/) | [BeautifulArrangement](/src/Q526BeautifulArrangement.java) | 回溯 | :star: :star: :star: @@ -119,11 +139,18 @@ Medium [673](https://leetcode.com/problems/number-of-longest-increasing-subsequence/) | [Number of Longest Increasing Subsequence](/src/Q673NumberofLongestIncreasingSubsequence.java) | DP | :star: :star: [713](https://leetcode.com/problems/subarray-product-less-than-k/description/) | [Subarray Product Less Than K](/src/Q713SubarrayProductLessThanK.java) | 双指针、滑动窗口 | :star: :star: [714](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/) | [Best Time to Buy and Sell Stock with Transaction Fee](/src/Q714BestTimetoBuyandSellStockwithTransactionFee.java) | 动态规划、状态机 | :star: :star: :star: - +[718](https://leetcode.com/problems/maximum-length-of-repeated-subarray/) | [Maximum Length of Repeated Subarray](/src/Q718MaximumLengthofRepeatedSubarray.java) | DP | :star: :star: :star: +[946](https://leetcode.com/problems/validate-stack-sequences/) | [Validate Stack Sequences](/src/Q946ValidateStackSequences.java) | Stack | :star: :star: + Hard --- -题号|题目|Tags|star| ----|---|--- |--- | +题号|题目|Tags|Star|Company| +---|---|--- |--- | ---| [4](https://leetcode.com/problems/median-of-two-sorted-arrays/) | [Median of Two Sorted Arrays](/src/Q4MedianofTwoSortedArrays.java) | 分治思想、二分查找 | :star: :star: :star: +[10](https://leetcode.com/problems/regular-expression-matching/) | [Regular Expression Matching](/src/Q10RegularExpressionMatching.java) | DP | :star: :star: :star: +[23](https://leetcode.com/problems/merge-k-sorted-lists/) | [Merge k Sorted Lists](/src/Q23MergekSortedLists.java) | ListNode,归并排序,优先队列 | :star: :star: :star: :star: [123](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/) | [Best Time to Buy and Sell Stock III](/src/Q123BestTimetoBuyandSellStockIII.java) | DP、状态机 | :star: :star: :star: -[188](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/) | [Best Time to Buy and Sell Stock IV](/src/Q188BestTimetoBuyandSellStockIV.java) | DP | :star: :star: :star: \ No newline at end of file +[124](https://leetcode.com/problems/binary-tree-maximum-path-sum/) | [Binary Tree Maximum Path Sum](/src/Q124BinaryTreeMaximumPathSum.java) | Tree,递归 | :star: :star: :star: +[146](https://leetcode.com/problems/lru-cache/) | [LRU Cache](/src/Q146LRUCache.java) | LRU,HashMap,LinkedHashMap | :star: :star: :star: | ByteDance +[188](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/) | [Best Time to Buy and Sell Stock IV](/src/Q188BestTimetoBuyandSellStockIV.java) | DP | :star: :star: :star: +[297](https://leetcode.com/problems/serialize-and-deserialize-binary-tree/) | [Serialize and Deserialize Binary Tree](/src/Q297SerializeandDeserializeBinaryTree.java) | Tree | :star: :star: :star: \ No newline at end of file diff --git a/java.gitignore b/java.gitignore new file mode 100644 index 0000000..4eecc56 --- /dev/null +++ b/java.gitignore @@ -0,0 +1,26 @@ +*.idea/workspace.xml +*.out/ + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* \ No newline at end of file diff --git a/src/DynamicProgramming/KnapsackProblem/Fibonacci.java b/src/DynamicProgramming/KnapsackProblem/Fibonacci.java deleted file mode 100644 index 2fa826a..0000000 --- a/src/DynamicProgramming/KnapsackProblem/Fibonacci.java +++ /dev/null @@ -1,74 +0,0 @@ -package DynamicProgramming.KnapsackProblem; - -/** - * 斐波那契问题是经典的动态规划问题,可以从这里面学到动态规划的思想 - * - * 补充1:走台阶,每次可以走1步,或者两步,问有多少种可能 - * - * 补充2:母牛生产问题,成熟母牛每年生一个小牛小牛三年之后成熟又可以生小牛。第一年有一头牛, - * 第二年开始生小牛,给定整数N,求N年后牛的数量 - * @author ahscuml - * @date 19-3-20 - * @time 下午3:14 - */ -public class Fibonacci { - public static void main(String[] args) { - System.out.println(fib1(8)); - System.out.println(fib2(8)); - System.out.println(cow(5)); - } - - /** - * 递归的方法来做这个提,从上往下 - * */ - private static int fib1(int n) { - if(n < 1) { - return 0; - } else if(n == 1 || n == 2) { - return 1; - } - return fib1(n - 1) + fib1( n - 2); - } - - /** - * 动态规划的方法,O(N)的时间复杂度 - * */ - private static int fib2(int n) { - if (n < 1) { - return 0; - } else if (n == 1 || n == 2) { - return 1; - } - int res = 1, pre = 1; - for (int i = 3; i <= n; i++) { - res += pre; - pre = res - pre; - } - return res; - } - - /** - * 小牛问题 - * 重点是找到递推的关系式 - * */ - private static int cow(int n) { - if(n < 1) { - return 0; - } else if(n == 1 || n == 2 || n == 3) { - return n; - } - // 前1年 - int n_1 = 3; - // 前2年 - int n_2 = 2; - // 前3年 - int n_3 = 1; - for(int i = 4; i <= n; i++) { - n_1 = n_1 + n_3; - int temp = n_2; - n_2 = n_1 - n_3; - n_3 = temp; - } - return n_1; - } -} diff --git a/src/DynamicProgramming/KnapsackProblem/Knapsack01.java b/src/DynamicProgramming/KnapsackProblem/Knapsack01.java deleted file mode 100644 index 4c3bcc3..0000000 --- a/src/DynamicProgramming/KnapsackProblem/Knapsack01.java +++ /dev/null @@ -1,14 +0,0 @@ -package DynamicProgramming.KnapsackProblem; - -import java.util.concurrent.atomic.AtomicIntegerArray; - -/** - * @author ahscuml - * @date 2018/11/28 - * @time 20:13 - */ -public class Knapsack01 { - public static void main(String[] args) { - - } -} diff --git a/src/DynamicProgramming/KnapsackProblem/MaxPathSum.java b/src/DynamicProgramming/KnapsackProblem/MaxPathSum.java deleted file mode 100644 index 2b582de..0000000 --- a/src/DynamicProgramming/KnapsackProblem/MaxPathSum.java +++ /dev/null @@ -1,67 +0,0 @@ -package DynamicProgramming.KnapsackProblem; - -/** - * 矩阵的最小路径和(左上角走到右下角,只能向右和向下走) - * - * @author ahscuml - * @date 19-3-20 - * @time 下午3:53 - */ -public class MaxPathSum { - public static void main(String[] args) { - int[][] matrix = {{1,3,5,9},{8,1,3,4},{5,0,6,1},{8,8,4,0}}; - System.out.println(maxPathSum1(matrix)); - System.out.println(maxPathSum1(matrix)); - } - - /** - * 创建一个二维数组来存储内容,dp[i][j]代表到达当前节点的最小路径值 - * 时间复杂度O(M * N),空间复杂度O(M * N) - * */ - public static int maxPathSum1(int[][] matrix) { - if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) { - return 0; - } - int[][] dp = new int[matrix.length][matrix[0].length]; - dp[0][0] = matrix[0][0]; - for (int i = 1; i < matrix.length; i++) { - dp[i][0] = dp[i - 1][0] + matrix[i][0]; - } - for (int j = 1; j < matrix[0].length; j++) { - dp[0][j] = dp[0][j - 1] + matrix[0][j]; - } - for (int i = 1; i < matrix.length; i++) { - for (int j = 1; j < matrix[0].length; j++) { - dp[i][j] = Math.min(dp[i - 1][j],dp[i][j - 1]) + matrix[i][j]; - } - } - return dp[matrix.length - 1][matrix[0].length - 1]; - } - - /** - * 对于上面的方法的优化,时间复杂度不变,但是空间复杂度变为O(mni(M,N)) - * */ - public static int maxPathSum2(int[][] matrix) { - if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) { - return 0; - } - int col = matrix.length; - int row = matrix[0].length; - int more = Math.max(col, row); - int less = Math.min(col, row); - // 判断是行更多一些,还是列更多一些 - boolean rowmore = more == col; - int[] dp = new int[less]; - dp[0] = matrix[0][0]; - for (int i = 1; i < less; i++) { - dp[i] = dp[i - 1] + (rowmore ? matrix[0][i] : matrix[i][0]); - } - for (int i = 1; i < more; i++) { - dp[0] = dp[0] + (rowmore ? matrix[i][0] : matrix[0][i]); - for (int j = 1; j < less; j++) { - dp[j] = Math.min(dp[j - 1], dp[j]) + (rowmore ? matrix[i][j] : matrix[j][i]); - } - } - return dp[less - 1]; - } -} diff --git a/src/DynamicProgramming/KnapsackProblem/MinCoin.java b/src/DynamicProgramming/KnapsackProblem/MinCoin.java deleted file mode 100644 index 9bfd070..0000000 --- a/src/DynamicProgramming/KnapsackProblem/MinCoin.java +++ /dev/null @@ -1,36 +0,0 @@ -package DynamicProgramming.KnapsackProblem; - -/** - * @author ahscuml - * @date 19-3-20 - * @time 下午4:33 - */ -public class MinCoin { - public static void main(String[] args) { - int[] coins = {1,2,5}; - int target = 11; - System.out.println(minCoin1(coins, target)); - } - - /** - * 首先要找到递推的关系式 - * dp[j]就是凑成j最少有多少种方法 - * */ - public static int minCoin1(int[] num, int target) { - int[] dp = new int[target + 1]; - dp[0] = 0; - for (int i = 1; i <= target; i++) { - int min = -1; - for (int coin : num) { - if (i >= coin) { - int temp = dp[i - coin]; - if (temp != -1) { - min = min == -1 ? temp + 1 : (min > temp + 1 ? temp + 1 : min); - } - } - } - dp[i] = min; - } - return dp[target]; - } -} diff --git a/src/Q100SameTree.java b/src/Q100SameTree.java index f431c58..8ba2f7d 100644 --- a/src/Q100SameTree.java +++ b/src/Q100SameTree.java @@ -1,3 +1,5 @@ +import util.TreeNode; + import java.util.LinkedList; import java.util.Queue; @@ -9,7 +11,7 @@ public class Q100SameTree { /** * 测试函数 - * */ + */ public static void main(String[] args) { TreeNode p1 = new TreeNode(1); TreeNode p2 = new TreeNode(2); @@ -23,13 +25,13 @@ public static void main(String[] args) { q1.left = q2; q1.right = q3; - System.out.println(isSameTreeRec(p1,q1)); - System.out.println(isSameTreeIte(p1,q1)); + System.out.println(isSameTreeRec(p1, q1)); + System.out.println(isSameTreeIte(p1, q1)); } /** * 递归的方法遍历这两个树 - * */ + */ public static boolean isSameTreeRec(TreeNode p, TreeNode q) { if (p == null && q == null) return true; if (p == null && q != null || p != null && q == null) return false; @@ -39,17 +41,17 @@ public static boolean isSameTreeRec(TreeNode p, TreeNode q) { /** * 循环的方法来遍历树,同时只使用一个queue非常简洁,但是对于null的判断会增加时间复杂度。 - * */ + */ public static boolean isSameTreeIte(TreeNode p, TreeNode q) { Queue queue = new LinkedList<>(); queue.add(p); queue.add(q); - while(!queue.isEmpty()){ + while (!queue.isEmpty()) { TreeNode f = queue.poll(); TreeNode s = queue.poll(); - if(f == null && s == null){ + if (f == null && s == null) { continue; - }else if(f == null || s == null || f.val != s.val){ + } else if (f == null || s == null || f.val != s.val) { return false; } queue.add(f.left); @@ -59,14 +61,4 @@ public static boolean isSameTreeIte(TreeNode p, TreeNode q) { } return true; } - - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/Q101SymmetricTree.java b/src/Q101SymmetricTree.java index ec98303..34447f4 100644 --- a/src/Q101SymmetricTree.java +++ b/src/Q101SymmetricTree.java @@ -1,3 +1,5 @@ +import util.TreeNode; + import java.util.Stack; /** @@ -114,14 +116,4 @@ private static boolean isSymmetricIte(TreeNode root) { } return true; } - - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/Q102BinaryTreeLevelOrderTraversal.java b/src/Q102BinaryTreeLevelOrderTraversal.java index 052ad23..08efe95 100644 --- a/src/Q102BinaryTreeLevelOrderTraversal.java +++ b/src/Q102BinaryTreeLevelOrderTraversal.java @@ -1,3 +1,5 @@ +import util.TreeNode; + import java.util.ArrayList; import java.util.LinkedList; import java.util.Queue; @@ -89,23 +91,10 @@ private static void depth(TreeNode root, int depth, ArrayList if (depth > list.size()) { list.add(new ArrayList<>()); } - // 获取之前添加的ArrayList然后添加数据; + // 获取之前添加的ArrayList然后添加数据;主要depth要减一 list.get(depth - 1).add(root.val); depth(root.left, depth + 1, list); depth(root.right, depth + 1, list); } - - /** - * 树结构的定义 - */ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/Q103BinaryTreeZigzagLevelOrderTraversal.java b/src/Q103BinaryTreeZigzagLevelOrderTraversal.java index 73fe2f6..f4ad8c3 100644 --- a/src/Q103BinaryTreeZigzagLevelOrderTraversal.java +++ b/src/Q103BinaryTreeZigzagLevelOrderTraversal.java @@ -1,3 +1,5 @@ +import util.TreeNode; + import java.util.*; /** @@ -27,52 +29,6 @@ public static void main(String[] args) { System.out.println(Helper(treeNode1)); } - /** - * 通过翻转来实现,循环算法 - */ - public static List> zigzagLevelOrderIte(TreeNode root) { - List> res = new ArrayList(); - List curRes = new ArrayList(); - if (root == null) { - return res; - } - Queue queue = new LinkedList(); - queue.offer(root); - TreeNode cur; - int level = 1; - // 当前层的元素数量 - int A = 1; - // 下一层的元素数量 - int next = 0; - while (!queue.isEmpty()) { - - cur = queue.poll(); - // 当前行减1; - A--; - curRes.add(cur.val); - if (cur.left != null) { - queue.offer(cur.left); - next++; - } - if (cur.right != null) { - queue.offer(cur.right); - next++; - } - if (A == 0) { - if (level % 2 == 0) { - Collections.reverse(curRes); - } - res.add(curRes); - curRes = new ArrayList(); - A = next; - next = 0; - level++; - } - } - return res; - } - - /** * 递归的算法 */ @@ -92,6 +48,7 @@ private static void travel(TreeNode curr, List> sol, int level) { List collection = sol.get(level); if (level % 2 == 0) collection.add(curr.val); + // 不一样的地方,利用ArrayList 的特点,从头添加的时候会把后面的往后移动 else collection.add(0, curr.val); travel(curr.left, sol, level + 1); @@ -99,7 +56,7 @@ private static void travel(TreeNode curr, List> sol, int level) { } /** - * 使用一个栈与一个队列来实现,因为栈弹出的过程就是翻转的过程 + * 使用两个栈来实现,因为栈弹出的过程就是翻转的过程 */ private static List> Helper(TreeNode root) { TreeNode cur; @@ -108,12 +65,12 @@ private static List> Helper(TreeNode root) { return res; } Stack stack = new Stack<>(); - Queue queue = new LinkedList<>(); - queue.offer(root); + Stack queue = new Stack<>(); + queue.push(root); while (!queue.isEmpty() || !stack.isEmpty()) { List temp = new ArrayList<>(); while (!queue.isEmpty()) { - cur = queue.poll(); + cur = queue.pop(); temp.add(cur.val); if (cur.left != null) { stack.push(cur.left); @@ -127,11 +84,11 @@ private static List> Helper(TreeNode root) { while (!stack.isEmpty()) { cur = stack.pop(); temp.add(cur.val); - if (cur.left != null) { - queue.offer(cur.left); - } if (cur.right != null) { - queue.offer(cur.right); + queue.push(cur.right); + } + if (cur.left != null) { + queue.push(cur.left); } } if (!temp.isEmpty()) { @@ -142,15 +99,38 @@ private static List> Helper(TreeNode root) { } /** - * 树结构的定义 + * 利用Collection.reverse函数来实现 */ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; + public static List> zigzagLevelOrderIte(TreeNode root) { + List> res = new ArrayList<>(); + if (root == null) { + return res; + } + List curList = new ArrayList(); + Queue queue = new LinkedList(); + queue.offer(root); + TreeNode cur = null; + boolean iszigzag = false; + while (!queue.isEmpty()) { + int size = queue.size(); + ArrayList list = new ArrayList(); + while (size != 0) { + cur = queue.poll(); + list.add(cur.val); + if (cur.left != null) { + queue.offer(cur.left); + } + if (cur.right != null) { + queue.offer(cur.right); + } + size--; + } + if (iszigzag) { + Collections.reverse(list); + } + res.add(list); + iszigzag = !iszigzag; } + return res; } } diff --git a/src/Q104MaximumDepthofBinaryTree.java b/src/Q104MaximumDepthofBinaryTree.java index 39a780f..f6c5818 100644 --- a/src/Q104MaximumDepthofBinaryTree.java +++ b/src/Q104MaximumDepthofBinaryTree.java @@ -1,3 +1,5 @@ +import util.TreeNode; + import java.util.LinkedList; import java.util.Queue; @@ -86,14 +88,4 @@ private static int maxDepthIte(TreeNode root) { } return level; } - - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/Q105ConstructBinaryTreefromPreorderandInorderTraversal.java b/src/Q105ConstructBinaryTreefromPreorderandInorderTraversal.java index c3c59f4..8fdf60b 100644 --- a/src/Q105ConstructBinaryTreefromPreorderandInorderTraversal.java +++ b/src/Q105ConstructBinaryTreefromPreorderandInorderTraversal.java @@ -1,4 +1,4 @@ -import TEST.InOrder; +import util.TreeNode; import java.util.HashMap; import java.util.Map; @@ -16,7 +16,7 @@ public static void main(String[] args) { int[] preorder = {3, 9, 20, 15, 7}; int[] inorder = {9, 3, 15, 20, 7}; - preorderRec(buildTree(preorder,inorder)); + preorderRec(buildTree(preorder, inorder)); } /** @@ -37,7 +37,7 @@ public static TreeNode buildTree(int[] preorder, int[] inorder) { public static TreeNode buildTree(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd, - Map inMap) { + Map inMap) { if (preStart > preEnd || inStart > inEnd) { return null; } @@ -63,17 +63,4 @@ public static void preorderRec(TreeNode root) { preorderRec(root.right); } } - - /** - * 树结构的定义 - */ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/Q107BinaryTreeLevelOrderTraversalII.java b/src/Q107BinaryTreeLevelOrderTraversalII.java new file mode 100644 index 0000000..4da0a5e --- /dev/null +++ b/src/Q107BinaryTreeLevelOrderTraversalII.java @@ -0,0 +1,75 @@ +import util.TreeNode; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * 倒着层序遍历二叉树 + * + * @author ahscuml + * @date 2019/4/29 + * @time 12:09 + */ +public class Q107BinaryTreeLevelOrderTraversalII { + /** + * 测试函数 + */ + public static void main(String[] args) { + // TODO + } + + /** + * 后序遍历的递归实现,记录层数,确定添加元素的位置 + */ + public static List> levelOrderBottomII(TreeNode root) { + List> wrapList = new LinkedList>(); + levelMaker(wrapList, root, 0); + return wrapList; + } + + public static void levelMaker(List> list, TreeNode root, int level) { + if (root == null) return; + if (level >= list.size()) { + list.add(0, new LinkedList()); + } + levelMaker(list, root.left, level + 1); + levelMaker(list, root.right, level + 1); + list.get(list.size() - level - 1).add(root.val); + } + + /** + * 层序遍历循环方法 + * 最后将结果逆序有两种方法,一种是规定好插入的位置,在第一个,另外一种是使用Collections.reverse()函数 + */ + public List> levelOrderBottom(TreeNode root) { + List> list = new ArrayList(); + if (root == null) { + return list; + } + Queue queue = new LinkedList<>(); + TreeNode cur = null; + queue.offer(root); + while (!queue.isEmpty()) { + List templist = new ArrayList(); + int count = queue.size(); + while (count > 0) { + cur = queue.poll(); + templist.add(cur.val); + if (cur.left != null) { + queue.offer(cur.left); + } + if (cur.right != null) { + queue.offer(cur.right); + } + count--; + } + if (templist != null) + list.add(0, templist); + } + return list; + } +} + + diff --git a/src/Q108ConvertSortedArraytoBinarySearchTree.java b/src/Q108ConvertSortedArraytoBinarySearchTree.java index f7ac3d7..98a68c7 100644 --- a/src/Q108ConvertSortedArraytoBinarySearchTree.java +++ b/src/Q108ConvertSortedArraytoBinarySearchTree.java @@ -1,3 +1,5 @@ +import util.TreeNode; + /** * @author ahscuml * @date 2019/1/4 @@ -6,16 +8,16 @@ public class Q108ConvertSortedArraytoBinarySearchTree { /** * 测试函数 - * */ + */ public static void main(String[] args) { } /** * 利用递归的方法来说实现 - * */ + */ public TreeNode sortedArrayToBST(int[] nums) { - if(nums == null || nums.length == 0) { + if (nums == null || nums.length == 0) { return null; } // 节点个数可能是奇数或者偶数,需要进行判断 @@ -23,8 +25,8 @@ public TreeNode sortedArrayToBST(int[] nums) { return helper(nums, 0, n - 1); } - public TreeNode helper(int[] nums, int left ,int right) { - if(right < left) { + public TreeNode helper(int[] nums, int left, int right) { + if (right < left) { return null; } int mid = (right + left) / 2; @@ -33,17 +35,4 @@ public TreeNode helper(int[] nums, int left ,int right) { root.right = helper(nums, mid + 1, right); return root; } - - /** - * 树结构的定义 - * */ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/Q109ConvertSortedListtoBinarySearchTree.java b/src/Q109ConvertSortedListtoBinarySearchTree.java new file mode 100644 index 0000000..0966fe7 --- /dev/null +++ b/src/Q109ConvertSortedListtoBinarySearchTree.java @@ -0,0 +1,70 @@ +import util.ListNode; +import util.TreeNode; + +/** + * 把一个有序链表变成二叉查找树 + * + * @author ahscuml + * @date 2019/5/18 + * @time 1:00 + */ +public class Q109ConvertSortedListtoBinarySearchTree { + /** + * 测试函数 + */ + public static void main(String[] args) { + + } + + /** + * 思路很简单和108题对应,但是108题中的array可以用index来找到中间值,list只能使用双指针这个方法 + * 同样这个里面有很多的细节 + */ + public TreeNode sortedListToBST(ListNode head) { + if (head == null) { + return null; + } + if (head.next == null) { + return new TreeNode(head.val); + } + ListNode fast = head, slow = head, last = slow; + // 利用这种判断方法可以保障fast不是空 + while (fast.next != null && fast.next.next != null) { + fast = fast.next.next; + last = slow; + slow = slow.next; + } + // 分裂为两个list + fast = slow.next; + last.next = null; + TreeNode cur = new TreeNode(slow.val); + if (head != slow) { + cur.left = sortedListToBST(head); + } + cur.right = sortedListToBST(fast); + return cur; + } + + /** + * 跟上面的思路是一样的,但是分成了两个方法,更加好理解 + */ + public TreeNode sortedListToBSTII(ListNode head) { + if (head == null) return null; + return toBST(head, null); + } + + public TreeNode toBST(ListNode head, ListNode tail) { + ListNode slow = head; + ListNode fast = head; + if (head == tail) return null; + + while (fast != tail && fast.next != tail) { + fast = fast.next.next; + slow = slow.next; + } + TreeNode thead = new TreeNode(slow.val); + thead.left = toBST(head, slow); + thead.right = toBST(slow.next, tail); + return thead; + } +} diff --git a/src/Q10RegularExpressionMatching.java b/src/Q10RegularExpressionMatching.java new file mode 100644 index 0000000..dd43a09 --- /dev/null +++ b/src/Q10RegularExpressionMatching.java @@ -0,0 +1,46 @@ +/** + * @author ahscuml + * @date 2019/4/7 + * @time 0:04 + */ +public class Q10RegularExpressionMatching { + public static void main(String[] args) { + // TODO 测试用例 + } + + public static boolean isMatch(String s, String p) { + boolean[][] dp = new boolean[s.length() + 1][p.length() + 1]; + // 初始化,当模式串为0的时候,除了0,0为true,其余都为false + dp[0][0] = true; + // 当s为0的时候,如果模式串带有*还可能为空,保证前面一个不是* + for(int j = 2; j <= p.length(); j++) { + if(p.charAt(j - 1) == '*' && j > 1 && p.charAt(j - 2) != '*') { + dp[0][j] = dp[0][j - 2]; + } + } + + for(int i = 1; i <= s.length(); i++) { + for(int j = 1; j <= p.length(); j++) { + // 首先确定如果相等的情况 + if(s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.') { + // 匹配的情况 + dp[i][j] = dp[i - 1][j - 1]; + } + // 不匹配的情况,1. 真的不匹配,不用管,因为默认是false + // 2. 出现'*' + if(p.charAt(j - 1) == '*') { + if(s.charAt(i - 1) != p.charAt(j - 2) && p.charAt(j - 2) != '.') { + // 不匹配任何内容,那么x*只能为空 + dp[i][j] = dp[i][j - 2]; + } else { + // 2.1 x*不匹配任何内容,直接跳过 + // 2.2 x*匹配一个内容 + // 2.3 x*匹配很多个内容 + dp[i][j] = dp[i][j - 2] || dp[i][j - 1] || dp[i - 1][j]; + } + } + } + } + return dp[s.length()][p.length()]; + } +} diff --git a/src/Q110BalancedBinaryTree.java b/src/Q110BalancedBinaryTree.java new file mode 100644 index 0000000..6e2addf --- /dev/null +++ b/src/Q110BalancedBinaryTree.java @@ -0,0 +1,68 @@ +import util.TreeNode; + +/** + * @author ahscuml + * @date 2019/4/13 + * @time 17:07 + */ +public class Q110BalancedBinaryTree { + /** + * 测试函数 + */ + public static void main(String[] args) { + // TODO + } + + /** + * 自底向上的方法,计算深度,然后返回。 + * 时间复杂度O(nlogn) + */ + public boolean isBalanced(TreeNode root) { + if (root == null) { + return true; + } + int left = depth(root.left); + int right = depth(root.right); + // 针对每一个深度都得符合要求 + if (Math.abs(left - right) <= 1) { + return isBalanced(root.left) && isBalanced(root.right); + } + return false; + } + + public int depth(TreeNode root) { + if (root == null) { + return 0; + } + return Math.max(depth(root.left), depth(root.right)) + 1; + } + + /** + * 自顶向下的方法 + * 时间复杂度O(n) + */ + public boolean isBalancedII(TreeNode root) { + return height(root) != -1; + } + + public int height(TreeNode node) { + if (node == null) { + return 0; + } + // 递归调用,计算深度 + int lH = height(node.left); + if (lH == -1) { + return -1; + } + // 右边递归调用,计算深度 + int rH = height(node.right); + if (rH == -1) { + return -1; + } + // 判断当前行是否满足要求,不满足要求直接返回-1 + if (lH - rH < -1 || lH - rH > 1) { + return -1; + } + return Math.max(lH, rH) + 1; + } +} diff --git a/src/Q112PathSum.java b/src/Q112PathSum.java index 86194d0..59e6d0c 100644 --- a/src/Q112PathSum.java +++ b/src/Q112PathSum.java @@ -1,3 +1,5 @@ +import util.TreeNode; + import java.util.Stack; /** @@ -38,12 +40,12 @@ public static boolean hasPathSumRec(TreeNode root, int sum) { /** * 采用循环的方法,可以避免堆栈的溢出,但是代码量很大,而且需要一个栈存储当前节点的和 + * 其实就是前序遍历,只不过存储的是值而已,通过一个判断来完成题目要求。 */ public static boolean hasPathSumIte(TreeNode root, int sum) { if (root == null) { return false; } - Stack stack = new Stack<>(); Stack SumForNode = new Stack<>(); int curSum = 0; @@ -68,17 +70,4 @@ public static boolean hasPathSumIte(TreeNode root, int sum) { } return false; } - - /** - * 树结构的定义 - */ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/Q113PathSumII.java b/src/Q113PathSumII.java index 18e70fe..ce6789b 100644 --- a/src/Q113PathSumII.java +++ b/src/Q113PathSumII.java @@ -1,3 +1,5 @@ +import util.TreeNode; + import java.util.ArrayList; import java.util.List; import java.util.Stack; @@ -96,20 +98,6 @@ public static List> pathSumIte(TreeNode root, int sum) { curSum -= cur.val; cur = null; } - return res; } - - /** - * 树结构的定义 - */ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/Q114FlattenBinaryTreetoLinkedList.java b/src/Q114FlattenBinaryTreetoLinkedList.java index e973153..d34051e 100644 --- a/src/Q114FlattenBinaryTreetoLinkedList.java +++ b/src/Q114FlattenBinaryTreetoLinkedList.java @@ -1,3 +1,5 @@ +import util.TreeNode; + import java.util.Stack; /** @@ -8,6 +10,11 @@ * @time 9:40 */ public class Q114FlattenBinaryTreetoLinkedList { + /** + * 和我的思路一样,但是非常简单的写法 + */ + private TreeNode prev = null; + // TODO 增加测试用例; public static void main(String[] args) { @@ -24,6 +31,7 @@ public void flatten(TreeNode root) { if (root == null) { return; } + // 这样递归调用保证是从后面往前面进行后面的操作的 flatten(root.right); flatten(root.left); // 如果左面空,那么不用处理,直接返回 @@ -44,10 +52,6 @@ public void flatten(TreeNode root) { } } - /** - * 和我的思路一样,但是非常简单的写法 - */ - private TreeNode prev = null; public void flattenEasy(TreeNode root) { if (root == null) return; @@ -59,7 +63,7 @@ public void flattenEasy(TreeNode root) { } /** - * 迭代方法 + * 迭代方法,先存右节点,再存左节点。 */ public void flattenIte(TreeNode root) { if (root == null) { @@ -79,20 +83,6 @@ public void flattenIte(TreeNode root) { cur.right = stack.peek(); } cur.left = null; - - } - } - - /** - * 树结构的定义 - */ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; } } } diff --git a/src/Q124BinaryTreeMaximumPathSum.java b/src/Q124BinaryTreeMaximumPathSum.java new file mode 100644 index 0000000..e67e48b --- /dev/null +++ b/src/Q124BinaryTreeMaximumPathSum.java @@ -0,0 +1,48 @@ +import util.TreeNode; + +/** + * @author ahscuml + * @date 2019/4/1 + * @time 12:09 + */ +public class Q124BinaryTreeMaximumPathSum { + /** + * 还是利用了递归的思想,以当前节点为中心,找到左右两边最大的子树,然后加起来 + */ + public static int max = Integer.MIN_VALUE; + + /** + * 测试函数 + */ + public static void main(String[] args) { + TreeNode t1 = new TreeNode(1); + TreeNode t2 = new TreeNode(2); + TreeNode t3 = new TreeNode(3); + t1.left = t2; + t1.right = t3; + System.out.println(maxPathSum(t1)); + } + + /** + * 返回这个最大值 + * */ + public static int maxPathSum(TreeNode root) { + helper(root); + return max; + } + + /** + * 返回以当前节点为中心的最大的左节点或者右节点 + */ + private static int helper(TreeNode node) { + if (node == null) { + return 0; + } + int left = Math.max(0, helper(node.left)); + int right = Math.max(0, helper(node.right)); + // 最大值的判断 + max = Math.max(max, left + right + node.val); + // 这是要返回的内容,最大的左或右,别忘了加上val + return Math.max(left, right) + node.val; + } +} diff --git a/src/Q138CopyListwithRandomPointer.java b/src/Q138CopyListwithRandomPointer.java new file mode 100644 index 0000000..e9a8423 --- /dev/null +++ b/src/Q138CopyListwithRandomPointer.java @@ -0,0 +1,51 @@ +import util.RandomNode; + +/** + * @author ahscuml + * @date 2019/4/17 + * @time 21:37 + */ +public class Q138CopyListwithRandomPointer { + /** + * 测试函数 + * */ + public static void main(String[] args) { + // TODO + } + + /** + * + * */ + public RandomNode copyRandomList(RandomNode head) { + if(head == null) { + return null; + } + RandomNode cur = head; + // 创建新的链表 + while(cur != null) { + RandomNode newNode = new RandomNode(); + newNode.val = cur.val; + newNode.next = cur.next; + cur.next = newNode; + cur = cur.next.next; + } + + cur = head; + // 复制random节点 + while(cur != null) { + cur.next.random = cur.random == null ? null : cur.random.next; + cur = cur.next.next; + } + cur = head; + RandomNode dummyHead = cur.next; + // 按照奇偶拆分成两个链表 + while(cur != null) { + RandomNode newNode = cur.next; + cur.next = newNode.next; + newNode.next = cur.next == null ? null : newNode.next.next; + cur = cur.next; + } + return dummyHead; + + } +} diff --git a/src/Q144BinaryTreePreorderTraversal.java b/src/Q144BinaryTreePreorderTraversal.java new file mode 100644 index 0000000..a6080e6 --- /dev/null +++ b/src/Q144BinaryTreePreorderTraversal.java @@ -0,0 +1,17 @@ +/** + * @author ahscuml + * @date 2019/4/8 + * @time 18:38 + */ +public class Q144BinaryTreePreorderTraversal { + /** + *测试函数 + * */ + public static void main(String[] args) { + // TODO + } + + /** + * 树的前序遍历,没那么复杂 + * */ +} diff --git a/src/Q146LRUCache.java b/src/Q146LRUCache.java new file mode 100644 index 0000000..d7feb6f --- /dev/null +++ b/src/Q146LRUCache.java @@ -0,0 +1,107 @@ +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author ahscuml + * @date 2019/4/8 + * @time 23:58 + */ +class LRUCache { + // 定义LRUCache的一些常量参数 + final Node head = new Node(0, 0); + final Node tail = new Node(0, 0); + final HashMap map; + final int capacity; + + // 对于LRU初始化 + public LRUCache(int capacity) { + this.capacity = capacity; + map = new HashMap(capacity); + head.next = tail; + tail.pre = head; + } + + // 插入一个元素到队列的头结点 + private void insertToHead(Node node) { + node.next = head.next; + node.next.pre = node; + head.next = node; + node.pre = head; + } + + // 从队列里删除一个节点 + private void remove(Node node) { + node.pre.next = node.next; + node.next.pre = node.pre; + } + + public int get(int key) { + if (map.containsKey(key)) { + Node node = map.get(key); + remove(node); + insertToHead(node); + return node.val; + } else { + return -1; + } + } + + public void put(int key, int value) { + if (map.containsKey(key)) { + Node node = map.get(key); + remove(node); + node.val = value; + insertToHead(node); + } else { + if (map.size() == capacity) { + map.remove(tail.pre.key); + // 只有到达容量的时候才移动 + remove(tail.pre); + } + Node node = new Node(key, value); + map.put(key, node); + insertToHead(node); + } + } + + // 创建一个node对象,方便进行插入删除 + // 这一一个双端队列 + class Node { + Node pre, next; + int key, val; + + Node(int key, int val) { + this.key = key; + this.val = val; + } + } +} + + + + +/** + * 采用LinkedHashMap的方式,非常简单。 + * */ +class LRUCacheII { + private final int CAPACITY; + private LinkedHashMap map; + + public LRUCacheII(int capacity) { + CAPACITY = capacity; + map = new LinkedHashMap(capacity, 0.75f, true) { + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > CAPACITY; + } + }; + } + + public int get(int key) { + return map.getOrDefault(key, -1); + } + + public void put(int key, int value) { + map.put(key, value); + } +} \ No newline at end of file diff --git a/src/Q148SortList.java b/src/Q148SortList.java index 9607ed4..5a2c4aa 100644 --- a/src/Q148SortList.java +++ b/src/Q148SortList.java @@ -79,19 +79,19 @@ public static ListNode sortList(ListNode head) { * 递归调用,两个节点,一个快,一个慢,快的到达末尾,慢的就到达中间 */ public static ListNode sortListRec(ListNode head) { - if (head == null || head.next == null) + if(head == null || head.next == null) { return head; - ListNode f = head.next.next; - ListNode p = head; - while (f != null && f.next != null) { - p = p.next; - f = f.next.next; } - // 递归调用 p在链表的中部 - ListNode h2 = sortListRec(p.next); - // 将一个链表从中间分为两部分 一个是head,一个是h2 - p.next = null; - return merge(sortListRec(head), h2); + ListNode slow = head,fast = head,pre = null; + while(fast != null && fast.next != null) { + pre = slow; + slow = slow.next; + fast = fast.next.next; + } + pre.next = null; + ListNode l1 = sortList(head); + ListNode l2 = sortList(slow); + return merge(l1, l2); } /** diff --git a/src/Q160IntersectionofTwoLinkedLists.java b/src/Q160IntersectionofTwoLinkedLists.java index de76548..2579847 100644 --- a/src/Q160IntersectionofTwoLinkedLists.java +++ b/src/Q160IntersectionofTwoLinkedLists.java @@ -14,6 +14,7 @@ public static void main(String[] args) { listNode2.next = listNode3; listNode3.next = listNode4; System.out.println(getIntersectionNode(listNode1, listNode2).val); + System.out.println(getIntersectionNodeII(listNode1, listNode2).val); } /** @@ -35,10 +36,43 @@ public static ListNode getIntersectionNode(ListNode headA, ListNode headB) { a = a == null ? headB : a.next; b = b == null ? headA : b.next; } - return a; } + /** + * 另外一种循环的方法就是首先求出两个链表的长度,然后调整到一样长的地方在走,直到找到相同的那个节点 + */ + public static ListNode getIntersectionNodeII(ListNode headA, ListNode headB) { + if (headA == null || headB == null) { + return null; + } + int alen = len(headA); + int blen = len(headB); + while (alen > blen) { + headA = headA.next; + alen--; + } + while (blen > alen) { + headB = headB.next; + blen--; + } + + while (headA != headB) { + headA = headA.next; + headB = headB.next; + } + return headA; + } + + public static int len(ListNode node) { + int count = 0; + while (node != null) { + count++; + node = node.next; + } + return count; + } + static class ListNode { int val; ListNode next; diff --git a/src/Q173BinarySearchTreeIterator.java b/src/Q173BinarySearchTreeIterator.java new file mode 100644 index 0000000..d17d4b2 --- /dev/null +++ b/src/Q173BinarySearchTreeIterator.java @@ -0,0 +1,95 @@ +import util.TreeNode; + +import java.util.ArrayDeque; +import java.util.LinkedList; +import java.util.Queue; + +/** + * @author ahscuml + * @date 2019/5/18 + * @time 0:04 + */ +public class Q173BinarySearchTreeIterator { + /** + * 测试函数 + */ + public static void main(String[] args) { + + } + + /** + * 把按照顺序遍历的过程通过三个函数展现出来,里面有很多细节的处理 + */ + class BSTIterator { + private ArrayDeque stack = new ArrayDeque<>(); + + public BSTIterator(TreeNode root) { + // 先到达最小的子节点 + while (root != null) { + stack.push(root); + root = root.left; + } + } + + /** + * @return the next smallest number + */ + public int next() { + TreeNode n = stack.peek(); + stack.pop(); + int res = n.val; + if (n.right != null) { + n = n.right; + while (n != null) { + stack.push(n); + n = n.left; + } + } + return res; + } + + /** + * @return whether we have a next smallest number + */ + public boolean hasNext() { + return !stack.isEmpty(); + } + } + + + /** + * 题目很简单,这个解法是相对笨一点的解法 + */ + class BSTIteratorII { + Queue queue = new LinkedList(); + + public void BSTIteratorII(TreeNode root) { + helper(root); + } + + void helper(TreeNode root) { + if (root == null) { + return; + } + helper(root.left); + queue.offer(root.val); + helper(root.right); + } + + /** + * @return the next smallest number + */ + public int next() { + if (hasNext()) + return queue.poll(); + return -1; + } + + /** + * @return whether we have a next smallest number + */ + public boolean hasNext() { + return !queue.isEmpty(); + } + } +} diff --git a/src/Q199BinaryTreeRightSideView.java b/src/Q199BinaryTreeRightSideView.java new file mode 100644 index 0000000..b16e0c4 --- /dev/null +++ b/src/Q199BinaryTreeRightSideView.java @@ -0,0 +1,71 @@ +import util.TreeNode; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * @author ahscuml + * @date 2019/4/1 + * @time 17:00 + */ +public class Q199BinaryTreeRightSideView { + /** + * 测试函数 + * */ + public static void main(String[] args) { + //TODO + } + + /** + * 循环的方式,相当于层序遍历 + * */ + public List rightSideView(TreeNode root) { + // 从右往左看就是将层序遍历的最后一个元素放入这个list中 + Queue queue = new LinkedList(); + List list = new ArrayList(); + if(root == null) { + return list; + } + queue.offer(root); + while(queue.size() != 0) { + int n = queue.size(); + for(int i = 0; i < n; i++) { + TreeNode cur = queue.poll(); + if(i == 0) { + list.add(cur.val); + } + if(cur.right != null) { + queue.offer(cur.right); + } + if(cur.left != null) { + queue.offer(cur.left); + } + } + } + return list; + } + + /** + * 递归的方法 + * */ + public List rightSideViewII(TreeNode root) { + List result = new ArrayList(); + rightView(root, result, 0); + return result; + } + + public void rightView(TreeNode curr, List result, int currDepth){ + if(curr == null){ + return; + } + if(currDepth == result.size()){ + result.add(curr.val); + } + + rightView(curr.right, result, currDepth + 1); + rightView(curr.left, result, currDepth + 1); + + } +} diff --git a/src/Q206ReverseLinkedList.java b/src/Q206ReverseLinkedList.java index fa0c12f..4d3240d 100644 --- a/src/Q206ReverseLinkedList.java +++ b/src/Q206ReverseLinkedList.java @@ -52,23 +52,23 @@ public static ListNode ReverseList(ListNode head) { return null; } HashMap map = new HashMap(); - ListNode pointer = new ListNode(0); - pointer.next = head; + ListNode dummyHead = new ListNode(0); + dummyHead.next = head; int n = 0; - while(pointer.next != null) { - pointer = pointer.next; - map.put(n,pointer); + while(dummyHead.next != null) { + dummyHead = dummyHead.next; + map.put(n,dummyHead); n++; } n--; head = map.get(n); - pointer = head; + dummyHead = head; while(n > 0) { n--; - pointer.next = map.get(n); - pointer = pointer.next; + dummyHead.next = map.get(n); + dummyHead = dummyHead.next; } - pointer.next = null; + dummyHead.next = null; return head; } diff --git a/src/Q215KthLargestElementinanArray.java b/src/Q215KthLargestElementinanArray.java index 07f55c0..c33ac42 100644 --- a/src/Q215KthLargestElementinanArray.java +++ b/src/Q215KthLargestElementinanArray.java @@ -1,6 +1,8 @@ import java.util.Arrays; +import java.util.PriorityQueue; /** + * 非常重点的题,主要考察Quick Select方法(https://www.jianshu.com/p/52f90fe2b141) * @author ahscuml * @date 2018/10/8 * @time 19:56 @@ -20,6 +22,7 @@ public static void main(String[] args) { System.out.println(findKthLargestIII(nums5, 1)); System.out.println(findKthLargestIV(nums3, 4)); System.out.println(findKthLargestV(nums3, 4)); + System.out.println(findKthLargestVI(nums3, 4)); } /** @@ -122,32 +125,32 @@ public static int quickSelect(int[] nums, int k, int left, int right) { /** * 同样的快速选择算法 但是在paartition操作中使用了双指针技术,所以会更快一点 - * */ + */ public static int findKthLargestV(int[] nums, int k) { - return quickSelectII(nums, nums.length-k, 0, nums.length-1); + return quickSelectII(nums, nums.length - k, 0, nums.length - 1); } - private static int quickSelectII(int[] nums, int k, int left, int right){ + private static int quickSelectII(int[] nums, int k, int left, int right) { // 递归的终止条件,同样也是 - if(left>=right){ + if (left >= right) { return nums[left]; } - // 随机化 - int index = (left+right)/2; + // 随机化, 取中点的值,其实也不是最好的,应该是三点法 + int index = (left + right) / 2; int pivot = nums[index]; int low = left, high = right; // partition 操作 - while(low<=high){ + while (low <= high) { // 如果左边比pivot小,左边不断增加,直到大于pivot - while(low<=high && nums[low]pivot){ + while (low <= high && nums[high] > pivot) { high--; } // 交换high与low - if(low<=high){ + if (low <= high) { int tmp = nums[low]; nums[low] = nums[high]; nums[high] = tmp; @@ -156,17 +159,28 @@ private static int quickSelectII(int[] nums, int k, int left, int right){ } } // 针对K进行递归,由于K是对nums的下标来说的,所以K不用变 - if(k>=low && k<=right){ + if (k >= low && k <= right) { return quickSelectII(nums, k, low, right); - } - else if(k>=left && k<=high){ + } else if (k >= left && k <= high) { return quickSelectII(nums, k, left, high); - } - else{ + } else { return nums[k]; } } + /** + * 这个问题非常适合利用堆来完成,使用一个小顶堆,在Java中就是priority queue + * */ + public static int findKthLargestVI(int[] nums, int k) { + PriorityQueue priorityQueue = new PriorityQueue<>(k); + for(int el : nums) { + priorityQueue.add(el); + if (priorityQueue.size() > k) { + priorityQueue.poll(); + } + } + return priorityQueue.peek(); + } private static void swap(int[] nums, int i, int j) { int temp = nums[i]; diff --git a/src/Q21MergeTwoSortedLists.java b/src/Q21MergeTwoSortedLists.java index 1a7645a..2a7e25c 100644 --- a/src/Q21MergeTwoSortedLists.java +++ b/src/Q21MergeTwoSortedLists.java @@ -1,5 +1,6 @@ /** * 21. Merge Two Sorted Lists + * * @author ahscuml * @date 2018/9/29 * @time 15:16 @@ -7,7 +8,7 @@ public class Q21MergeTwoSortedLists { /** * 测试函数 - * */ + */ public static void main(String[] args) { ListNode listNode1 = new ListNode(1); ListNode listNode2 = new ListNode(2); @@ -26,24 +27,52 @@ public static void main(String[] args) { result = result.next; } } + /** * 递归,相当优秀 - * */ - public static ListNode mergeTwoLists(ListNode l1, ListNode l2){ - if(l1 == null) { + */ + public static ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if (l1 == null) { return l2; } - if(l2 == null) { + if (l2 == null) { return l1; } - if(l1.val < l2.val){ + if (l1.val < l2.val) { l1.next = mergeTwoLists(l1.next, l2); return l1; - } else{ + } else { l2.next = mergeTwoLists(l1, l2.next); return l2; } } + + /** + * 循环的方法,同样也很优秀,只不过长了一点 + * 创建一个dummyHead节点,这是惯用的方法 + */ + public ListNode mergeTwoListsII(ListNode l1, ListNode l2) { + ListNode dummyHead = new ListNode(-1); + ListNode cur = dummyHead; + while (l1 != null && l2 != null) { + if (l1.val < l2.val) { + cur.next = l1; + l1 = l1.next; + } else { + cur.next = l2; + l2 = l2.next; + } + cur = cur.next; + } + if (l1 != null) { + cur.next = l1; + } + if (l2 != null) { + cur.next = l2; + } + return dummyHead.next; + } + /** * 链表的定义 */ diff --git a/src/Q226InvertBinaryTree.java b/src/Q226InvertBinaryTree.java index a3d4c6e..15c7de1 100644 --- a/src/Q226InvertBinaryTree.java +++ b/src/Q226InvertBinaryTree.java @@ -1,3 +1,5 @@ +import util.TreeNode; + import java.util.LinkedList; import java.util.Queue; @@ -91,14 +93,4 @@ private static TreeNode invertTreeIte(TreeNode root) { } return root; } - - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/Q230KthSmallestElementinaBST.java b/src/Q230KthSmallestElementinaBST.java new file mode 100644 index 0000000..5d0945a --- /dev/null +++ b/src/Q230KthSmallestElementinaBST.java @@ -0,0 +1,79 @@ +import util.TreeNode; + +import java.util.ArrayDeque; + +/** + * @author ahscuml + * @date 2019/5/17 + * @time 23:14 + */ +public class Q230KthSmallestElementinaBST { + /** + * 测试函数 + * */ + public static void main(String[] args) { + + } + + /** + * BST的特点就是中序遍历就是顺序的数组 + * 按照中序遍历的结构来完成 + * */ + int count = 0; + int res = -1; + public int kthSmallest(TreeNode root, int k) { + helper(root, k); + return res; + } + + void helper(TreeNode root, int k) { + if(root != null) { + kthSmallest(root.left, k); + if(++count == k) { + res = root.val; + } + kthSmallest(root.right, k); + } + } + + /** + * 利用循环的方法 + * */ + public int kthSmallestIte(TreeNode root, int k) { + TreeNode cur = root; + ArrayDeque stack = new ArrayDeque(); + while(!stack.isEmpty() || cur != null) { + if(cur != null) { + stack.push(cur); + cur = cur.left; + } else { + cur = stack.pop(); + if(--k == 0) { + return cur.val; + } + cur = cur.right; + } + } + return -1; + } + + /** + * 另外一种,利用二分查找,分别统计这个节点的左右节点各有多少个节点,直到找到K个 + * */ + public int kthSmallestIII(TreeNode root, int k) { + int cnt = count(root.left); + if(k <= cnt) { + return kthSmallestIII(root.left, k); + } else if(k > cnt + 1) { + return kthSmallestIII(root.right, k - cnt - 1); + } + return root.val; + } + + int count(TreeNode root) { + if(root == null) { + return 0; + } + return 1 + count(root.left) + count(root.right); + } +} diff --git a/src/Q235LowestCommonAncestorofaBinarySearchTree.java b/src/Q235LowestCommonAncestorofaBinarySearchTree.java new file mode 100644 index 0000000..df4a6fa --- /dev/null +++ b/src/Q235LowestCommonAncestorofaBinarySearchTree.java @@ -0,0 +1,48 @@ +import util.TreeNode; + +/** + * 二叉搜索树的公共祖先 + * + * @author ahscuml + * @date 2019/4/8 + * @time 20:19 + */ +public class Q235LowestCommonAncestorofaBinarySearchTree { + /** + * 测试函数 + */ + public static void main(String[] args) { + // TODO + } + + /** + * 利用BST的特点 + * 利用树递归的性质 + */ + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null) { + return null; + } + if (p.val < root.val && q.val < root.val) { + return lowestCommonAncestor(root.left, p, q); + } else if (p.val > root.val && q.val > root.val) { + return lowestCommonAncestor(root.right, p, q); + } else { + return root; + } + } + + /** + * 利用循环的方法 + */ + public TreeNode lowestCommonAncestorIte(TreeNode root, TreeNode p, TreeNode q) { + while (true) { + if (root == null || (root.val - p.val) * (root.val - q.val) <= 0) return root; + if (p.val < root.val) { + root = root.left; + } else { + root = root.right; + } + } + } +} diff --git a/src/Q236LowestCommonAncestorofaBinaryTree.java b/src/Q236LowestCommonAncestorofaBinaryTree.java new file mode 100644 index 0000000..2268a94 --- /dev/null +++ b/src/Q236LowestCommonAncestorofaBinaryTree.java @@ -0,0 +1,67 @@ +import util.TreeNode; + +import java.util.*; + +/** + * 二叉树最近公共祖先 + * + * @author ahscuml + * @date 2019/4/8 + * @time 19:44 + */ +public class Q236LowestCommonAncestorofaBinaryTree { + /** + * 测试函数 + */ + public static void main(String[] args) { + // TODO + } + + /** + * 循环的方法,记录祖先 + */ + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + Map parent = new HashMap<>(); + Deque stack = new ArrayDeque<>(); + parent.put(root, null); + stack.push(root); + + while (!parent.containsKey(p) || !parent.containsKey(q)) { + TreeNode node = stack.pop(); + if (node.left != null) { + parent.put(node.left, node); + stack.push(node.left); + } + if (node.right != null) { + parent.put(node.right, node); + stack.push(node.right); + } + } + Set ancestors = new HashSet<>(); + while (p != null) { + ancestors.add(p); + p = parent.get(p); + } + while (!ancestors.contains(q)) + q = parent.get(q); + return q; + } + + /** + * 递归的方法 + */ + public TreeNode lowestCommonAncestorRec(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root == p || root == q) { + return root; + } + TreeNode left = lowestCommonAncestorRec(root.left, p, q); + TreeNode right = lowestCommonAncestorRec(root.right, p, q); + if (left == null) { + return right; + } + if (right == null) { + return left; + } + return root; + } +} diff --git a/src/Q23MergekSortedLists.java b/src/Q23MergekSortedLists.java new file mode 100644 index 0000000..5911b52 --- /dev/null +++ b/src/Q23MergekSortedLists.java @@ -0,0 +1,111 @@ +import util.ListNode; + +import java.util.*; + +/** + * @author ahscuml + * @date 2019/4/1 + * @time 18:19 + */ +public class Q23MergekSortedLists { + /** + * 测试函数 + */ + public static void main(String[] args) { + //TODO + } + + /** + * 看到了merge最先想到的就应该是mergesort,针对链表进行mergesort + */ + public ListNode mergeKLists(ListNode[] lists) { + if (lists.length == 0) { + return null; + } + return sort(lists, 0, lists.length - 1); + } + + public ListNode sort(ListNode[] lists, int start, int end) { + if (start == end) { + return lists[start]; + } + int mid = start + (end - start) / 2; + ListNode l1 = sort(lists, start, mid); + ListNode l2 = sort(lists, mid + 1, end); + return merge(l1, l2); + } + + public ListNode merge(ListNode a, ListNode b) { + if (a == null) { + return b; + } + if (b == null) { + return a; + } + if (a.val < b.val) { + a.next = merge(a.next, b); + return a; + } else { + b.next = merge(b.next, a); + return b; + } + } + + /** + * 对于很对元素排序的题还可以应用优先队列,应用优先队列的特性,让优先队列去排序 + * */ + public ListNode mergeKLists(List lists) { + if (lists == null || lists.size() == 0) { + return null; + } + // 优先队列的构造函数,确定大小和初始化构造器,通过构造器来完成排序的工作 + PriorityQueue queue = new PriorityQueue(lists.size(), new Comparator() { + @Override + public int compare(ListNode o1, ListNode o2) { + return o1.val - o2.val; + } + }); + + ListNode dummy = new ListNode(0); + ListNode tail = dummy; + for (ListNode node : lists) { + if (node != null) { + queue.add(node); + } + while (!queue.isEmpty()) { + tail.next = queue.poll(); + tail = tail.next; + // lists里面的ListNode只是一个节点,如果当前节点后面还有节点,那么在放入队列的时候将这个节点之后的节点添加进queue + if (tail.next != null) { + queue.add(tail.next); + } + } + } + return dummy.next; + } + + /** + * 还有一种方法,可以把所有的ListNode的值读出来,读到一个list里,然后进行排序,最后从头到尾进行建立ListNode的操作 + * 这种方法竟然打败了 + * */ + public ListNode mergeKListsIII(ListNode[] lists) { + ArrayList list = new ArrayList(); + for(int i = 0; i < lists.length; i++) { + ListNode cur = lists[i]; + while(cur != null) { + list.add(cur.val); + cur = cur.next; + } + } + Collections.sort(list); + ListNode dummyHead = new ListNode(0); + ListNode cur = dummyHead; + for(int i = 0; i < list.size(); i++) { + + cur.next = new ListNode(list.get(i)); + cur = cur.next; + //cur = null; + } + return dummyHead.next; + } +} diff --git a/src/Q257BinaryTreePaths.java b/src/Q257BinaryTreePaths.java new file mode 100644 index 0000000..afaf10e --- /dev/null +++ b/src/Q257BinaryTreePaths.java @@ -0,0 +1,47 @@ +import util.TreeNode; + +import java.util.ArrayList; +import java.util.List; + +/** + * 二叉树从头到尾的路径 + * @author ahscuml + * @date 2019/4/29 + * @time 13:00 + */ +public class Q257BinaryTreePaths { + /** + * 测试函数 + */ + public static void main(String[] args) { + + } + + /** + * 将StringBuilder作为传递资源完成内容。 + * setLength函数设置长度 + * 最后一个不用加上->,所以需要判断当前节点的左右子节点是否是null + * */ + public List binaryTreePaths(TreeNode root) { + List res = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + helper(res, root, sb); + return res; + } + + private void helper(List res, TreeNode root, StringBuilder sb) { + if (root == null) { + return; + } + int len = sb.length(); + sb.append(root.val); + if (root.left == null && root.right == null) { + res.add(sb.toString()); + } else { + sb.append("->"); + helper(res, root.left, sb); + helper(res, root.right, sb); + } + sb.setLength(len); + } +} diff --git a/src/Q279PerfectSquares.java b/src/Q279PerfectSquares.java index aa4425d..20f0a41 100644 --- a/src/Q279PerfectSquares.java +++ b/src/Q279PerfectSquares.java @@ -18,14 +18,14 @@ public static void main(String[] args) { * 动态规划方法 * */ public static int numSquares(int n) { - int count[] = new int[n + 1]; - Arrays.fill(count, Integer.MAX_VALUE); - count[0] = 0; + int dp[] = new int[n + 1]; + Arrays.fill(dp, Integer.MAX_VALUE); + dp[0] = 0; for(int i = 1; i <= n; i++) { for(int j = 1; j * j <=i; j++) { - count[i] = Math.min(count[i],count[i - j * j] + 1); + dp[i] = Math.min(dp[i],dp[i - j * j] + 1); } } - return count[n]; + return dp[n]; } } diff --git a/src/Q297SerializeandDeserializeBinaryTree.java b/src/Q297SerializeandDeserializeBinaryTree.java new file mode 100644 index 0000000..5177f90 --- /dev/null +++ b/src/Q297SerializeandDeserializeBinaryTree.java @@ -0,0 +1,57 @@ +/** + * @author ahscuml + * @date 2019/5/13 + * @time 23:32 + */ + +import util.TreeNode; + +public class Q297SerializeandDeserializeBinaryTree { + int index = -1; + + /** + * 测试函数 + */ + public static void main(String[] args) { + + } + + /** + * 序列化和反序列化,这是一个运行时间相对优秀的答案 + * 主要利用前序遍历,将一棵树组装成一个String + * 反序列化同理,同样要注意反序列化的顺序 + * */ + private void serializeNode(TreeNode node, StringBuilder sb) { + if (node == null) { + sb.append('#').append(","); + return; + } + sb.append(node.val).append(','); + serializeNode(node.left, sb); + serializeNode(node.right, sb); + } + + // Encodes a tree to a single string. + public String serialize(TreeNode root) { + StringBuilder sb = new StringBuilder(); + serializeNode(root, sb); + return sb.substring(0, sb.length() - 1); + } + + // Decodes your encoded data to tree. + public TreeNode deserialize(String data) { + String[] val = data.split(","); + return buildTree(val); + } + + private TreeNode buildTree(String[] val) { + index++; + TreeNode cur = null; + if (!val[index].equals("#")) { + cur = new TreeNode(Integer.valueOf(val[index])); + cur.left = buildTree(val); + cur.right = buildTree(val); + } + return cur; + } +} diff --git a/src/Q322CoinChange.java b/src/Q322CoinChange.java new file mode 100644 index 0000000..f404ffb --- /dev/null +++ b/src/Q322CoinChange.java @@ -0,0 +1,112 @@ +/** + * @author ahscuml + * @date 2019/3/20 + * @time 17:58 + */ +public class Q322CoinChange { + public static void main(String[] args) { + int[] coins = {1, 2, 5}; + int amount = 11; + System.out.println(coinChange(coins, amount)); + int[] coins1 = {2}; + int amount1 = 3; + System.out.println(coinChange(coins1, amount1)); + int[] coins2 = {2, 5, 10, 1}; + int amount2 = 27; + System.out.println(coinChange(coins2, amount2)); + } + + /** + * 自己写的方法 + * 带最字的都是动态规划的问题,所以可以从动态规划的角度考虑 + * 首先动态规划是划分成子问题,首先找出子问题 + * dp[i][j] 用 coins[0...j]的硬币,完成价格J的最少个数 + */ + public static int coinChange(int[] coins, int target) { + if (coins == null || coins.length < 1 || target < 1) { + return 0; + } + + int[][] dp = new int[coins.length][target + 1]; + for (int i = 0; i < coins.length; i++) { + dp[i][0] = 0; + } + + for (int i = 1; i < target + 1; i++) { + if (i % coins[0] == 0) { + dp[0][i] = i / coins[0]; + } else { + dp[0][i] = Integer.MAX_VALUE; + } + } + + for (int i = 1; i < coins.length; i++) { + for (int j = 1; j < target + 1; j++) { + // 还要处理j - coins[i] < 0的问题 + if (j - coins[i] < 0) { + dp[i][j] = dp[i - 1][j]; + } else { + // 还要处理Integer.MAX_VALUE的问题 + dp[i][j] = dp[i][j - coins[i]] == Integer.MAX_VALUE + ? dp[i - 1][j] : Math.min(dp[i - 1][j], dp[i][j - coins[i]] + 1); + } + } + } + return dp[coins.length - 1][target] == Integer.MAX_VALUE ? -1 : dp[coins.length - 1][target]; + } + + /** + * 循环的方式 + */ + public int coinChange1(int[] coins, int amount) { + if (amount < 1) return 0; + return helper(coins, amount, new int[amount]); + } + + /** + * 递归的方法,自上而下 + * + * @param coins coins we have + * @param rem remainint to change + * @param count the number of coins + */ + private int helper(int[] coins, int rem, int[] count) { + if (rem < 0) return -1; // not valid + if (rem == 0) return 0; // completed + // already computed, so reuse + if (count[rem - 1] != 0) return count[rem - 1]; + int min = Integer.MAX_VALUE; + for (int coin : coins) { + int res = helper(coins, rem - coin, count); + if (res >= 0 && res < min) + min = res + 1; + } + count[rem - 1] = (min == Integer.MAX_VALUE) ? -1 : min; + return count[rem - 1]; + } + + /** + * 循环的方法,就是我的方法的改版,不过用了空间压缩的方法,只用一个一维数组就搞定了 + * 当前金额sum的最小值是金额为sum - coin的最小值加1 + */ + public int coinChange2(int[] coins, int amount) { + if (amount < 1) return 0; + // 当前amount所需的最少的coin次数,长度是amount + 1 + int[] dp = new int[amount + 1]; + // 当前金额 + int sum = 0; + + while (++sum <= amount) { + // 最少的次数,对于一个数值,遍历完一遍coins才知道min + int min = -1; + for (int coin : coins) { + if (sum >= coin && dp[sum - coin] != -1) { + int temp = dp[sum - coin] + 1; + min = min < 0 ? temp : (temp < min ? temp : min); + } + } + dp[sum] = min; + } + return dp[amount]; + } +} diff --git a/src/Q328OddEvenLinkedList.java b/src/Q328OddEvenLinkedList.java new file mode 100644 index 0000000..f681dde --- /dev/null +++ b/src/Q328OddEvenLinkedList.java @@ -0,0 +1,66 @@ +import util.ListNode; + +/** + * @author ahscuml + * @date 2019/4/13 + * @time 10:49 + */ +public class Q328OddEvenLinkedList { + /** + * 测试函数 + */ + public static void main(String[] args) { + // TODO + } + + /** + * 重点是循环条件的判断 + * */ + public static ListNode oddEvenListII(ListNode head) { + // 先找到odd和even的开头?? + if(head == null || head.next == null) { + return head; + } + ListNode even = head.next, curOdd = head, curEven = head.next; + while(curEven != null && curEven.next != null) { + curOdd.next = curEven.next; + curOdd = curOdd.next; + curEven.next = curOdd.next; + curEven = curEven.next; + } + curOdd.next = even; + return head; + } + + + /** + * 这个不是这道题的答案,这个是这个题的变种,关注的是listnode中的值 + */ + public ListNode oddEvenList(ListNode head) { + if (head == null || head.next == null) { + return head; + } + boolean isSwaped = false; + ListNode dummyHead = new ListNode(-1); + dummyHead.next = head; + ListNode cur = dummyHead; + do { + isSwaped = false; + cur = dummyHead; + while (cur.next.next != null) { + if (cur.next.val % 2 == 0 && cur.next.next.val % 2 == 1) { + swapNode(cur, cur.next, cur.next.next); + isSwaped = true; + } + cur = cur.next; + } + } while (isSwaped); + return dummyHead.next; + } + + private void swapNode(ListNode pre, ListNode left, ListNode right) { + left.next = right.next; + right.next = left; + pre.next = right; + } +} diff --git a/src/Q343IntegerBreak.java b/src/Q343IntegerBreak.java new file mode 100644 index 0000000..661f8bc --- /dev/null +++ b/src/Q343IntegerBreak.java @@ -0,0 +1,28 @@ +/** + * @author ahscuml + * @date 2019/4/9 + * @time 0:27 + */ +public class Q343IntegerBreak { + public static void main(String[] args) { + integerBreak(10); + } + + /** + * 需要特殊考虑2和3 + * */ + public static int integerBreak(int n) { + // 这个一看就是动态规划的问题 + // 行就是数字n,列就是最大的乘积 + int[] dp = new int[n + 1]; + dp[0] = 1; + dp[1] = 1; + for (int i = 2; i <= n; i++) { + for (int j = 1; j <= i / 2; j++) { + dp[i] = Math.max(Math.max(dp[i], dp[j] * dp[i - j]), i); + } + System.out.print(dp[i] + " "); + } + return dp[n]; + } +} diff --git a/src/Q347TopKFrequentElements.java b/src/Q347TopKFrequentElements.java index 4180f43..e9e2924 100644 --- a/src/Q347TopKFrequentElements.java +++ b/src/Q347TopKFrequentElements.java @@ -1,7 +1,4 @@ -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; +import java.util.*; /** * @author ahscuml @@ -19,6 +16,7 @@ public static void main(String[] args) { } /** + * 使用桶排序来做这件事情 * 利用HashMap统计频次 * 利用List的数组存储结果 */ @@ -31,6 +29,7 @@ public static List topKFrequent(int[] nums, int k) { } // 遍历存有频率的HashMap,利用存有list的数组bucket 按照频率将元素存储到bucket里 + // 如何遍历HashMap也是一个重点 List[] bucket = new List[nums.length + 1]; for (int i : map.keySet()) { int fre = map.get(i); @@ -49,4 +48,56 @@ public static List topKFrequent(int[] nums, int k) { } return res; } + + /** + * 使用堆来完成任务,也就是PriorityQueue + * */ + public static List topKFrequentII(int[] nums, int k) { + // 利用HahsMap来存储频次 + Map map = new HashMap<>(); + for(int n: nums){ + map.put(n, map.getOrDefault(n,0)+1); + } + + // 优先队列的使用 + PriorityQueue> maxHeap = + new PriorityQueue<>((a,b)->(b.getValue()-a.getValue())); + for(Map.Entry entry: map.entrySet()){ + maxHeap.add(entry); + } + + List res = new ArrayList<>(); + while(res.size() entry = maxHeap.poll(); + res.add(entry.getKey()); + } + return res; + } + + /** + * 使用TreeMap来完成这个任务 + * */ + public static List topKFrequentIII(int[] nums, int k) { + Map map = new HashMap<>(); + for(int n: nums){ + map.put(n, map.getOrDefault(n,0)+1); + } + + TreeMap> freqMap = new TreeMap<>(); + for(int num : map.keySet()){ + int freq = map.get(num); + if(!freqMap.containsKey(freq)){ + freqMap.put(freq, new LinkedList<>()); + } + freqMap.get(freq).add(num); + } + + // 对于TreeMap的使用 + List res = new ArrayList<>(); + while(res.size()> entry = freqMap.pollLastEntry(); + res.addAll(entry.getValue()); + } + return res; + } } diff --git a/src/Q416PartitionEqualSubsetSum.java b/src/Q416PartitionEqualSubsetSum.java new file mode 100644 index 0000000..a9ccef6 --- /dev/null +++ b/src/Q416PartitionEqualSubsetSum.java @@ -0,0 +1,87 @@ +import java.util.Arrays; + +/** + * Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets + * such that the sum of elements in both subsets is equal. + * + * @author ahscuml + * @date 2019/3/20 + * @time 20:02 + */ +public class Q416PartitionEqualSubsetSum { + public static void main(String[] args) { + int[] nums = {1, 5, 11, 5}; + System.out.println(canPartition(nums)); + System.out.println(canPartition1(nums)); + } + + /** + * 0-1背包问题的变形 类似于coins问题??? + * dp[i][j] means whether the specific sum j can be gotten from the first i numbers. + */ + public static boolean canPartition(int[] nums) { + int sum = 0; + for (int num : nums) { + sum += num; + } + // sum的末位不能是奇数,因为奇数不可能分成两个相等的内容 + if ((sum & 1) == 1) { + return false; + } + sum /= 2; + int n = nums.length; + boolean[][] dp = new boolean[n + 1][sum + 1]; + /** + * ii的地方全填成false? + * */ + for (int i = 0; i < dp.length; i++) { + Arrays.fill(dp[i], false); + } + dp[0][0] = true; + // 和为0的 + for (int i = 1; i < n + 1; i++) { + dp[i][0] = true; + } + // 不使用元素的 + for (int j = 1; j < sum + 1; j++) { + dp[0][j] = false; + } + for (int i = 1; i < n + 1; i++) { + for (int j = 1; j < sum + 1; j++) { + // 不用当前这个元素 + dp[i][j] = dp[i - 1][j]; + // j是sum, + if (j >= nums[i - 1]) { + dp[i][j] = (dp[i][j] || dp[i - 1][j - nums[i - 1]]); + } + } + } + return dp[n][sum]; + } + + /** + * 上面方法的优化,使用一维数组 + * */ + public static boolean canPartition1(int[] nums) { + int sum = 0; + for (int num : nums) { + sum += num; + } + if ((sum & 1) == 1) { + return false; + } + sum /= 2; + boolean[] dp = new boolean[sum + 1]; + // 数组的初始化 + Arrays.fill(dp, false); + dp[0] = true; + for (int num : nums) { + for (int i = sum; i > 0; i--) { + if (i >= num) { + dp[i] = dp[i] || dp[i - num]; + } + } + } + return dp[sum]; + } +} diff --git a/src/Q437PathSumIII.java b/src/Q437PathSumIII.java index e2719f5..49e5b3c 100644 --- a/src/Q437PathSumIII.java +++ b/src/Q437PathSumIII.java @@ -1,3 +1,5 @@ +import util.TreeNode; + import java.util.HashMap; /** @@ -45,14 +47,4 @@ public static int helper(TreeNode root, int currSum, int target, HashMap spiralOrder(int[][] matrix) { + List res = new ArrayList(); + if (matrix.length == 0) { + return res; + } + int rowBegin = 0, rowEnd = matrix.length - 1, colBegin = 0, colEnd = matrix[0].length - 1; + while (rowBegin <= rowEnd && colBegin <= colEnd) { + // 打印rowBegin行,从colBegin到colEnd + for (int i = colBegin; i <= colEnd; i++) { + res.add(matrix[rowBegin][i]); + } + rowBegin++; + // 打印colEnd列 + // 这里值变换了rowBegin而且后面还是比较row,所以不用判断 + for (int i = rowBegin; i <= rowEnd; i++) { + res.add(matrix[i][colEnd]); + } + colEnd--; + + // 打印 rowEnd行 + // 这里要比较row + if (rowBegin <= rowEnd) { + for (int i = colEnd; i >= colBegin; i--) { + res.add(matrix[rowEnd][i]); + } + } + rowEnd--; + + // 打印colBegin列 + // 这里要比较col,因为前面改过col + if (colBegin <= colEnd) { + for (int i = rowEnd; i >= rowBegin; i--) { + res.add(matrix[i][colBegin]); + } + } + colBegin++; + } + return res; + } + + /** + * 第二种方法,可能更加方便记忆 + */ + public static List spiralOrderII(int[][] matrix) { + List res = new ArrayList(); + if (matrix.length == 0 || matrix[0].length == 0) return res; + + int top = 0; + int bottom = matrix.length - 1; + int left = 0; + int right = matrix[0].length - 1; + + while (true) { + for (int i = left; i <= right; i++) res.add(matrix[top][i]); + top++; + if (left > right || top > bottom) break; + + for (int i = top; i <= bottom; i++) res.add(matrix[i][right]); + right--; + if (left > right || top > bottom) break; + + for (int i = right; i >= left; i--) res.add(matrix[bottom][i]); + bottom--; + if (left > right || top > bottom) break; + + for (int i = bottom; i >= top; i--) res.add(matrix[i][left]); + left++; + if (left > right || top > bottom) break; + } + + return res; + } +} diff --git a/src/Q572SubtreeofAnotherTree.java b/src/Q572SubtreeofAnotherTree.java index d512e24..d82a579 100644 --- a/src/Q572SubtreeofAnotherTree.java +++ b/src/Q572SubtreeofAnotherTree.java @@ -1,3 +1,5 @@ +import util.TreeNode; + import java.util.LinkedList; import java.util.Queue; @@ -74,17 +76,4 @@ private static boolean check(TreeNode s, TreeNode t) { } return false; } - - /** - * 树结构的定义 - */ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/Q617MergeTwoBinaryTrees.java b/src/Q617MergeTwoBinaryTrees.java index cde7740..ed0e1bf 100644 --- a/src/Q617MergeTwoBinaryTrees.java +++ b/src/Q617MergeTwoBinaryTrees.java @@ -1,4 +1,8 @@ +import util.TreeNode; + /** + * TODO 循环的方法 + * * @author ahscuml * @date 2018/11/26 * @time 15:09 @@ -49,7 +53,6 @@ public static TreeNode mergeTrees(TreeNode t1, TreeNode t2) { return newNode; } - /** * 中序遍历, 递归 打印这个树 */ @@ -63,15 +66,18 @@ private static void inOrderRec(TreeNode root) { } /** - * 树结构的定义 + * 自己写的递归方法,时间复杂度O(n) */ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; + public TreeNode mergeTreesII(TreeNode t1, TreeNode t2) { + if (t1 == null) { + return t2; + } + if (t2 == null) { + return t1; } + t1.val = t1.val + t2.val; + t1.left = mergeTrees(t1.left, t2.left); + t1.right = mergeTrees(t1.right, t2.right); + return t1; } } diff --git a/src/Q637AverageofLevelsinBinaryTree.java b/src/Q637AverageofLevelsinBinaryTree.java new file mode 100644 index 0000000..a4f0dd6 --- /dev/null +++ b/src/Q637AverageofLevelsinBinaryTree.java @@ -0,0 +1,50 @@ +import util.TreeNode; + +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * @author ahscuml + * @date 2019/4/29 + * @time 12:22 + */ +public class Q637AverageofLevelsinBinaryTree { + /** + * 测试函数 + */ + public static void main(String[] args) { + + } + + /** + * 层序遍历,统计这一层的值,除就可以了 + */ + public List averageOfLevels(TreeNode root) { + List list = new LinkedList(); + if (root == null) { + return list; + } + Queue queue = new LinkedList<>(); + TreeNode cur = null; + queue.offer(root); + while (!queue.isEmpty()) { + int count = queue.size(); + int n = count; + double sum = 0; + while (count > 0) { + cur = queue.poll(); + sum += cur.val; + if (cur.left != null) { + queue.offer(cur.left); + } + if (cur.right != null) { + queue.offer(cur.right); + } + count--; + } + list.add(sum / n); + } + return list; + } +} diff --git a/src/Q64MinimumPathSum.java b/src/Q64MinimumPathSum.java index a84c9b3..70743ee 100644 --- a/src/Q64MinimumPathSum.java +++ b/src/Q64MinimumPathSum.java @@ -9,20 +9,21 @@ public static void main(String[] args) { {1, 5, 1}, {4, 2, 1}}; System.out.println(minPathSum(nums)); + System.out.println(minPathSumII(nums)); } /** * 依旧使用动态规划,和62,63一样的想法。 * 可以不使用额外的存储空间,直接将内容存储到matrix中,可以试试这个想法。 - * */ + */ public static int minPathSum(int[][] matrix) { int n = matrix[0].length; int[] aux = new int[n]; - for(int i = 0; i < matrix.length; i++) { - for(int j = 0; j < n; j++) { + for (int i = 0; i < matrix.length; i++) { + for (int j = 0; j < n; j++) { if (j == 0) { aux[j] = aux[j] + matrix[i][j]; - } else if(i == 0){ + } else if (i == 0) { aux[j] = aux[j - 1] + matrix[i][j]; } else { aux[j] = matrix[i][j] + Math.min(aux[j - 1], aux[j]); @@ -31,4 +32,28 @@ public static int minPathSum(int[][] matrix) { } return aux[n - 1]; } + + /** + * 动态规划的方法,只不过采用的是二维的数组,最基本的想法 + * 注意创建辅助数组的时候的长度以及创建完成以后首先对00赋值 + */ + public static int minPathSumII(int[][] grid) { + if (grid.length == 0 || grid[0].length == 0) { + return 0; + } + int[][] dp = new int[grid.length][grid[0].length]; + dp[0][0] = grid[0][0]; + for (int i = 1; i < grid.length; i++) { + dp[i][0] = grid[i][0] + dp[i - 1][0]; + } + for (int i = 1; i < grid[0].length; i++) { + dp[0][i] = grid[0][i] + dp[0][i - 1]; + } + for (int i = 1; i < grid.length; i++) { + for (int j = 1; j < grid[0].length; j++) { + dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]; + } + } + return dp[grid.length - 1][grid[0].length - 1]; + } } diff --git a/src/Q718MaximumLengthofRepeatedSubarray.java b/src/Q718MaximumLengthofRepeatedSubarray.java new file mode 100644 index 0000000..472ebfe --- /dev/null +++ b/src/Q718MaximumLengthofRepeatedSubarray.java @@ -0,0 +1,34 @@ +/** + * @author ahscuml + * @date 2019/4/9 + * @time 0:54 + */ +public class Q718MaximumLengthofRepeatedSubarray { + /** + * 测试函数 + */ + public static void main(String[] args) { + int[] A = {1, 2, 3, 2, 1}; + int[] B = {3, 2, 1, 4, 7}; + System.out.println(findLength(A, B)); + } + + /** + * 动态规划 + * 找到规律,也就是递推关系式很好处理 + */ + public static int findLength(int[] A, int[] B) { + int res = 0; + // DP问题 + int[][] dp = new int[A.length + 1][B.length + 1]; + for (int i = 1; i < dp.length; i++) { + for (int j = 1; j < dp[0].length; j++) { + if (A[i - 1] == B[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1; + res = Math.max(res, dp[i][j]); + } + } + } + return res; + } +} diff --git a/src/Q83RemoveDuplicatesfromSortedList.java b/src/Q83RemoveDuplicatesfromSortedList.java new file mode 100644 index 0000000..6508961 --- /dev/null +++ b/src/Q83RemoveDuplicatesfromSortedList.java @@ -0,0 +1,53 @@ +import util.ListNode; + +/** + * @author ahscuml + * @date 2019/4/1 + * @time 0:09 + */ +public class Q83RemoveDuplicatesfromSortedList { + /** + * 测试函数 + */ + public static void main(String[] args) { + ListNode l1 = new ListNode(1); + ListNode l2 = new ListNode(1); + ListNode l3 = new ListNode(2); + ListNode l4 = new ListNode(3); + ListNode l5 = new ListNode(3); + l1.next = l2; + l2.next = l3; + l3.next = l4; + l4.next = l5; + ListNode cur = deleteDuplicatesII(l1); + while (cur != null) { + System.out.print(cur.val + " "); + cur = cur.next; + } + + } + + /** + * 递归的方法,非常不建议使用,因为会产生栈的溢出 + */ + public static ListNode deleteDuplicates(ListNode head) { + if (head == null || head.next == null) return head; + head.next = deleteDuplicates(head.next); + return head.val == head.next.val ? head.next : head; + } + + /** + * 常规的解法,时间复杂度O(n),空间复杂度O(1) + */ + public static ListNode deleteDuplicatesII(ListNode head) { + ListNode cur = head; + while (cur != null && cur.next != null) { + if (cur.val == cur.next.val) { + cur.next = cur.next.next; + } else { + cur = cur.next; + } + } + return head; + } +} diff --git a/src/Q86PartitionList.java b/src/Q86PartitionList.java index 2ad888f..6381319 100644 --- a/src/Q86PartitionList.java +++ b/src/Q86PartitionList.java @@ -50,6 +50,45 @@ public static ListNode partition(ListNode head, int x) { return smallHead.next; } + /** + * 空间复杂度O(1),时间复杂度O(n) + * 在链表内部调整,找到一个小的,就把这个小的放到前面。 + * */ + public ListNode partitionII(ListNode head, int x) { + // 循环的方法 + // 存3个节点,一个是pre,一个cur,还有一个小数字的尾节点 + if(head == null) { + return head; + } + ListNode dummyHead = new ListNode(-1); + dummyHead.next = head; + ListNode cur = head; + ListNode pre = dummyHead; + ListNode tail = dummyHead; + while(cur != null) { + if(cur.val < x) { + if(tail == pre) { + cur = cur.next; + pre = pre.next; + tail = tail.next; + } else { + // 摘链 + pre.next = cur.next; + // 插入 + cur.next = tail.next; + tail.next = cur; + tail = cur; + cur = pre.next; + } + + } else { + cur = cur.next; + pre = pre.next; + } + } + return dummyHead.next; + } + public static class ListNode { int val; ListNode next; diff --git a/src/Q946ValidateStackSequences.java b/src/Q946ValidateStackSequences.java new file mode 100644 index 0000000..0663f19 --- /dev/null +++ b/src/Q946ValidateStackSequences.java @@ -0,0 +1,36 @@ +import java.util.Stack; + +/** + * @author ahscuml + * @date 2019/4/13 + * @time 18:52 + */ +public class Q946ValidateStackSequences { + /** + * + * */ + public static void main(String[] args) { + int[] pushed = {1, 2, 3, 4, 5}; + int[] popped = {4, 5, 3, 2, 1}; + System.out.println(validateStackSequences(pushed, popped)); + } + + /** + * 很简单的思想,不过记得stack要先push + * */ + public static boolean validateStackSequences(int[] pushA, int[] popA) { + Stack stack = new Stack(); + int j = 0; + for (int i = 0; i < pushA.length; i++) { + stack.push(pushA[i]); + while (!stack.isEmpty() && stack.peek() == popA[j]) { + j++; + stack.pop(); + } + } + if (stack.isEmpty()) { + return true; + } + return false; + } +} diff --git a/src/Q94BinaryTreeInorderTraversal.java b/src/Q94BinaryTreeInorderTraversal.java index 6f076d9..7232cb3 100644 --- a/src/Q94BinaryTreeInorderTraversal.java +++ b/src/Q94BinaryTreeInorderTraversal.java @@ -1,3 +1,5 @@ +import util.TreeNode; + import java.util.ArrayList; import java.util.List; import java.util.Stack; @@ -64,14 +66,4 @@ public static List inorderTraversal2(TreeNode root) { } return res; } - - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/Q95UniqueBinarySearchTreesII.java b/src/Q95UniqueBinarySearchTreesII.java new file mode 100644 index 0000000..593398b --- /dev/null +++ b/src/Q95UniqueBinarySearchTreesII.java @@ -0,0 +1,95 @@ +import util.TreeNode; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author ahscuml + * @date 2019/4/5 + * @time 15:46 + */ +public class Q95UniqueBinarySearchTreesII { + public static void main(String[] args) { + //TODO 测试用例 + } + + /** + * 优化后的方法,也就是利用动态规划的特性,用空间换时间,将之前的内容存储起来 + * 同时应用了一个小trick,左子树可以直接从之前的子树移动过来。 + */ + public static List generateTreesII(int n) { + List[] res = new List[n + 1]; + res[0] = new ArrayList<>(); + if (n == 0) { + return res[0]; + } + // 赋值空 + res[0].add(null); + // 1-i产生的结果 + for (int i = 1; i <= n; i++) { + res[i] = new ArrayList(); + // j是左子树的元素个数 + for (int j = 0; j < i; j++) { + for (TreeNode left : res[j]) { + for (TreeNode right : res[i - j - 1]) { + // 根节点的值 + TreeNode root = new TreeNode(j + 1); + root.left = left; + root.right = clone(right, j + 1); + res[i].add(root); + } + } + } + } + return res[n]; + } + + /** + * 节省空间,将从1开始的子树通过加上offset拷贝过来。因为右子树是从 offset + 1 开始的 + */ + public static TreeNode clone(TreeNode n, int offset) { + if (n == null) { + return null; + } + TreeNode node = new TreeNode(n.val + offset); + node.left = clone(n.left, offset); + node.right = clone(n.right, offset); + return node; + } + + /** + * 暴力解法:通过辅助函数来完成(依然打败了63%) + * 缺点是没有利用之前存储的内容来进行计算 + */ + public List generateTrees(int n) { + List res = new ArrayList<>(); + if (n == 0) { + return res; + } + return generateHelper(1, n); + } + + /** + * 辅助函数的主要思路是分别得出左右子树的可能性,然后将这些子树拼接到一起,加入结果集 + */ + public List generateHelper(int s, int e) { + List res = new ArrayList<>(); + if (s > e) { + res.add(null); + return res; + } + for (int i = s; i <= e; i++) { + List left = generateHelper(s, i - 1); + List right = generateHelper(i + 1, e); + for (TreeNode l : left) { + for (TreeNode r : right) { + TreeNode root = new TreeNode(i); + root.left = l; + root.right = r; + res.add(root); + } + } + } + return res; + } +} diff --git a/src/Q96UniqueBinarySearchTrees.java b/src/Q96UniqueBinarySearchTrees.java index 9cd7299..7b35601 100644 --- a/src/Q96UniqueBinarySearchTrees.java +++ b/src/Q96UniqueBinarySearchTrees.java @@ -15,6 +15,7 @@ public static void main(String[] args) { /** * 空间换时间,记录之前的结果 + * 卡塔兰数的一个例子 */ public int numTrees(int n) { // 二叉搜索树要满足左小右大的条件 diff --git a/src/Q97InterleavingString.java b/src/Q97InterleavingString.java new file mode 100644 index 0000000..f957861 --- /dev/null +++ b/src/Q97InterleavingString.java @@ -0,0 +1,37 @@ +/** + * @author ahscuml + * @date 2019/3/16 + * @time 9:00 + */ +public class Q97InterleavingString { + + /** + * DP的方法 + * 首先要明白子问题是什么 + * 空间换时间,空间的意义是什么 + */ + public boolean isInterleave(String s1, String s2, String s3) { + if ((s1.length() + s2.length()) != s3.length()) { + return false; + } + // 需要存储的空间 + boolean[][] matrix = new boolean[s2.length() + 1][s1.length() + 1]; + matrix[0][0] = true; + // 初始化第一行 + for (int i = 1; i < matrix[0].length; i++) { + matrix[0][i] = matrix[0][i - 1] && (s1.charAt(i - 1) == s3.charAt(i - 1)); + } + // 初始化第一列 + for (int i = 1; i < matrix.length; i++) { + matrix[i][0] = matrix[i - 1][0] && (s2.charAt(i - 1) == s3.charAt(i - 1)); + } + // 利用之前的计算填充二维数组 + for (int i = 1; i < matrix.length; i++) { + for (int j = 1; j < matrix[0].length; j++) { + matrix[i][j] = (matrix[i - 1][j] && (s2.charAt(i - 1) == s3.charAt(i + j - 1))) + || (matrix[i][j - 1] && (s1.charAt(j - 1) == s3.charAt(i + j - 1))); + } + } + return matrix[s2.length()][s1.length()]; + } +} diff --git a/src/Q98ValidateBinarySearchTree.java b/src/Q98ValidateBinarySearchTree.java index 6685824..c78e278 100644 --- a/src/Q98ValidateBinarySearchTree.java +++ b/src/Q98ValidateBinarySearchTree.java @@ -1,7 +1,10 @@ +import util.TreeNode; + import java.util.Stack; /** * 二叉搜索树是不是合理的 + * * @author ahscuml * @date 2018/12/28 * @time 16:34 @@ -54,17 +57,4 @@ public boolean isValidBSTIte(TreeNode root) { } return true; } - - /** - * 树结构的定义 - */ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/TEST/InOrder.java b/src/TEST/InOrder.java index f5c0651..76ef4f6 100644 --- a/src/TEST/InOrder.java +++ b/src/TEST/InOrder.java @@ -1,5 +1,7 @@ package TEST; +import util.TreeNode; + import java.util.Stack; /** @@ -71,17 +73,4 @@ private static void inOrderIte(TreeNode root) { } } } - - /** - * 树结构的定义 - */ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/TEST/LevelOrder.java b/src/TEST/LevelOrder.java index 03bee31..70957d1 100644 --- a/src/TEST/LevelOrder.java +++ b/src/TEST/LevelOrder.java @@ -1,5 +1,7 @@ package TEST; +import util.TreeNode; + import java.util.LinkedList; import java.util.Queue; @@ -153,18 +155,4 @@ public static void levelOrderIte(TreeNode root) { } } } - - - /** - * 树结构的定义 - */ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/TEST/PostOrder.java b/src/TEST/PostOrder.java index 69b86ff..b40595c 100644 --- a/src/TEST/PostOrder.java +++ b/src/TEST/PostOrder.java @@ -1,5 +1,7 @@ package TEST; +import util.TreeNode; + import java.util.Stack; /** @@ -42,7 +44,7 @@ private static void postOrderRec(TreeNode root) { /*if (root == null) { return; }*/ - if(root!=null){ + if (root != null) { postOrderRec(root.left); postOrderRec(root.right); System.out.print(root.val); @@ -63,9 +65,9 @@ private static void postOrderIte(TreeNode root) { Stack output = new Stack<>(); TreeNode cur = root; - while (cur != null || !stack.isEmpty()) { + while (cur != null || !stack.isEmpty()) { if (cur != null) { - output.push(cur); + output.push(cur); stack.push(cur); // 先进后出,所以先是右边 cur = cur.right; @@ -80,17 +82,4 @@ private static void postOrderIte(TreeNode root) { System.out.print(output.pop().val); } } - - /** - * 树结构的定义 - */ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/TEST/PreOrder.java b/src/TEST/PreOrder.java index 15604d1..1d2ed9d 100644 --- a/src/TEST/PreOrder.java +++ b/src/TEST/PreOrder.java @@ -1,5 +1,7 @@ package TEST; +import util.TreeNode; + import java.util.Stack; /** @@ -73,17 +75,4 @@ public static void preorderIte(TreeNode root) { } } } - - /** - * 树结构的定义 - */ - public static class TreeNode { - int val; - TreeNode left; - TreeNode right; - - TreeNode(int x) { - val = x; - } - } } diff --git a/src/util/ListNode.java b/src/util/ListNode.java new file mode 100644 index 0000000..d529e10 --- /dev/null +++ b/src/util/ListNode.java @@ -0,0 +1,15 @@ +package util; + +/** + * @author ahscuml + * @date 2019/4/1 + * @time 0:10 + */ +public class ListNode { + public int val; + public ListNode next; + + public ListNode(int x) { + val = x; + } +} diff --git a/src/util/RandomNode.java b/src/util/RandomNode.java new file mode 100644 index 0000000..ab84fd6 --- /dev/null +++ b/src/util/RandomNode.java @@ -0,0 +1,20 @@ +package util; + +/** + * @author ahscuml + * @date 2019/4/17 + * @time 21:40 + */ +public class RandomNode { + public int val; + public RandomNode next; + public RandomNode random; + + public RandomNode() {} + + public RandomNode(int _val,RandomNode _next,RandomNode _random) { + val = _val; + next = _next; + random = _random; + } +}