├── .gitignore ├── README.md ├── codes └── java_dataStructure_luozhaoyong │ ├── 1.bmp │ ├── 2.zip │ ├── 3.bmp │ ├── README.md │ └── src │ ├── demo1 │ ├── AddOneToHundred.java │ ├── TestArray.java │ ├── TestBinarySearch.java │ ├── TestMyArray.java │ ├── TestMyArraySearch.java │ ├── TestOpArray.java │ ├── TestOpArray2.java │ ├── TestSearch.java │ └── util │ │ └── MyArray.java │ ├── demo10 │ ├── Node.java │ └── TestHuffmanCode.java │ ├── demo11 │ ├── BinarySortTree.java │ ├── Node.java │ └── TestBinarySortTree.java │ ├── demo12 │ ├── BinarySortTree.java │ ├── Node.java │ └── TestBinarySortTree.java │ ├── demo13 │ ├── HashTable.java │ ├── StuInfo.java │ └── TestHashTable.java │ ├── demo14 │ ├── Graph.java │ ├── TestGraph.java │ └── Vertex.java │ ├── demo2 │ ├── DoubleNode.java │ ├── LoopNode.java │ ├── MyQueue.java │ ├── MyStack.java │ ├── Node.java │ ├── TestLoopNode.java │ └── test │ │ ├── TestDoubleNode.java │ │ ├── TestLoopNode.java │ │ ├── TestMyQueue.java │ │ ├── TestMyStack.java │ │ └── TestNode.java │ ├── demo3 │ ├── TestFibonacci.java │ ├── TestHanoi.java │ └── TestRecursive.java │ ├── demo4 │ ├── BubbleSort.java │ ├── HeapSort.java │ ├── InsertSort.java │ ├── MergeSort.java │ ├── QuickSort.java │ ├── RadixQueueSort.java │ ├── RadixSort.java │ ├── SelectionSort.java │ └── ShellSort.java │ ├── demo5 │ ├── BinaryTree.java │ ├── TestBinaryTree.java │ └── TreeNode.java │ ├── demo6 │ ├── ArrayBinaryTree.java │ └── TestArrayBinaryTree.java │ ├── demo7 │ ├── TestThreadedBinaryTree.java │ ├── ThreadedBinaryTree.java │ └── ThreadedNode.java │ └── demo9 │ ├── Node.java │ └── TestHuffmanTree.java ├── contribute.md └── solutions ├── README.md ├── images ├── 017_Telephone-keypad2.png ├── 160_example_1.png ├── 160_example_2.png ├── 160_example_3.png └── 160_statement.png ├── leetcode ├── 001-twoSum │ ├── README.md │ ├── hatrick.md │ └── woody.md ├── 002-addTwoNumber │ ├── README.md │ └── monkey.md ├── 003-longestSubstringWithoutRepeatingCharacters │ ├── README.md │ ├── monkey.md │ └── zengdiqing1994.md ├── 005-LongestPalindromicSubstring │ ├── hatrick.md │ └── official.md ├── 006-ZigZagConversion │ ├── README.md │ └── zengdiqing.md ├── 015-threeSum │ ├── hatrick.md │ └── official.md ├── 017-LetterCombinationsOfAPhoneNumber │ └── README.md ├── 020-validParentheses │ └── official.md ├── 023-MergeKSortedLists │ └── README.md ├── 024-swapNodesInPairs │ └── official.md ├── 025-reverseNodesInKGroup │ ├── bigablecat.md │ └── official.md ├── 032-LongestValidParentheses │ └── official.md ├── 033-SearchInRotatedSortedArray │ ├── README.md │ └── zengdiqing1994.md ├── 036-ValidSudoku │ ├── SpecialYang.md │ └── official.md ├── 037-SudokuSolver │ ├── SpecialYang.md │ └── official.md ├── 048-RotateImage │ ├── README.md │ └── zengdiqing.md ├── 050-powxN │ └── bigablecat.md ├── 051-NQueens │ ├── melody-l.md │ └── official.md ├── 052-N-QueensII │ ├── hatrick.md │ └── official.md ├── 053-maximumSubarray │ ├── BambooYH.md │ ├── README.md │ └── zengdiqing1994.md ├── 054-SpiralMatrix │ ├── README.md │ └── zengdiqing1994.md ├── 059-SpiralMatrixII │ ├── README.md │ └── zengdiqing1994.md ├── 062-UniquePaths │ ├── BambooYH.md │ └── official.md ├── 063-UniquePathsII │ ├── SpecialYang.md │ └── official.md ├── 064-minimumPathSum │ ├── README.md │ └── melody-l.md ├── 069-SqrtX │ ├── README.md │ └── bigablecat.md ├── 070-ClimbingStairs │ ├── README.md │ └── melody-l.md ├── 072-EditDistance │ └── official.md ├── 075-SortColors │ ├── README.md │ └── bigablecat.md ├── 076-MinimumWindowSubstring │ └── README.md ├── 085-MaximalRectangle │ └── passself.md ├── 087-ScrambleString │ └── official.md ├── 091-DecodeWays │ ├── melody-l.md │ ├── official.md │ └── sandao.md ├── 095-UniqueBinarySearchTreesII │ ├── melody-l.md │ └── official.md ├── 096-uniqueBinarySearchTrees │ └── official.md ├── 097-InterleavingString │ └── official.md ├── 098-validateBinarySearchTree │ └── BambooYH.md ├── 102-BinaryTreeLevelOrderTraversal │ ├── SpecialYang.md │ ├── hatrick.md │ ├── official.md │ └── zengdiqing1994.md ├── 104-MaximumDepthOfBinaryTree │ ├── melody-l.md │ └── official.md ├── 110-BalancedBinaryTree │ ├── README.md │ ├── bigablecat.md │ └── zengdiqing1994.md ├── 115-DistinctSubsequences │ └── official.md ├── 120-Triangle │ ├── melody-l.md │ └── official.md ├── 121-bestTimeToBuyAndSellStock │ ├── bigablecat.md │ └── official.md ├── 122-bestTimeToBuyAndSellStockII │ ├── SpecialYang.md │ └── bigablecat.md ├── 123-BestTimeToBuyAndSellStockIII │ ├── SpecialYang.md │ └── official.md ├── 131-PalindromePartitioning │ └── official.md ├── 132-PalindromePartitioningII │ └── official.md ├── 139-WordBreak │ └── official.md ├── 140-WordBreakII │ └── official.md ├── 141-linkedListCycle │ └── official.md ├── 142-linkedListCycleII │ ├── bigablecat.md │ └── official.md ├── 144-BinaryTreePreorderTraversal │ ├── README.md │ └── bigablecat.md ├── 146-lruCache │ ├── hatrick.md │ └── official.md ├── 152-MaximumProductSubarray │ ├── README.md │ ├── SpecialYang.md │ └── zengdiqing1994.md ├── 153-FindMinimumInRotatedSortedArray │ ├── README.md │ └── zengdiqing1994.md ├── 160-IntersectionOfTwoLinkedLists │ ├── README.md │ └── bigablecat.md ├── 167-TwoSumII │ ├── README.md │ └── bigablecat.md ├── 169-majorityElement │ ├── README.md │ ├── SpecialYang.md │ ├── bigablecat.md │ └── zengdiqing1994.md ├── 174-DungeonGame │ └── passself.md ├── 188-bestTimeToBuyAndSellStockIV │ ├── BambooYH.md │ └── official.md ├── 191-NumberOf1Bits │ ├── README.md │ └── bigablecat.md ├── 198-houseRobber │ ├── README.md │ └── hatrick.md ├── 200-numberOfIslands │ ├── BambooYH.md │ └── official.md ├── 206-reverseLinkedList │ └── official.md ├── 207-CourseSchedule │ ├── README.md │ └── bigablecat.md ├── 208-implementTriePrefixTree │ ├── README.md │ └── bigablecat.md ├── 212-wordSearchII │ └── official.md ├── 213-HouseRobberII │ ├── SpecialYang.md │ └── official.md ├── 215-KthLargestElementInAnArray │ ├── BambooYH.md │ ├── README.md │ └── bigablecat.md ├── 221-MaximalSquare │ └── official.md ├── 225-implementStackUsingQueues │ ├── hatrick.md │ └── official.md ├── 230-KthSmallestElementInABST │ ├── README.md │ └── bigablecat.md ├── 231-PowerOfTwo │ ├── hatrick.md │ └── official.md ├── 232-implementQueueUsingStacks │ ├── README.md │ └── hatrick.md ├── 236-lowestCommonAncestorOfABinaryTree │ └── BambooYH.md ├── 239-slidingWindowMaximum │ └── official.md ├── 241-DifferentWaysToAddParentheses │ ├── README.md │ └── bigablecat.md ├── 242-ValidAnagram │ ├── README.md │ ├── bigablecat.md │ └── zengdiqing1994.md ├── 260-SingleNumberIII │ ├── README.md │ └── zengdiqing1994.md ├── 264-UglyNumberII │ ├── bigablecat.md │ └── official.md ├── 279-PerfectSquares │ ├── README.md │ ├── bigablecat.md │ └── zengdiqing1994.md ├── 295-FindMedianFromDataStream │ └── BambooYH.md ├── 300-LongestIncreasingSubsequence │ ├── README.md │ └── melody-l.md ├── 303-rangeSumQueryImmutable │ ├── BambooYH.md │ └── README.md ├── 304-RangeSumQuery2DImmutable │ ├── official.md │ └── woody.md ├── 309-BestTimeToBuyAndSellStockWithCooldown │ ├── README.md │ └── bigablecat.md ├── 312-BurstBalloons │ ├── melody-l.md │ └── official.md ├── 321-CreateMaximumNumber │ └── README.md ├── 322-CoinChange │ └── official.md ├── 338-CountingBits │ └── bigablecat.md ├── 343-IntegerBreak │ ├── README.md │ └── hatrick.md ├── 347-TopKFrequentElements │ ├── README.md │ └── bigablecat.md ├── 354-RussianDollEnvelopes │ ├── official.md │ └── zengdiqing1994.md ├── 357-CountNumbersWithUniqueDigits │ └── official.md ├── 363-MaxSumOfRectangleNoLargerThanK │ └── official.md ├── 367-ValidPerfectSquare │ └── official.md ├── 368-LargestDivisibleSubset │ └── passself.md ├── 374-GuessNumberHigherOrLower │ └── official.md ├── 375-GuessNumberHigherOrLowerII │ └── official.md ├── 376-WiggleSubsequence │ ├── melody-l.md │ └── official.md ├── 377-CombinationSumIV │ └── official.md ├── 378-KthSmallestElementInASortedMatrix │ ├── README.md │ └── zengdiqing1994.md ├── 392-IsSubsequence │ ├── official.md │ └── zengdiqing1994.md ├── 403-FrogJump │ └── README.md ├── 409-LongestPalindrome │ ├── README.md │ └── zengdiqing1994.md ├── 410-SplitArrayLargestSum │ ├── hatrick.md │ └── official.md ├── 413-arithmeticSlices │ └── official.md ├── 416-PartitionEqualSubsetSum │ ├── README.md │ └── bigablecat.md ├── 446-ArithmeticSlicesIISubsequence │ └── official.md ├── 455-AssignCookies │ ├── README.md │ ├── SpecialYang.md │ └── bigablecat.md ├── 462-MinimumMovesToEqualArrayElementsII │ ├── README.md │ └── zengdiqing1994.md ├── 464-CanIWin │ └── official.md ├── 467-UniqueSubstringsInWraparoundString │ └── passself.md ├── 472-ConcatenatedWords │ └── official.md ├── 474-OnesAndZeroes │ ├── hatrick.md │ └── official.md ├── 486-PredictTheWinner │ └── official.md ├── 494-TargetSum │ └── official.md ├── 504-Base7 │ ├── README.md │ └── zengdiqing1994.md ├── 513-FindBottomLeftTreeValue │ ├── README.md │ ├── bigablecat.md │ └── zengdiqing1994.md ├── 514-FreedomTrail │ ├── hatrick.md │ └── official.md ├── 516-LongestPalindromicSubsequence │ └── passself.md ├── 517-SuperWashingMachines │ └── official.md ├── 523-ContinuousSubarraySum │ ├── hatrick.md │ └── official.md ├── 546-RemoveBoxes │ └── passself.md ├── 547-friendCircles │ └── bigablecat.md ├── 551-StudentAttendanceRecordI │ └── official.md ├── 552-StudentAttendanceRecordII │ └── official.md ├── 557-Reverse Words in a String III │ └── sandao.md ├── 576-OutOfBoundaryPaths │ ├── official.md │ └── zengdiqing1994.md ├── 583-DeleteOperationForTwoStrings │ └── README.md ├── 629-KInversePairsArray │ ├── official.md │ └── zengdiqing1994.md ├── 638-ShoppingOffers │ └── bigablecat.md ├── 646-MaximumLengthOfPairChain │ ├── SpecialYang.md │ └── official.md ├── 647-PalindromicSubstrings │ ├── bigablecat.md │ └── official.md ├── 650-2KeysKeyboard │ ├── mahone.md │ └── official.md ├── 664-StrangePrinter │ └── official.md ├── 673-NumberOfLongestIncreasingSubsequence │ ├── README.md │ └── bigablecat.md ├── 684-RedundantConnection │ ├── README.md │ └── bigablecat.md ├── 688-KnightProbabilityInChessboard │ └── passself.md ├── 689-MaximumSumOf3Non-OverlappingSubarrays │ ├── bigablecat.md │ └── official.md ├── 691-StickersToSpellWord │ └── official.md ├── 692-TopKFrequentWords │ └── bigablecat.md ├── 695-MaxAreaOfIsland │ └── README.md ├── 698-PartitionToKEqualSumSubsets │ ├── hatrick.md │ └── official.md ├── 703-KthLargestElementInAStream │ └── BambooYH.md ├── 712-MinimumASCIIDeleteSumforTwoStrings │ ├── BambooYH.md │ └── official.md ├── 714-BestTimeToBuyAndSellStockWithTransactionFee │ ├── hatrick.md │ └── official.md ├── 718-MaximumLengthOfRepeatedSubarray │ ├── mahone.md │ └── official.md ├── 730-CountDifferentPalindromicSubsequences │ └── official.md ├── 740-DeleteAndEarn │ ├── melody-l.md │ └── official.md ├── 746-minCostClimbingStairs │ ├── bigablecat.md │ └── official.md ├── 764-LargestPlusSign │ ├── SpecialYang.md │ └── official.md ├── 785-IsGraphBipartite │ ├── README.md │ └── bigablecat.md ├── 787-CheapestFlightsWithinKStops │ ├── official.md │ └── zengdiqing1994.md ├── 790-DominoAndTrominoTiling │ ├── mahone.md │ └── official.md ├── 801-MinimumSwapsToMakeSequencesIncreasing │ └── official.md ├── 808-SoupServings │ └── official.md ├── 813-LargestSumOfAverages │ ├── melody-l.md │ └── official.md ├── 837-New21Game │ └── official.md ├── 838-PushDominoes │ └── official.md ├── 844-BackspaceStringCompare │ ├── BambooYH.md │ └── bigablecat.md ├── 847-ShortestPathVisitingAllNodes │ ├── bigablecat.md │ └── official.md ├── 860-lemonadeChange │ ├── BambooYH.md │ ├── SpecialYang.md │ └── official.md ├── 873-LengthOfLongestFibonacciSubsequence │ └── official.md ├── 874-walkingRobotSimulation │ ├── SpecialYang.md │ ├── hatrick.md │ └── official.md ├── 875-KokoEatingBananas │ └── sandao.md ├── 877-stoneGame │ ├── melody-l.md │ └── official.md ├── 898-BitwiseORsOfSubarrays │ └── official.md ├── 903-ValidPermutationsForDISequence │ ├── official.md │ └── zengdiqing1994.md ├── 920-NumberOfMusicPlaylists │ └── passself.md ├── 931-MinimumFallingPathSum │ ├── hatrick.md │ └── official.md ├── 935-KnightDialer │ └── official.md ├── 940-DistinctSubsequencesII │ └── official.md ├── 943-FindTheShortestSuperstring │ └── official.md ├── 954-ArrayOfDoubledPairs │ └── bigablecat.md ├── 956-TallestBillboard │ └── official.md ├── 964-LeastOperatorsToExpressNumber │ └── official.md ├── 967-NumbersWithSameConsecutiveDifferences │ ├── bigablecat.md │ └── official.md ├── 968-BinaryTreeCameras │ ├── official.md │ └── zengdiqing1994.md ├── 975-OddEvenJump │ └── official.md ├── 982-TriplesWithBitwiseANDEqualToZero │ └── official.md └── sample │ ├── concise.md │ ├── concise.png │ ├── full.md │ └── full.png └── 剑指Offer ├── 003-数组中重复的数字 ├── README.md └── zengdiqing1994.md ├── 004-二维数组中的查找 ├── README.md └── zengdiqing1994.md ├── 005-替换空格 ├── README.md └── zengdiqing1994.md ├── 006-从尾到头打印链表 ├── README.md └── zengdiqing1994.md ├── 007-重建二叉树 ├── README.md └── zengdiqing1994.md ├── 008-二叉树的下一个结点 └── README.md ├── 009-用两个栈实现队列 └── README.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.java.hsp 2 | *.sonarj 3 | *.sw* 4 | .DS_Store 5 | .settings 6 | .springBeans 7 | bin 8 | build.sh 9 | integration-repo 10 | ivy-cache 11 | jxl.log 12 | jmx.log 13 | derby.log 14 | spring-test/test-output/ 15 | .gradle 16 | argfile* 17 | 18 | 19 | /build 20 | buildSrc/build 21 | /spring-*/build 22 | /src/asciidoc/build 23 | target/ 24 | 25 | # Eclipse artifacts, including WTP generated manifests 26 | .classpath 27 | .project 28 | spring-*/src/main/java/META-INF/MANIFEST.MF 29 | 30 | # IDEA artifacts and output dirs 31 | *.iml 32 | *.ipr 33 | *.iws 34 | .idea/ 35 | out 36 | test-output 37 | atlassian-ide-plugin.xml 38 | .gradletasknamecache 39 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hollischuang/algorithm/05c9121a00f99652ead193a0d9e7d2dadadae397/codes/java_dataStructure_luozhaoyong/1.bmp -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hollischuang/algorithm/05c9121a00f99652ead193a0d9e7d2dadadae397/codes/java_dataStructure_luozhaoyong/2.zip -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hollischuang/algorithm/05c9121a00f99652ead193a0d9e7d2dadadae397/codes/java_dataStructure_luozhaoyong/3.bmp -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo1/AddOneToHundred.java: -------------------------------------------------------------------------------- 1 | package demo1; 2 | 3 | /** 4 | * 计算从 1 加到 100 的和 5 | * @author admin 6 | */ 7 | public class AddOneToHundred { 8 | public static void main(String[] args) { 9 | int total = 0; 10 | int end = 100; 11 | 12 | // 使用 for 循环计算 13 | for (int i = 1; i <= end; i++) { 14 | // total 记录总和 15 | // 每次都累加当前自然数 i 的值 16 | // 这条语句执行了 end 次 17 | total += i; 18 | } 19 | //打印结果 20 | System.out.println("普通 for 循环:" + total); 21 | 22 | // 将 end 变量还原为初始值 23 | end = 100; 24 | // 通过等差数列求和公式计算 1 加到 100 的总和 25 | // 这条语句执行了 1 次 26 | total = (1 + end) * end / 2; 27 | 28 | //打印结果 29 | System.out.println("等差数列求和公式:" + total); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo1/TestArray.java: -------------------------------------------------------------------------------- 1 | package demo1; 2 | 3 | /** 4 | * 数组的基本使用 5 | * @author admin 6 | */ 7 | public class TestArray { 8 | public static void main(String[] args) { 9 | // 创建数组 10 | // int 是数组内元素的类型;3 是数组的大小 11 | int[] arr1 = new int[3]; 12 | 13 | // 获取数组长度 14 | int length1 = arr1.length; 15 | // 打印结果 3 16 | System.out.println("arr1's length:" + length1); 17 | 18 | // 访问数组中的元素:数组名[下标] 19 | // 注意:下标从 0 开始,下标最大可以取到 (数组长度 - 1) 20 | // 获取数组第 1 个元素,即下标为 0 的元素 21 | int element0 = arr1[0]; 22 | // 打印结果 0 23 | System.out.println("element0: " + element0); 24 | 25 | // 为数组中的元素赋值 26 | arr1[0] = 99; 27 | element0 = arr1[0]; 28 | // 打印结果 99 29 | System.out.println("element0: " + element0); 30 | 31 | arr1[1] = 98; 32 | arr1[2] = 97; 33 | 34 | // 遍历数组,从下标 0 开始,到 (数组长度 - 1) 结束 35 | for (int i = 0; i < length1; i++) { 36 | // 打印第 i 个元素 37 | System.out.println("arr1 element " + i + ": " + arr1[i]); 38 | } 39 | 40 | // 创建数组的同时为元素赋值 41 | int[] arr2 = new int[]{90, 80, 70, 60, 50}; 42 | // 打印结果 5 43 | System.out.println("arr2's length:" + arr2.length); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo1/TestBinarySearch.java: -------------------------------------------------------------------------------- 1 | package demo1; 2 | 3 | /** 4 | * 测试二分查找 5 | * @author admin 6 | */ 7 | public class TestBinarySearch { 8 | public static void main(String[] args) { 9 | // 目标数组 10 | int[] arr = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}; 11 | // 目标元素 12 | int target = 3; 13 | // 记录开始位置 14 | int begin = 0; 15 | // 记录结束位置 16 | int end = arr.length - 1; 17 | // 记录中间位置 18 | int mid = begin + (end - begin) / 2; 19 | // 目标元素在数组中的下标,初始值为 -1 20 | int index = -1; 21 | 22 | // 当开始位置小于或等于结束位置时,循环继续 23 | // begin == end 时,即二者重合时 24 | // mid = begin + (end - begin)/2 == begin 25 | // 即 begin 位置本身还没有检查,需要再进入循环一次 26 | while (begin <= end) { 27 | // 如果 mid 位置刚好等于目标值 28 | if (arr[mid] == target) { 29 | // 结束循环 30 | index = mid; 31 | break; 32 | } 33 | // 如果 mid 位置元素大于目标值 34 | if (arr[mid] > target) { 35 | // 将结束位置左移到 mid 位置前一个位置 36 | end = mid - 1; 37 | } else { 38 | // 如果 mid 位置元素小于目标值 39 | // 说明目标值在 mid 的右边 40 | // 将开始位置右移到 mid 后一个位置 41 | begin = mid + 1; 42 | } 43 | // 重新计算 mid 位置的值 44 | mid = begin + (end - begin) / 2; 45 | } 46 | System.out.println(index); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo1/TestMyArray.java: -------------------------------------------------------------------------------- 1 | package demo1; 2 | 3 | import demo1.util.MyArray; 4 | 5 | /** 6 | * 测试可变数组 7 | * @author admin 8 | */ 9 | public class TestMyArray { 10 | 11 | public static void main(String[] args) { 12 | // 创建一个可变数组 13 | MyArray ma = new MyArray(); 14 | // 获取数组长度 15 | int size = ma.size(); 16 | System.out.println(size); 17 | // 显示可变数组中的所有元素到控制台 18 | ma.show(); 19 | 20 | // 向可变数组末尾添加一个元素 21 | ma.add(99); 22 | ma.add(98); 23 | ma.add(97); 24 | ma.show(); 25 | 26 | // 测试删除元素,删除下标为 1 的元素 27 | ma.delete(1); 28 | ma.show(); 29 | 30 | // 获取指定下标的元素 31 | int element = ma.get(1); 32 | System.out.println(element); 33 | 34 | System.out.println("============="); 35 | ma.add(96); 36 | ma.add(95); 37 | ma.add(94); 38 | ma.show(); 39 | 40 | // 向指定位置插入元素 41 | ma.insert(3, 33); 42 | ma.show(); 43 | System.out.println("============="); 44 | 45 | // 测试替换指定位置的值 46 | ma.set(0, 100); 47 | ma.show(); 48 | 49 | // 打印数组长度,set 方法对原数组操作,数组长度没有变化 50 | // 打印结果为 6 51 | System.out.println(ma.size()); 52 | 53 | // 测试下标越界 54 | // 会抛出越界异常 55 | ma.set(-1,100); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo1/TestMyArraySearch.java: -------------------------------------------------------------------------------- 1 | package demo1; 2 | 3 | import demo1.util.MyArray; 4 | 5 | /** 6 | * 测试查找方法 7 | * @author admin 8 | */ 9 | public class TestMyArraySearch { 10 | public static void main(String[] args) { 11 | MyArray ma = new MyArray(); 12 | ma.add(1); 13 | ma.add(2); 14 | ma.add(3); 15 | ma.add(4); 16 | ma.add(5); 17 | // 线性查找 18 | int index = ma.search(4); 19 | System.out.println("index: " + index); 20 | 21 | // 调用二分法查找 22 | int index2 = ma.binarySearch(-1); 23 | System.out.println("index2: " + index2); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo1/TestOpArray.java: -------------------------------------------------------------------------------- 1 | package demo1; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 数组动态扩容 7 | * 解决数组长度不可变的问题 8 | * @author admin 9 | */ 10 | public class TestOpArray { 11 | public static void main(String[] args) { 12 | // 原数组 13 | int[] arr = new int[]{9, 8, 7}; 14 | 15 | // 直接调用 java.util.Arrays 中的方法,将数组元素转为 String 格式用于打印和查看 16 | System.out.println(Arrays.toString(arr)); 17 | 18 | // 要加入数组的新元素 19 | int dst = 6; 20 | 21 | // 1. 创建一个新数组,长度是原数组长度 + 1 22 | int[] newArr = new int[arr.length + 1]; 23 | // 2. 把原数组中的元素复制到新数组中 24 | for (int i = 0; i < arr.length; i++) { 25 | // 将原数组中的第 i 个元素 arr[i] 26 | // 赋值给新数组第 i 个位置 27 | newArr[i] = arr[i]; 28 | } 29 | // 打印新数组中的所有元素 30 | System.out.println(Arrays.toString(newArr)); 31 | // 3. 将目标元素放入新数组的最后 32 | // 新数组最后一个位置的下标是 newArr.length - 1 33 | // 教学视频中使用了 arr.length,两者是相等的,newArr.length - 1 更容易理解 34 | newArr[newArr.length - 1] = dst; 35 | // 4. 新数组替换原数组,即原数组的变量 arr,指向新数组 36 | arr = newArr; 37 | System.out.println(Arrays.toString(arr)); 38 | } 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo1/TestOpArray2.java: -------------------------------------------------------------------------------- 1 | package demo1; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 删除数组中的元素 7 | * @author admin 8 | */ 9 | public class TestOpArray2 { 10 | public static void main(String[] args) { 11 | // 原数组 12 | int[] arr = new int[]{9, 8, 7, 6, 5, 4}; 13 | 14 | // 要删除元素的下标 15 | // 即 arr 中下标为 3 的元素,arr[3] = 6 16 | int dst = 3; 17 | 18 | // 1. 创建一个新数组,长度是原数组的的长度 -1 19 | int[] newArr = new int[arr.length - 1]; 20 | 21 | // 2. 复制原数组中除了要删除的元素以外的其他元素 22 | // 方法1:视频中老师使用的方法,一个循环中加判断 23 | // for (int i = 0; i < arr.length - 1; i++) { 24 | // if (i < dst) { 25 | // // 下标比要删除的下标小,可以直接一对一拷贝 26 | // newArr[i] = arr[i]; 27 | // } else { 28 | // // 下标大于要删除的下标,需要在原下标 i 的基础上 + 1 29 | // // 即跳过了要删除的下标 30 | // newArr[i] = arr[i + 1]; 31 | // } 32 | // } 33 | // 方法2:将数组分为两段,分别用循环遍历,正好跳过了要删除的下标 dst 34 | // 数组中下标小于要删除的下标 35 | for (int i = 0; i < dst; i++) { 36 | // 直接通过相等的下标赋值 37 | newArr[i] = arr[i]; 38 | } 39 | // 数组中下标大于要删除的下标 40 | for (int i = dst; i < arr.length - 1; i++) { 41 | // 在原有下标的基础上 +1,因为跳过了要删除的下标,之后每个下标都要 +1 42 | newArr[i] = arr[i + 1]; 43 | } 44 | 45 | // 3. 用新数组替换原数组 46 | arr = newArr; 47 | 48 | // 打印结果 49 | System.out.println(Arrays.toString(arr)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo1/TestSearch.java: -------------------------------------------------------------------------------- 1 | package demo1; 2 | 3 | /** 4 | * 线性查找 5 | * @author admin 6 | */ 7 | public class TestSearch { 8 | public static void main(String[] args) { 9 | // 目标数组 10 | int[] arr = new int[]{2, 3, 5, 6, 8, 4, 9, 0}; 11 | // 目标值 12 | int target = 0; 13 | // 目标值的下标,初始值为 -1 14 | int index = -1; 15 | // 遍历数组,查找目标值在数组中的位置 16 | for (int i = 0; i < arr.length; i++) { 17 | // 如果当前值与目标值相等 18 | if (arr[i] == target) { 19 | // 将目标值下标指向当前位置 20 | index = i; 21 | break; 22 | } 23 | } 24 | // 打印目标值下标 25 | System.out.println(index); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo10/Node.java: -------------------------------------------------------------------------------- 1 | package demo10; 2 | 3 | /** 4 | * 定义赫夫曼树的节点 5 | * 6 | * @author admin 7 | */ 8 | public class Node implements Comparable { 9 | /** 10 | * 字符数据 11 | */ 12 | Byte data; 13 | /** 14 | * 权重 15 | */ 16 | int weight; 17 | /** 18 | * 左子节点 19 | */ 20 | Node left; 21 | /** 22 | * 右子节点 23 | */ 24 | Node right; 25 | 26 | /** 27 | * 构造方法 28 | * 29 | * @param data 30 | * @param weight 31 | */ 32 | public Node(Byte data, int weight) { 33 | this.data = data; 34 | this.weight = weight; 35 | } 36 | 37 | /** 38 | * 覆写原有比较方法 39 | * 40 | * @param o 41 | * @return 42 | */ 43 | @Override 44 | public int compareTo(Node o) { 45 | // 返回倒序结果 46 | return o.weight - this.weight; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return "Node{data=" + data + ", weight=" + weight + "}"; 52 | 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo11/TestBinarySortTree.java: -------------------------------------------------------------------------------- 1 | package demo11; 2 | 3 | /** 4 | * 测试二叉排序树 5 | * @author admin 6 | */ 7 | public class TestBinarySortTree { 8 | public static void main(String[] args) { 9 | int[] arr = new int[]{7, 3, 10, 12, 5, 1, 9}; 10 | BinarySortTree bst = new BinarySortTree(); 11 | // 添加节点 12 | for (int i : arr) { 13 | bst.add(new Node(i)); 14 | } 15 | // 中序遍历 16 | bst.midShow(); 17 | 18 | // 查找节点 19 | Node node1 = bst.search(10); 20 | Node node2 = bst.search(20); 21 | System.out.println(node1); 22 | System.out.println(node2); 23 | 24 | // 删除叶子节点,值为 12 的节点没有孩子节点 25 | bst.delete(12); 26 | bst.midShow(); 27 | 28 | // 要删除的节点只有一个子节点 29 | // 上个测试删除的节点 12 就是 10 的子节点 30 | // 目前 10 只剩下一个子节点 9 31 | bst.delete(10); 32 | bst.midShow(); 33 | 34 | // 删除的节点有两个孩子节点 35 | bst.delete(7); 36 | bst.midShow(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo12/TestBinarySortTree.java: -------------------------------------------------------------------------------- 1 | package demo12; 2 | 3 | /** 4 | * 测试平衡二叉树 5 | * @author admin 6 | */ 7 | public class TestBinarySortTree { 8 | public static void main(String[] args) { 9 | int[] arr = new int[]{8, 9, 6, 7, 5, 4}; 10 | BinarySortTree bst = new BinarySortTree(); 11 | // 添加节点 12 | for (int i : arr) { 13 | bst.add(new Node(i)); 14 | } 15 | // 打印结果为 3 16 | System.out.println(bst.root.height()); 17 | // 打印结果为 6 18 | System.out.println(bst.root.value); 19 | 20 | System.out.println("======================="); 21 | 22 | // 重新创建一棵平衡二叉树,测试左旋 23 | arr = new int[]{2, 1, 4, 3, 5, 6}; 24 | bst = new BinarySortTree(); 25 | // 添加节点 26 | for (int i : arr) { 27 | bst.add(new Node(i)); 28 | } 29 | // 打印结果为 3 30 | System.out.println(bst.root.height()); 31 | // 打印结果为 4 32 | System.out.println(bst.root.value); 33 | 34 | System.out.println("======================="); 35 | 36 | // 重新创建一棵平衡二叉树,测试双旋转 37 | arr = new int[]{8, 9, 5, 4, 6, 7}; 38 | bst = new BinarySortTree(); 39 | // 添加节点 40 | for (int i : arr) { 41 | bst.add(new Node(i)); 42 | } 43 | // 打印结果为 3 44 | System.out.println(bst.root.height()); 45 | // 打印结果为 6 46 | System.out.println(bst.root.value); 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo13/HashTable.java: -------------------------------------------------------------------------------- 1 | package demo13; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 自定义哈希表 7 | * 8 | * @author admin 9 | */ 10 | public class HashTable { 11 | /** 12 | * 存储学生数据的数组 13 | */ 14 | private StuInfo[] data = new StuInfo[100]; 15 | 16 | /** 17 | * 向散列表中添加元素 18 | * 19 | * @param stuInfo 20 | */ 21 | public void put(StuInfo stuInfo) { 22 | // 调用散列函数获取存储位置 23 | int index = stuInfo.hashCode(); 24 | // 在指定位置存入对象 25 | data[index] = stuInfo; 26 | } 27 | 28 | /** 29 | * 从散列表中获取元素 30 | * 31 | * @param stuInfo 32 | * @return 33 | */ 34 | public StuInfo get(StuInfo stuInfo) { 35 | return data[stuInfo.hashCode()]; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "HashTable{" + 41 | "data=" + Arrays.toString(data) + 42 | '}'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo13/StuInfo.java: -------------------------------------------------------------------------------- 1 | package demo13; 2 | 3 | /** 4 | * 学生信息类 5 | * 6 | * @author admin 7 | */ 8 | public class StuInfo { 9 | int age; 10 | int count; 11 | 12 | public int getAge() { 13 | return age; 14 | } 15 | 16 | public void setAge(int age) { 17 | this.age = age; 18 | } 19 | 20 | public int getCount() { 21 | return count; 22 | } 23 | 24 | public void setCount(int count) { 25 | this.count = count; 26 | } 27 | 28 | /** 29 | * 自定义散列函数 30 | * 31 | * @return 32 | */ 33 | @Override 34 | public int hashCode() { 35 | // 1. 直接定址法 36 | // 将年龄直接返回 37 | // 2. 取余法 38 | // 将 age 取模后返回余数 39 | return age%10; 40 | } 41 | 42 | public StuInfo(int age, int count) { 43 | super(); 44 | this.age = age; 45 | this.count = count; 46 | } 47 | 48 | public StuInfo(int age) { 49 | this.age = age; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "StuInfo{" + 55 | "age=" + age + 56 | ", count=" + count + 57 | '}'; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo13/TestHashTable.java: -------------------------------------------------------------------------------- 1 | package demo13; 2 | 3 | /** 4 | * 测试散列函数 5 | * @author admin 6 | */ 7 | public class TestHashTable { 8 | public static void main(String[] args) { 9 | StuInfo s1 = new StuInfo(16, 3); 10 | StuInfo s2 = new StuInfo(17, 11); 11 | StuInfo s3 = new StuInfo(18, 23); 12 | StuInfo s4 = new StuInfo(19, 24); 13 | StuInfo s5 = new StuInfo(20, 9); 14 | 15 | HashTable ht = new HashTable(); 16 | ht.put(s1); 17 | ht.put(s2); 18 | ht.put(s3); 19 | ht.put(s4); 20 | ht.put(s5); 21 | 22 | System.out.println(ht); 23 | 24 | // 获取目标数据 25 | StuInfo target = new StuInfo(18); 26 | StuInfo info = ht.get(target); 27 | System.out.println(info); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo14/TestGraph.java: -------------------------------------------------------------------------------- 1 | package demo14; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 测试图 7 | * 8 | * @author admin 9 | */ 10 | public class TestGraph { 11 | public static void main(String[] args) { 12 | Vertex v1 = new Vertex("A"); 13 | Vertex v2 = new Vertex("B"); 14 | Vertex v3 = new Vertex("C"); 15 | Vertex v4 = new Vertex("D"); 16 | Vertex v5 = new Vertex("E"); 17 | 18 | Graph g = new Graph(5); 19 | g.addVertex(v1); 20 | g.addVertex(v2); 21 | g.addVertex(v3); 22 | g.addVertex(v4); 23 | g.addVertex(v5); 24 | 25 | g.addEdge("A", "C"); 26 | g.addEdge("B", "C"); 27 | g.addEdge("A", "B"); 28 | g.addEdge("B", "D"); 29 | g.addEdge("B", "E"); 30 | 31 | // 遍历打印邻接矩阵,查看添加边的操作是否正确 32 | // 打印结果: 33 | // [0, 1, 1, 0, 0] 34 | // [1, 0, 1, 1, 1] 35 | // [1, 1, 0, 0, 0] 36 | // [0, 1, 0, 0, 0] 37 | // [0, 1, 0, 0, 0] 38 | for (int[] a : g.adjMat) { 39 | System.out.println(Arrays.toString(a)); 40 | } 41 | 42 | // 执行深度优先遍历 43 | // 打印结果: 44 | // A --> B 45 | // B --> C 46 | // B --> D 47 | // B --> E 48 | g.dfs(); 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo14/Vertex.java: -------------------------------------------------------------------------------- 1 | package demo14; 2 | 3 | /** 4 | * 顶点类 5 | * 6 | * @author admin 7 | */ 8 | public class Vertex { 9 | /** 10 | * 顶点数据内容 11 | */ 12 | String value; 13 | /** 14 | * 顶点是否已经访问过 15 | */ 16 | boolean visited; 17 | 18 | public String getValue() { 19 | return value; 20 | } 21 | 22 | public void setValue(String value) { 23 | this.value = value; 24 | } 25 | 26 | public Vertex(String value) { 27 | this.value = value; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return value; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo2/DoubleNode.java: -------------------------------------------------------------------------------- 1 | package demo2; 2 | 3 | /** 4 | * 定义双向链表的节点 5 | * @author admin 6 | */ 7 | public class DoubleNode { 8 | /** 9 | * 前置节点 10 | */ 11 | DoubleNode pre = this; 12 | 13 | /** 14 | * 后继节点 15 | */ 16 | DoubleNode next = this; 17 | 18 | /** 19 | * 节点数据 20 | */ 21 | int data; 22 | 23 | /** 24 | * 构造函数 25 | * @param data 26 | */ 27 | public DoubleNode(int data){ 28 | this.data = data; 29 | } 30 | 31 | /** 32 | * 插入节点方法 33 | * @param node 34 | */ 35 | public void after(DoubleNode node){ 36 | // 获取当前节点的后继节点 37 | DoubleNode nextNext = this.next; 38 | // 将当前节点的后继节点指向新节点 39 | this.next = node; 40 | // 新节点的前置节点指向当前节点 41 | node.pre = this; 42 | 43 | // 新节点的后继节点指向原后继节点 44 | node.next = nextNext; 45 | // 原后继节点的前置节点指向新节点 46 | nextNext.pre = node; 47 | 48 | // 上述过程将新节点插入到当前节点和原后继节点之间 49 | } 50 | 51 | /** 52 | * 获取后继节点 53 | * @return 54 | */ 55 | public DoubleNode next(){ 56 | // 返回后继节点 57 | return this.next; 58 | } 59 | 60 | /** 61 | * 获取前置节点 62 | * @return 63 | */ 64 | public DoubleNode pre(){ 65 | // 返回前置节点 66 | return this.pre; 67 | } 68 | 69 | /** 70 | * 获取数据 71 | * @return 72 | */ 73 | public int getData(){ 74 | // 返回当前节点数据 75 | return this.data; 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo2/LoopNode.java: -------------------------------------------------------------------------------- 1 | package demo2; 2 | 3 | /** 4 | * 定义节点类 5 | * 6 | * @author admin 7 | */ 8 | public class LoopNode { 9 | /** 10 | * 节点数据 11 | */ 12 | int data; 13 | /** 14 | * 后继节点 15 | * 尾节点指向头节点 16 | */ 17 | LoopNode next = this; 18 | 19 | /** 20 | * 构造方法 21 | * 22 | * @param data 23 | */ 24 | public LoopNode(int data) { 25 | this.data = data; 26 | } 27 | 28 | /** 29 | * 获取后继节点 30 | * 31 | * @return 32 | */ 33 | public LoopNode next() { 34 | // 直接返回后继节点 35 | return this.next; 36 | } 37 | 38 | /** 39 | * 获取节点数据 40 | * 41 | * @return 42 | */ 43 | public int getData() { 44 | return this.data; 45 | } 46 | 47 | 48 | /** 49 | * 删除当前节点的下一个节点 50 | */ 51 | public void removeNext() { 52 | // 如果当前节点的后继节点为空,直接返回 53 | if (next == null) { 54 | return; 55 | } 56 | // 将当前节点的后继节点指向下下个节点 57 | this.next = next.next; 58 | } 59 | 60 | /** 61 | * 插入一个新节点 62 | * 63 | * @param node 64 | */ 65 | public void after(LoopNode node) { 66 | // 获取当前节点的后继节点 67 | LoopNode nextNext = this.next; 68 | // 当前节点的后继节点指向新加入的节点 69 | this.next = node; 70 | // 新节点的后继节点指向原先的后继节点 71 | node.next = nextNext; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo2/MyQueue.java: -------------------------------------------------------------------------------- 1 | package demo2; 2 | 3 | /** 4 | * 数组实现一个队列 5 | * @author admin 6 | */ 7 | public class MyQueue { 8 | /** 9 | * 存储数据的数组 10 | */ 11 | int[] elements; 12 | 13 | /** 14 | * 构造方法 15 | */ 16 | public MyQueue() { 17 | // 初始化数组 18 | elements = new int[0]; 19 | } 20 | 21 | /** 22 | * 入队 23 | * @param element 24 | */ 25 | public void add(int element) { 26 | // 新建一个数组,长度是原数组的长度+1 27 | int[] newArr = new int[elements.length + 1]; 28 | 29 | // 将原数组中的元素赋值逐个给新数组 30 | for (int i = 0; i < elements.length; i++) { 31 | newArr[i] = elements[i]; 32 | } 33 | 34 | // 将新元素赋值给新数组的最后一个位置 35 | newArr[newArr.length - 1] = element; 36 | // 新旧数组替换 37 | elements = newArr; 38 | } 39 | 40 | /** 41 | * 出队 42 | * @return 43 | */ 44 | public int poll() { 45 | if (elements.length == 0) { 46 | throw new RuntimeException("queue is empty"); 47 | } 48 | // 取出数组的第一个元素 49 | int element = elements[0]; 50 | 51 | // 创建一个新数组,长度比原数组长度少 1 52 | int[] newArr = new int[elements.length - 1]; 53 | 54 | // 将原数组除第一个元素以外的所有元素赋值给新数组 55 | for (int i = 1; i < elements.length; i++) { 56 | // 取原数组元素时,i 从 1开始 57 | // 新数组下标从 0 开始,所以对应每个下标要在 i 的基础上 -1 58 | newArr[i - 1] = elements[i]; 59 | } 60 | // 新旧数组替换 61 | elements = newArr; 62 | 63 | // 返回出队的元素 64 | return element; 65 | } 66 | 67 | /** 68 | * 判断队列是否为空 69 | * @return 70 | */ 71 | public boolean isEmpty() { 72 | // 判断队列长度是否为 0 73 | return elements.length == 0; 74 | } 75 | 76 | 77 | } 78 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo2/TestLoopNode.java: -------------------------------------------------------------------------------- 1 | package demo2; 2 | 3 | /** 4 | * 测试循环链表 5 | */ 6 | public class TestLoopNode { 7 | public static void main(String[] args) { 8 | // 创建新节点 9 | LoopNode n1 = new LoopNode(1); 10 | LoopNode n2 = new LoopNode(2); 11 | LoopNode n3 = new LoopNode(3); 12 | LoopNode n4 = new LoopNode(4); 13 | // 插入节点 14 | n1.after(n2); 15 | // 显示结果 16 | System.out.println(n1.next().getData()); // 2 17 | System.out.println(n2.next().getData()); // 1 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo2/test/TestDoubleNode.java: -------------------------------------------------------------------------------- 1 | package demo2.test; 2 | 3 | import demo2.DoubleNode; 4 | 5 | /** 6 | * 测试双向链表 7 | * @author admin 8 | */ 9 | public class TestDoubleNode { 10 | public static void main(String[] args) { 11 | // 创建节点 12 | DoubleNode n1 = new DoubleNode(1); 13 | DoubleNode n2 = new DoubleNode(2); 14 | DoubleNode n3 = new DoubleNode(3); 15 | // 打印节点的值,结果为 1 16 | System.out.println(n1.pre().getData()); 17 | // 打印结果为 1 18 | System.out.println(n1.getData()); 19 | // 打印结果为 1 20 | System.out.println(n1.next().getData()); 21 | System.out.println(); 22 | 23 | // 节点之间建立连接 24 | n1.after(n2); 25 | n2.after(n3); 26 | // 打印节点的值,打印结果为 1 27 | System.out.println(n2.pre().getData()); 28 | // 打印结果为 2 29 | System.out.println(n2.getData()); 30 | // 打印结果为 3 31 | System.out.println(n2.next().getData()); 32 | System.out.println(); 33 | 34 | // 双向循环链表最后添加的节点,后继节点指向第一个节点,打印结果为 1 35 | System.out.println(n3.next().getData()); 36 | // 打印结果为 3 37 | System.out.println(n1.pre().getData()); 38 | 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo2/test/TestLoopNode.java: -------------------------------------------------------------------------------- 1 | package demo2.test; 2 | 3 | import demo2.LoopNode; 4 | 5 | /** 6 | * 测试循环链表 7 | * 8 | * @author admin 9 | */ 10 | public class TestLoopNode { 11 | public static void main(String[] args) { 12 | LoopNode n1 = new LoopNode(1); 13 | LoopNode n2 = new LoopNode(2); 14 | LoopNode n3 = new LoopNode(3); 15 | LoopNode n4 = new LoopNode(4); 16 | 17 | // 增加节点 18 | n1.after(n2); 19 | n2.after(n3); 20 | n3.after(n4); 21 | 22 | // 打印结果是 2 23 | System.out.println(n1.next().getData()); 24 | // 打印结果是 3 25 | System.out.println(n2.next().getData()); 26 | // 打印结果是 4 27 | System.out.println(n3.next().getData()); 28 | // 打印结果是 1,循环链表首尾相连 29 | System.out.println(n4.next().getData()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo2/test/TestMyQueue.java: -------------------------------------------------------------------------------- 1 | package demo2.test; 2 | 3 | import demo2.MyQueue; 4 | 5 | /** 6 | * 测试队列 7 | * @author admin 8 | */ 9 | public class TestMyQueue { 10 | public static void main(String[] args) { 11 | // 创建一个队列 12 | MyQueue mq = new MyQueue(); 13 | // 添加元素 14 | mq.add(9); 15 | mq.add(8); 16 | mq.add(7); 17 | // 出队,打印结果为 9 18 | System.out.println(mq.poll()); 19 | mq.add(6); 20 | // 出队前有新元素入队,不影响出队的顺序,打印结果为 8 21 | System.out.println(mq.poll()); 22 | // 判断是否为空,打印结果为 false 23 | System.out.println(mq.isEmpty()); 24 | // 继续出队,打印结果为 7 25 | System.out.println(mq.poll()); 26 | // 大姨结果为 8 27 | System.out.println(mq.poll()); 28 | // 再判断是否为空,打印结果为 true 29 | System.out.println(mq.isEmpty()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo2/test/TestMyStack.java: -------------------------------------------------------------------------------- 1 | package demo2.test; 2 | 3 | import demo2.MyStack; 4 | 5 | /** 6 | * 测试栈 7 | * 8 | * @author admin 9 | */ 10 | public class TestMyStack { 11 | public static void main(String[] args) { 12 | MyStack ms = new MyStack(); 13 | // 测试栈为空时抛出异常 14 | try { 15 | ms.pop(); 16 | } catch (RuntimeException e) { 17 | e.printStackTrace(); 18 | } 19 | 20 | // 压入数据 21 | ms.push(9); 22 | ms.push(8); 23 | ms.push(7); 24 | 25 | // 查看栈顶元素,打印结果为 7 26 | System.out.println(ms.peek()); 27 | 28 | // 取出栈顶元素,打印结果为 7 29 | System.out.println(ms.pop()); 30 | 31 | // 再次查看栈顶元素,打印结果为 8 32 | System.out.println(ms.peek()); 33 | 34 | // 判断栈是否为空,打印结果为 false 35 | System.out.println(ms.isEmpty()); 36 | 37 | // 取出栈顶元素,打印结果为 8 38 | System.out.println(ms.pop()); 39 | // 打印结果为 9 40 | System.out.println(ms.pop()); 41 | 42 | // 判断栈是否为空,打印结果为 true 43 | System.out.println(ms.isEmpty()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo2/test/TestNode.java: -------------------------------------------------------------------------------- 1 | package demo2.test; 2 | 3 | import demo2.Node; 4 | 5 | /** 6 | * 测试单链表 7 | * 8 | * @author admin 9 | */ 10 | public class TestNode { 11 | public static void main(String[] args) { 12 | // 创建节点 13 | Node n1 = new Node(1); 14 | Node n2 = new Node(2); 15 | Node n3 = new Node(3); 16 | // 追加节点 17 | n1.append(n2).append(n3).append(new Node(4)); 18 | // 获取后继节点,打印结果为 3 19 | System.out.println(n1.next().next().getData()); 20 | // 判断节点是否为最后一个节点,打印结果为 false 21 | System.out.println(n1.isLast()); 22 | // 打印结果为 true 23 | System.out.println(n1.next().next().next().isLast()); 24 | 25 | // 显示已有节点,打印结果 1 2 3 4 26 | n1.show(); 27 | // 删除 n3 28 | n1.next().removeNext(); 29 | // 显示删除后剩余的节点,打印结果 1 2 4 30 | n1.show(); 31 | 32 | // 创建一个新节点 33 | Node node = new Node(3); 34 | // 将新节点插入 n2 之后 35 | n1.next().after(node); 36 | // 重新显示所有节点,打印结果 1 2 3 4 37 | n1.show(); 38 | 39 | // 再来一次 40 | // 创建一个新节点 41 | node = new Node(5); 42 | // 将新节点插入 n2 之后 43 | n1.next().after(node); 44 | // 重新显示所有节点,打印结果 1 2 5 3 4 45 | n1.show(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo3/TestFibonacci.java: -------------------------------------------------------------------------------- 1 | package demo3; 2 | 3 | /** 4 | * 测试斐波那契数列 5 | * @author admin 6 | */ 7 | public class TestFibonacci { 8 | public static void main(String[] args) { 9 | // 斐波那契数列 1 1 2 3 5 8 13 10 | int i = fibonacci(3); 11 | // 打印结果为 2 12 | System.out.println(i); 13 | 14 | i = fibonacci(6); 15 | // 打印结果为 8 16 | System.out.println(i); 17 | } 18 | 19 | /** 20 | * 斐波那契数列求值函数 21 | * @param i 22 | * @return 23 | */ 24 | public static int fibonacci(int i) { 25 | // 递归函数停止条件,当 i 等于 1 或者 2 时返回数字 1 26 | if (i == 1 || i == 2) { 27 | return 1; 28 | } 29 | // 其他情况递归调用当前函数 30 | // 即第 i 项等于前两项之和 31 | return fibonacci(i - 1) + fibonacci(i - 2); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo3/TestHanoi.java: -------------------------------------------------------------------------------- 1 | package demo3; 2 | 3 | /** 4 | * 测试汉诺塔 5 | * @author admin 6 | */ 7 | public class TestHanoi { 8 | public static void main(String[] args) { 9 | hanoi(1, 'A', 'B', 'C'); 10 | System.out.println(); 11 | 12 | hanoi(2, 'A', 'B', 'C'); 13 | System.out.println(); 14 | 15 | hanoi(3, 'A', 'B', 'C'); 16 | System.out.println(); 17 | 18 | hanoi(4, 'A', 'B', 'C'); 19 | } 20 | 21 | /** 22 | * 共有 n 个盘子 23 | * 将上面的 n - 1 个盘子视为 1 个整体 24 | * 最底下的 1 个盘子视为 1 个整体 25 | * 3 根柱子中的空闲柱子作为中转 26 | * 当 n>=3 时,每次递归都将问题转化为 2 个盘子的情况 27 | * 28 | * @param n 盘子总数 29 | * @param from 第一根柱子 30 | * @param in 中间的柱子 31 | * @param to 最后一根柱子 32 | */ 33 | public static void hanoi(int n, char from, char in, char to) { 34 | // 只有一个盘子的情况 35 | if (n == 1) { 36 | // 直接将当前盘子移动到目标位置 37 | System.out.println("第 1 个盘子从 " + from + " 移动到 " + to); 38 | 39 | // 其他情况都转换成处理 2 个盘子的汉诺塔问题 40 | } else { 41 | // 将上面的 n-1 个盘子视为 1 个整体,从原位置 from 移动到中间位置 in 42 | // to 此时为空,作为中转的柱子 43 | hanoi(n - 1, from, to, in); 44 | 45 | // 再将最底下的 1 个盘子,从原位置 from 移动到最终的目标位置 to 46 | System.out.println("第 " + n + " 个盘子从 " + from + " 移动到 " + to); 47 | 48 | // 最后将放在中间位置 in 的盘子,也移动到目标位置 to 49 | // from 此时为空,作为中转的柱子 50 | hanoi(n - 1, in, from, to); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo3/TestRecursive.java: -------------------------------------------------------------------------------- 1 | package demo3; 2 | 3 | /** 4 | * 测试递归 5 | * @author admin 6 | */ 7 | public class TestRecursive { 8 | public static void main(String[] args) { 9 | // 调用递归函数 10 | print(3); 11 | } 12 | 13 | /** 14 | * 递归打印 15 | * @param i 16 | */ 17 | public static void print(int i) { 18 | if (i > 0) { 19 | System.out.println(i); 20 | print(i - 1); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo4/BubbleSort.java: -------------------------------------------------------------------------------- 1 | package demo4; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 冒泡排序 7 | *

8 | * 多次遍历数组 9 | * 每次逐个比较相邻两个元素 10 | * 如果没有按照指定顺序排列,就互换元素 11 | * 直到遍历结束或者全部有序为止 12 | * 13 | * @author admin 14 | */ 15 | public class BubbleSort { 16 | public static void main(String[] args) { 17 | int[] arr = new int[]{5, 7, 2, 9, 4, 1, 0, 5, 7}; 18 | bubbleSort(arr); 19 | System.out.println(Arrays.toString(arr)); 20 | } 21 | 22 | /** 23 | * 冒泡排序 24 | *

25 | * 时间复杂度:O(n^2) 26 | * 外循环执行了 n 次 27 | * 内循环每次都排除上一轮已排好序的末尾元素,因此每轮递减 1 28 | * (n-1) + (n-2) + ... 1 = (n-1+1)/2 = n/2 29 | * 外循环 * 内循环 = n*(n/2) = n^2/2 30 | * O(n^2/2) = O(n^2) 31 | *

32 | * 空间复杂度:O(1),没有使用额外空间 33 | */ 34 | public static void bubbleSort(int[] arr) { 35 | // 如果数组长度小于等于 1,不用排序 36 | if (arr.length <= 1) { 37 | return; 38 | } 39 | // 临时变量,用于两数交换时做临时存储 40 | int temp; 41 | for (int i = 0; i < arr.length - 1; i++) { 42 | 43 | // 每轮排序,最大的值都会排到末尾 44 | // i = 1 时,arr[arr.length-1-1] 已经在上一轮排好序了 45 | // i = 2 时,arr[arr.length-1-2] 已经在上一轮排好序了 46 | // 因此内循环控制变量 j 的值,最大应小于 arr.length - 1 - i 47 | // 可以避免重复检查数组末尾已经排好序的部分 48 | for (int j = 0; j < arr.length - 1 - i; j++) { 49 | if (arr[j] > arr[j + 1]) { 50 | // 临时变量存储 arr[j] 的值 51 | temp = arr[j]; 52 | // 将 arr[j+1] 的值赋给 arr[j] 53 | arr[j] = arr[j + 1]; 54 | // 将原 arr[j] 的值赋给 arr[j] 55 | arr[j + 1] = temp; 56 | } 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo4/SelectionSort.java: -------------------------------------------------------------------------------- 1 | package demo4; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 选择排序 7 | *

8 | * 将数组看作有序和无序两部分 9 | * 每次都从无序部分找出最小的元素,与无序部分的第一个元素交换位置 10 | * 直到数组完全排序为止 11 | * 12 | * @author admin 13 | */ 14 | public class SelectionSort { 15 | public static void main(String[] args) { 16 | int[] arr = new int[]{3, 4, 5, 7, 1, 2, 0, 3, 6, 8}; 17 | selectionSort(arr); 18 | System.out.println(Arrays.toString(arr)); 19 | } 20 | 21 | /** 22 | * 选择排序方法 23 | * 时间复杂度: 24 | * 内循环每次都会从无序部分找出最小的元素 25 | * 依次比较了 n-1 次,n-2 次,n-3 次 ... 1 次 26 | * 总共比较的次数是 (n-1) + (n-2) + ...+ 1 = (n-1 + 1) /2 = n/2 次 27 | * 外循环执行了 n 次,总共的时间复杂度是 O(n*n/2) = O(n^2/2) = O(n^2) 28 | * 29 | * @param arr 30 | */ 31 | public static void selectionSort(int[] arr) { 32 | // 当数组元素小于等于 1 时,天然有序,无需进行排序 33 | if (arr.length <= 1) { 34 | return; 35 | } 36 | // 遍历数组 37 | for (int i = 0; i < arr.length; i++) { 38 | int minIndex = i; 39 | for (int j = i + 1; j < arr.length; j++) { 40 | // 如果内循环当前元素 arr[j] 比已知最小值还小 41 | // 则将最小值下标 minIndex 替换为 j 42 | if (arr[j] < arr[minIndex]) { 43 | minIndex = j; 44 | } 45 | } 46 | // 内循环结束时 47 | // 未排序部分第一个元素是 arr[i] 48 | // 未排序部分最小元素是 arr[minIndex] 49 | // 如果 i 与 minIndex 不相等 50 | // 则需要交换两者的值 51 | // 让未排序部分的最小元素排到未排序部分的第一个元素位置 52 | if (i != minIndex) { 53 | // 交换两者的位置 54 | int temp = arr[i]; 55 | arr[i] = arr[minIndex]; 56 | arr[minIndex] = temp; 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo4/ShellSort.java: -------------------------------------------------------------------------------- 1 | package demo4; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 希尔排序 7 | *

8 | * 取某个数字作为步长,按步长对数组进行插入排序 9 | * 排序完成后,步长按规律递减 10 | * 用新步长进行下一轮插入排序 11 | * 重复上述步骤,直到步长变成 1,进行最后一轮普通的插入排序为止 12 | * 13 | * @author admin 14 | */ 15 | public class ShellSort { 16 | public static void main(String[] args) { 17 | int[] arr = new int[]{3, 5, 2, 7, 8, 1, 2, 0, 4, 7, 4, 3, 8}; 18 | shellSort(arr); 19 | System.out.println(Arrays.toString(arr)); 20 | } 21 | 22 | /** 23 | * 希尔排序方法 24 | * 数组完全逆序时,接近插入排序的时间复杂度 O(n^2) 25 | * 最优时间复杂度,约为 O(n^1.3) 26 | * 27 | * @param arr 28 | */ 29 | public static void shellSort(int[] arr) { 30 | // 用于记录当前排序次数,与主逻辑无关,仅用于打印结果 31 | int k = 1; 32 | 33 | // 除数设定为 2,每次步长都是上一次的 1/2 34 | int divisor = 2; 35 | // 遍历所有步长的情况 36 | for (int d = arr.length / divisor; d > 0; d /= divisor) { 37 | // 外循环控制变量 i 起始位置为 d 38 | // d 是规定的步长,当 d ==1 时,就变成了插入排序 39 | for (int i = d; i < arr.length; i++) { 40 | // 内循环控制变量 j 41 | for (int j = i - d; j >= 0; j -= d) { 42 | // 如果 arr[j] 比更靠后的元素 arr[j+d] 大 43 | // 则交换两者位置,保持前面数字更小的顺序 44 | if (arr[j] > arr[j + d]) { 45 | // 交换 arr[j] 和 arr[j+d] 的位置 46 | int temp = arr[j]; 47 | arr[j] = arr[j + d]; 48 | arr[j + d] = temp; 49 | } 50 | } 51 | } 52 | System.out.println("第 " + k + " 次排序结果 " + Arrays.toString(arr)); 53 | k++; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo5/BinaryTree.java: -------------------------------------------------------------------------------- 1 | package demo5; 2 | 3 | /** 4 | * 二叉树 5 | * @author admin 6 | */ 7 | public class BinaryTree { 8 | /** 9 | * 根结点 10 | */ 11 | TreeNode root; 12 | 13 | 14 | /** 15 | * 设置根结点 16 | * 17 | * @param node 节点参数 18 | */ 19 | public void setRoot(TreeNode node) { 20 | root = node; 21 | } 22 | 23 | /** 24 | * 前序遍历 25 | */ 26 | public void frontShow() { 27 | if (root == null) { 28 | System.out.println("树为空"); 29 | return; 30 | } 31 | // 调用根结点的前序遍历方法 32 | root.frontShow(); 33 | // 打印一个空行,与主逻辑无关 34 | System.out.println(); 35 | } 36 | 37 | /** 38 | * 中序遍历 39 | */ 40 | public void midShow() { 41 | if (root == null) { 42 | return; 43 | } 44 | root.midShow(); 45 | System.out.println(); 46 | } 47 | 48 | /** 49 | * 后序遍历 50 | */ 51 | public void afterShow() { 52 | if (root == null) { 53 | return; 54 | } 55 | root.afterShow(); 56 | System.out.println(); 57 | } 58 | 59 | /** 60 | * 前序查找 61 | * 62 | * @param i 63 | * @return 64 | */ 65 | public TreeNode frontSearch(int i) { 66 | return root.frontSearch(i); 67 | } 68 | 69 | /** 70 | * 删除方法 71 | * 72 | * @param i 73 | */ 74 | public void delete(int i) { 75 | if (root.value == i) { 76 | root = null; 77 | return; 78 | } 79 | root.delete(i); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo5/TestBinaryTree.java: -------------------------------------------------------------------------------- 1 | package demo5; 2 | 3 | /** 4 | * 测试二叉树 5 | * @author admin 6 | */ 7 | public class TestBinaryTree { 8 | public static void main(String[] args) { 9 | /* 第 30 课,创建二叉树*/ 10 | // 创建一棵二叉树 11 | BinaryTree binTree = new BinaryTree(); 12 | 13 | // 创建一个节点作为根结点 14 | TreeNode root = new TreeNode(1); 15 | // 设置根结点 16 | binTree.setRoot(root); 17 | 18 | // 创建一个左节点 19 | TreeNode leftNode = new TreeNode(2); 20 | // 设置左节点 21 | root.setLeftNode(leftNode); 22 | 23 | // 创建一个右节点 24 | TreeNode rightNode = new TreeNode(3); 25 | // 设置右节点 26 | root.setRightNode(rightNode); 27 | 28 | /* 第 31 课,遍历二叉树*/ 29 | 30 | // 为第二层的左节点创建左右两个子节点 31 | leftNode.setLeftNode(new TreeNode(4)); 32 | leftNode.setRightNode(new TreeNode(5)); 33 | 34 | // 为第二层的右节点创建左右两个子节点 35 | rightNode.setLeftNode(new TreeNode(6)); 36 | rightNode.setRightNode(new TreeNode(7)); 37 | 38 | // 调用前序遍历方法 39 | binTree.frontShow(); 40 | 41 | // 调用中序遍历方法 42 | binTree.midShow(); 43 | 44 | // 调用后序遍历方法 45 | binTree.afterShow(); 46 | 47 | // 调用前序查找方法,查找节点值为 2 的节点 48 | TreeNode result = binTree.frontSearch(2); 49 | // 检查当前结果是否为根结点的左子节点 50 | System.out.println(result == leftNode); 51 | 52 | // 测试删除节点的方法 53 | binTree.delete(5); 54 | // 前序遍历显示节点是否被删除 55 | // 打印结果是 1 2 4 3 6 7 56 | binTree.frontShow(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo6/ArrayBinaryTree.java: -------------------------------------------------------------------------------- 1 | package demo6; 2 | 3 | /** 4 | * 顺序存储二叉树 5 | * 6 | * @author admin 7 | */ 8 | public class ArrayBinaryTree { 9 | /** 10 | * 数据以数组的形式来存储 11 | */ 12 | int[] data; 13 | 14 | /** 15 | * 构造方法 16 | * 17 | * @param data 指定数组参数 18 | */ 19 | public ArrayBinaryTree(int[] data) { 20 | this.data = data; 21 | } 22 | 23 | /** 24 | * 从根结点开始前序遍历 25 | */ 26 | public void frontShow() { 27 | // 传入根结点下标 0 28 | frontShow(0); 29 | } 30 | 31 | /** 32 | * 前序遍历 33 | * 34 | * @param index 起点的下标 35 | */ 36 | public void frontShow(int index) { 37 | // 检查边际条件 38 | if (data == null || data.length == 0) { 39 | return; 40 | } 41 | // 获取当前节点的值 42 | System.out.print(data[index] + " "); 43 | // 获取左子节点下标 44 | int leftIndex = index * 2 + 1; 45 | // 处理左子节点 46 | if (leftIndex < data.length) { 47 | // 左子节点递归调用前序遍历方法 48 | frontShow(leftIndex); 49 | } 50 | // 获取右子节点下标 51 | int rightIndex = index * 2 + 2; 52 | // 处理右子节点 53 | if (rightIndex < data.length) { 54 | // 右子节点递归调用前序遍历方法 55 | frontShow(rightIndex); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo6/TestArrayBinaryTree.java: -------------------------------------------------------------------------------- 1 | package demo6; 2 | 3 | /** 4 | * 测试顺序存储二叉树 5 | * @author admin 6 | */ 7 | public class TestArrayBinaryTree { 8 | public static void main(String[] args) { 9 | // 创建数组 10 | int[] data = new int[]{1, 2, 3, 4, 5, 6, 7}; 11 | // 创建顺序存储二叉树对象 12 | ArrayBinaryTree binTree = new ArrayBinaryTree(data); 13 | 14 | // 调用前序遍历方法 15 | // 打印结果是 1 2 4 5 3 6 7 16 | binTree.frontShow(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo7/TestThreadedBinaryTree.java: -------------------------------------------------------------------------------- 1 | package demo7; 2 | 3 | 4 | /** 5 | * 测试线索二叉树 6 | * @author admin 7 | */ 8 | public class TestThreadedBinaryTree { 9 | public static void main(String[] args) { 10 | /* 第 30 课,创建二叉树*/ 11 | // 创建一棵二叉树 12 | ThreadedBinaryTree binTree = new ThreadedBinaryTree(); 13 | 14 | // 创建一个节点作为根结点 15 | ThreadedNode root = new ThreadedNode(1); 16 | // 设置根结点 17 | binTree.setRoot(root); 18 | 19 | // 创建一个左节点 20 | ThreadedNode leftNode = new ThreadedNode(2); 21 | // 设置左节点 22 | root.setLeftNode(leftNode); 23 | 24 | /* 第 31 课,遍历二叉树*/ 25 | // 创建一个右节点 26 | ThreadedNode rightNode = new ThreadedNode(3); 27 | // 设置右节点 28 | root.setRightNode(rightNode); 29 | 30 | // 为第二层的左节点创建左右两个子节点 31 | leftNode.setLeftNode(new ThreadedNode(4)); 32 | ThreadedNode fiveNode = new ThreadedNode(5); 33 | leftNode.setRightNode(fiveNode); 34 | 35 | // 为第二层的右节点创建左右两个子节点 36 | rightNode.setLeftNode(new ThreadedNode(6)); 37 | rightNode.setRightNode(new ThreadedNode(7)); 38 | 39 | // 调用中序遍历方法 40 | // 执行结果:4 2 5 1 6 3 7 41 | binTree.midShow(); 42 | 43 | // 中序线索化二叉树 44 | binTree.threadNodes(); 45 | 46 | // 找到节点 5 的后继节点 47 | ThreadedNode afterFive = fiveNode.rightNode; 48 | // 打印后继节点的值 49 | // 执行结果为 1 50 | System.out.println(afterFive.value); 51 | 52 | // 线索化二叉树之后,遍历所有节点 53 | // 执行结果:4 2 5 1 6 3 7 54 | binTree.threadIterate(); 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /codes/java_dataStructure_luozhaoyong/src/demo9/Node.java: -------------------------------------------------------------------------------- 1 | package demo9; 2 | 3 | /** 4 | * 定义赫夫曼树的节点 5 | * 6 | * @author admin 7 | */ 8 | public class Node implements Comparable { 9 | /** 10 | * 权值 11 | */ 12 | int value; 13 | /** 14 | * 左子节点 15 | */ 16 | Node left; 17 | /** 18 | * 右子节点 19 | */ 20 | Node right; 21 | 22 | public Node(int value) { 23 | this.value = value; 24 | } 25 | 26 | /** 27 | * 覆写 compareTo 方法 28 | * 29 | * @param o 用于对比的目标节点 30 | * @return 31 | */ 32 | @Override 33 | public int compareTo(Node o) { 34 | // 返回倒序结果,让根结点权值较大的二叉树排在前面 35 | return o.value - this.value; 36 | } 37 | 38 | /** 39 | * 覆写 toString 方法 40 | * @return 41 | */ 42 | @Override 43 | public String toString() { 44 | return "Node{" + 45 | "value=" + value + 46 | '}'; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /solutions/images/017_Telephone-keypad2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hollischuang/algorithm/05c9121a00f99652ead193a0d9e7d2dadadae397/solutions/images/017_Telephone-keypad2.png -------------------------------------------------------------------------------- /solutions/images/160_example_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hollischuang/algorithm/05c9121a00f99652ead193a0d9e7d2dadadae397/solutions/images/160_example_1.png -------------------------------------------------------------------------------- /solutions/images/160_example_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hollischuang/algorithm/05c9121a00f99652ead193a0d9e7d2dadadae397/solutions/images/160_example_2.png -------------------------------------------------------------------------------- /solutions/images/160_example_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hollischuang/algorithm/05c9121a00f99652ead193a0d9e7d2dadadae397/solutions/images/160_example_3.png -------------------------------------------------------------------------------- /solutions/images/160_statement.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hollischuang/algorithm/05c9121a00f99652ead193a0d9e7d2dadadae397/solutions/images/160_statement.png -------------------------------------------------------------------------------- /solutions/leetcode/001-twoSum/README.md: -------------------------------------------------------------------------------- 1 | **1. 两数之和** 2 | --- 3 | [https://leetcode-cn.com/problems/two-sum/](https://leetcode-cn.com/problems/two-sum/) 4 | 5 | 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 6 | 7 | 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 8 | 9 | **示例:** 10 | 11 | ``` 12 | 给定 nums = [2, 7, 11, 15], target = 9 13 | 14 | 因为 nums[0] + nums[1] = 2 + 7 = 9 15 | 所以返回 [0, 1] 16 | ``` 17 | -------------------------------------------------------------------------------- /solutions/leetcode/001-twoSum/hatrick.md: -------------------------------------------------------------------------------- 1 | **1. 两数之和** 2 | --- 3 | [https://leetcode-cn.com/problems/two-sum/](https://leetcode-cn.com/problems/two-sum/) 4 | 5 | 解决方案 6 | **思路** 7 | 思路1: 根据题意我们其实可以直接使用双重for循环,然后拿到两个值相加就等于目标值的那两个下标返回即可, 8 | 只是这样的时间复杂度是O(N^2) 9 | 思路2: 我们可以转换思路,先将目标值与我们需要下标对应元素值保存起来,等到下一个我们需要的差值,就会拿到之前key, 10 | 既可以得到两个下标 11 | 12 | ``` 13 | private static int[] twoSum(int[] nums, int target) { 14 | //定义容器,存放首个下标,当有其差值出现的时候,便可以等到另一个下标 15 | Map map = new HashMap<>(); 16 | //用来存储最后返回结果 17 | int[] result = new int[2]; 18 | for (int i = 0; i < nums.length; i++) { 19 | //判断之前的key是否已经保存到map中,如果已经存在,那么当前的值加上之前的值既为目标值 20 | if (map.containsKey(target - nums[i])) { 21 | result[0] = map.get(target - nums[i]); 22 | //这个时候i所对应的元素还没有放到map中,但是我们要找的值已经找到返回即可 23 | result[1] = i; 24 | return result; 25 | } 26 | map.put(nums[i], i); 27 | } 28 | return result; 29 | } 30 | 31 | ``` 32 | **复杂度分析** 33 | 时间复杂度:O(N) 循环所有数组元素,当然根据目标值,每次查找花费O(1)时间,所以最后复杂度为O(N) 34 | 空间复杂度:O(N) 使用map数据结构,存储的元素取决于传入的元素数量 35 | 36 | 37 | **参考资料** 38 | * 本题leetCode英文官方题解: 39 | [https://leetcode-cn.com/articles/two-sum/](https://leetcode-cn.com/articles/two-sum/) 40 | -------------------------------------------------------------------------------- /solutions/leetcode/001-twoSum/woody.md: -------------------------------------------------------------------------------- 1 | >答案示例,本人自行编写后参考LeetCode官方题库。 2 | 3 | **001.两数之和** 4 | --- 5 | [https://leetcode-cn.com/problems/two-sum/](https://leetcode-cn.com/problems/two-sum/) 6 | 7 | 摘要 8 | 9 | 本文适用于初学者。 10 | 11 | 12 | ```java 13 | 14 | class Solution { 15 | //这道题虽然不难,但在解决的过程中会发现有更优质的方法去解决 16 | public int[] twoSum(int[] nums, int target) { 17 | //第一眼看到这个题的时候,很像冒泡排除,选择排序 18 | int i=0; int j=i+1; 19 | //其实这个效率低的方法直接冒泡就可以 20 | // 确定要循环几次,来走完所有的情况 21 | for(i=0;i 4 -> 3) + (5 -> 6 -> 4) 15 | 输出:7 -> 0 -> 8 16 | 原因:342 + 465 = 807 17 | ``` 18 | -------------------------------------------------------------------------------- /solutions/leetcode/002-addTwoNumber/monkey.md: -------------------------------------------------------------------------------- 1 | **1. AddTwoNumber** 2 | --- 3 | [https://leetcode.com/problems/add-two-numbers/](https://leetcode.com/problems/add-two-numbers/) 4 | 5 | - 解决思路 6 | > 题目只是单纯的要求两个数相加求和,那我们直接用迭代的方式来控制对应位置上数字两两相加。需要注意的有两点:一是需要考虑两个个位数相加的进位,超过10之后向前进一,这里用一个变量来保存进位。二是因为两个数字的长度不一定一样,长度短的如果位数不够,则用0来补足。 7 | 8 | - code(scala version) 9 | ``` 10 | def addTwoNumbers(l1: ListNode, l2: ListNode): ListNode = { 11 | 12 | var ll1 = l1 13 | var ll2 = l2 14 | 15 | //定义指向头结点的变量 16 | var result: ListNode = new ListNode() 17 | //定义一个dummy指针来指向头节点,这样可以任意的移动刚开始指向头节点的变量而不用担心头结点的丢失 18 | var dummy: ListNode = result 19 | 20 | //保存两个一位数相加后结果的十位数上的值:结果大于等于10则为1,否则为0 21 | var carry: Int = 0 22 | var sum, x, y: Int = 0 23 | while (ll1 != null || ll2 != null) { 24 | //如果当前链表的当前节点为空,则值为null 25 | if (ll1 != null) x = ll1.x else x = 0 26 | if (ll2 != null) y = ll2.x else y = 0 27 | sum = x + y + carry 28 | result.next = new ListNode(sum % 10) 29 | carry = if (sum > 9) 1 else 0 30 | result = result.next 31 | 32 | //链表当前节点不为空,则向后推移一个节点,若为空,则不变 33 | if (ll1 != null) ll1 = ll1.next 34 | if (ll2 != null) ll2 = ll2.next 35 | } 36 | //当两个链表中的所以节点都相加完之后,判断最后一个相加的结果是否超过10,超过10的时候需要额外增加一个节点来保存进位的结果 37 | if (carry == 1) result.next = new ListNode(1) 38 | //返回dummy指针的next,即结果的头指针 39 | dummy.next 40 | } 41 | ``` 42 | - 时间空间复杂度分析 43 | > 时间复杂度:O(max(m,n)) m,n分别为两个链表的长度,因为需要相应位置相加,所以需要遍历两个链表 44 | > 空间复杂度:O(max(m,n)) m,n分别为两个链表的长度,最后结果长度一定跟最大的数长度相同或者比其大一位,我们用对应长度的链表保存。 45 | 46 | - 参考资料 47 | [official solution: https://leetcode.com/problems/add-two-numbers/solution/](https://leetcode.com/problems/add-two-numbers/solution/) 48 | -------------------------------------------------------------------------------- /solutions/leetcode/003-longestSubstringWithoutRepeatingCharacters/README.md: -------------------------------------------------------------------------------- 1 | **3. 无重复字符的最长子串** 2 | --- 3 | [https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/](https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/) 4 | 5 | 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 6 | 7 | **示例 1:** 8 | 9 | ``` 10 | 输入: "abcabcbb" 11 | 输出: 3 12 | 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 13 | ``` 14 | 15 | **示例 2:** 16 | 17 | ``` 18 | 输入: "bbbbb" 19 | 输出: 1 20 | 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 21 | ``` 22 | 23 | **示例 3:** 24 | 25 | ``` 26 | 输入: "pwwkew" 27 | 输出: 3 28 | 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 29 | 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。 30 | ``` 31 | -------------------------------------------------------------------------------- /solutions/leetcode/003-longestSubstringWithoutRepeatingCharacters/monkey.md: -------------------------------------------------------------------------------- 1 | **1. 003-LongestSubstringWithoutRepeatingCharacters** 2 | --- 3 | [https://leetcode.com/problems/longest-substring-without-repeating-characters/](https://leetcode.com/problems/longest-substring-without-repeating-characters/) 4 | 5 | - 解决思路 6 | > 题目需要求解最长无重复字符的子串长度。首先依次的遍历该字符串,用一个数据结构(set,map等)来保存已经遍历过的字符,当前字符没有出现过,则将其添加到我们定义的数据结构中,当前无重复子串长度加一。如果当前字符出现过,则需要将数据结构中与该字符相同字符之前的字符全部删除,并重新计数新的子串长度。此处需要用一个变量来保存之前无重复子串的最大长度,每次出现重复字符时都要跟之前最大的长度比较判断是否需要更新。 7 | 8 | - code(scala version) 9 | ``` 10 | def lengthOfLongestSubstringWithSet(s: String): Int ={ 11 | //传入的string的长度 12 | var length = s.length 13 | //用set保存出现过的字符 14 | var elemSet: Set[Char] = Set() 15 | 16 | var begin, end = 0 17 | //用来保存当前所计算的最长长度 18 | var maxLength = 0 19 | while(begin < length && end < length){ 20 | //如果set中不包含当前字符,则将当前字符添加入set,并向后移动给一个字符 21 | if(!elemSet.contains(s.charAt(end))){ 22 | elemSet += s.charAt(end) 23 | end = end +1 24 | //更新maxLength,此处是重点:注意一定要用max函数比较 当前的不重复字符串长度 与 上一次出现重复字符时记录的最长不重复字符串长度 25 | maxLength = Math.max(maxLength , end - begin) 26 | } else{ 27 | //如果set中包含当前字符,则利用循环将出现重复字符之前的字符全部从set中删除,保证set所留的都是需要重新计算长度的字符 28 | do { 29 | elemSet -= s.charAt(begin) 30 | begin = begin + 1 31 | } while(s.charAt(begin-1)!=s.charAt(end)) 32 | } 33 | } 34 | 35 | maxLength 36 | } 37 | ``` 38 | - 时间空间复杂度分析 39 | > 时间复杂度:O(n) n为字符串长度,此处需要遍历两次字符串,所以时间复杂度为O(2n)=O(n) 40 | > 空间复杂度:O(min(m,n)) 因为我们需要O(k)的空间来保存无重复字符的子串。k的最大长度不会超过原始字符串的长度n,也不会超过原始字符串中字符所在的字符表或者字母表集合的大小m。k取m和n的最小值。 41 | 42 | - 参考资料 43 | [https://leetcode.com/problems/longest-substring-without-repeating-characters/solution/](https://leetcode.com/problems/longest-substring-without-repeating-characters/solution/) -------------------------------------------------------------------------------- /solutions/leetcode/003-longestSubstringWithoutRepeatingCharacters/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 3.给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 2 | 3 | 示例 1: 4 | 5 | 输入: "abcabcbb" 6 | 输出: 3 7 | 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 8 | 示例 2: 9 | 10 | 输入: "bbbbb" 11 | 输出: 1 12 | 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 13 | 示例 3: 14 | 15 | 输入: "pwwkew" 16 | 输出: 3 17 | 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 18 | 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。 19 | 20 | 思路: 21 | 22 | ```py 23 | def lengthOfLongestSubstring(self, s): 24 | lookup = collections.defaultdict(int) 25 | l, r, counter, res = 0, 0, 0, 0 # counter 为当前子串中 unique 字符的数量 26 | while r < len(s): 27 | lookup[s[r]] += 1 28 | if lookup[s[r]] == 1: # 遇到了当前子串中未出现过的字符 29 | counter += 1 30 | r += 1 31 | # counter < r - l 说明有重复字符出现,否则 counter 应该等于 r - l 32 | while l < r and counter < r - l: 33 | lookup[s[l]] -= 1 34 | if lookup[s[l]] == 0: # 当前子串中的一种字符完全消失了 35 | counter -= 1 36 | l += 1 37 | res = max(res, r - l) # 当前子串满足条件了,更新最大长度 38 | return res 39 | ``` 40 | 时间复杂度:O(n^2) 41 | 42 | 空间复杂度:O(n) 43 | -------------------------------------------------------------------------------- /solutions/leetcode/005-LongestPalindromicSubstring/official.md: -------------------------------------------------------------------------------- 1 | **5. 最长回文子串** 2 | --- 3 | [https://leetcode-cn.com/problems/longest-palindromic-substring/](https://leetcode-cn.com/problems/longest-palindromic-substring/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/006-ZigZagConversion/README.md: -------------------------------------------------------------------------------- 1 | **6. Z 字形变换** 2 | --- 3 | [https://leetcode-cn.com/problems/zigzag-conversion/](https://leetcode-cn.com/problems/zigzag-conversion/) 4 | 5 | 将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。 6 | 7 | 比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下: 8 | 9 | ``` 10 | L C I R 11 | E T O E S I I G 12 | E D H N 13 | ``` 14 | 15 | 之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"。 16 | 17 | 请你实现这个将字符串进行指定行数变换的函数: 18 | 19 | ``` 20 | string convert(string s, int numRows); 21 | ``` 22 | 23 | **示例 1:** 24 | 25 | ``` 26 | 输入: s = "LEETCODEISHIRING", numRows = 3 27 | 输出: "LCIRETOESIIGEDHN" 28 | ``` 29 | 30 | **示例 2:** 31 | 32 | ``` 33 | 输入: s = "LEETCODEISHIRING", numRows = 4 34 | 输出: "LDREOEIIECIHNTSG" 35 | 解释: 36 | 37 | L D R 38 | E O E I I 39 | E C I H N 40 | T S G 41 | ``` 42 | -------------------------------------------------------------------------------- /solutions/leetcode/006-ZigZagConversion/zengdiqing.md: -------------------------------------------------------------------------------- 1 | 6.将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。 2 | 3 | 比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下: 4 | 5 | L C I R 6 | E T O E S I I G 7 | E D H N 8 | 之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"。 9 | 10 | 请你实现这个将字符串进行指定行数变换的函数: 11 | 12 | string convert(string s, int numRows); 13 | 示例 1: 14 | 15 | 输入: s = "LEETCODEISHIRING", numRows = 3 16 | 输出: "LCIRETOESIIGEDHN" 17 | 示例 2: 18 | 19 | 输入: s = "LEETCODEISHIRING", numRows = 4 20 | 输出: "LDREOEIIECIHNTSG" 21 | 解释: 22 | 23 | L D R 24 | E O E I I 25 | E C I H N 26 | T S G 27 | 28 | 思路:idx从0开始,自增直到numRows-1,此后又一直自减到0,重复执行。 29 | 30 | 从第一行开始往下,走到第四行又往上走,这里用 step = 1 代表往下走, step = -1 代表往上走 31 | 32 | 因为只会有一次遍历,同时把每一行的元素都存下来,所以时间复杂度和空间复杂度都是 O(N) 33 | 34 | ```py 35 | class Solution: 36 | def convert(self, s: str, numRows: int) -> str: 37 | if numRows==1 or numRows>=len(s): 38 | return s #判断情况 39 | res = [''] * numRows #初始化res结果 40 | idx, step = 0, 1 41 | for c in s: 42 | res[idx] += c #把字符加入res中 43 | if idx == 0: 44 | step = 1 #step向下加一 45 | elif idx == numRows-1: #一直到最后一行为止 46 | step = -1 #向上操作 47 | idx += step #idx代表第几行 48 | return ''.join(res) 49 | ``` 50 | 时间复杂度: O(n) 51 | 空间复杂度: O(1) 52 | -------------------------------------------------------------------------------- /solutions/leetcode/015-threeSum/official.md: -------------------------------------------------------------------------------- 1 | **15. 三数之和** 2 | --- 3 | [https://leetcode-cn.com/problems/3sum/](https://leetcode-cn.com/problems/3sum/) 4 | 5 | -------------------------------------------------------------------------------- /solutions/leetcode/017-LetterCombinationsOfAPhoneNumber/README.md: -------------------------------------------------------------------------------- 1 | **17. 电话号码的字母组合** 2 | --- 3 | [https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/](https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/) 4 | 5 | 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 6 | 7 | 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 8 | ![017_Telephone-keypad2](https://raw.githubusercontent.com/hollischuang/algorithm/master/images/017_Telephone-keypad2.png) 9 | 10 | **示例:** 11 | 12 | ``` 13 | 输入:"23" 14 | 输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. 15 | ``` 16 | 17 | **说明:** 18 | 尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。 19 | -------------------------------------------------------------------------------- /solutions/leetcode/020-validParentheses/official.md: -------------------------------------------------------------------------------- 1 | **20. 有效的括号** 2 | --- 3 | [https://leetcode-cn.com/problems/valid-parentheses/](https://leetcode-cn.com/problems/valid-parentheses/) 4 | 5 | -------------------------------------------------------------------------------- /solutions/leetcode/023-MergeKSortedLists/README.md: -------------------------------------------------------------------------------- 1 | **23. 合并K个排序链表** 2 | --- 3 | [https://leetcode-cn.com/problems/merge-k-sorted-lists/](https://leetcode-cn.com/problems/merge-k-sorted-lists/) 4 | 5 | 合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。 6 | 7 | **示例:** 8 | 9 | ``` 10 | 输入: 11 | [ 12 | 1->4->5, 13 | 1->3->4, 14 | 2->6 15 | ] 16 | 输出: 1->1->2->3->4->4->5->6 17 | ``` 18 | -------------------------------------------------------------------------------- /solutions/leetcode/024-swapNodesInPairs/official.md: -------------------------------------------------------------------------------- 1 | **24. 两两交换链表中的节点** 2 | --- 3 | [https://leetcode-cn.com/problems/swap-nodes-in-pairs/](https://leetcode-cn.com/problems/swap-nodes-in-pairs/) 4 | 5 | -------------------------------------------------------------------------------- /solutions/leetcode/025-reverseNodesInKGroup/official.md: -------------------------------------------------------------------------------- 1 | **25. k个一组翻转链表** 2 | --- 3 | [https://leetcode-cn.com/problems/reverse-nodes-in-k-group/](https://leetcode-cn.com/problems/reverse-nodes-in-k-group/) 4 | 5 | -------------------------------------------------------------------------------- /solutions/leetcode/032-LongestValidParentheses/official.md: -------------------------------------------------------------------------------- 1 | **32. 最长有效括号** 2 | --- 3 | [https://leetcode-cn.com/problems/longest-valid-parentheses/](https://leetcode-cn.com/problems/longest-valid-parentheses/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/033-SearchInRotatedSortedArray/README.md: -------------------------------------------------------------------------------- 1 | **33. 搜索旋转排序数组** 2 | --- 3 | [https://leetcode-cn.com/problems/search-in-rotated-sorted-array/](https://leetcode-cn.com/problems/search-in-rotated-sorted-array/) 4 | 5 | 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 6 | 7 | ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 8 | 9 | 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 10 | 11 | 你可以假设数组中不存在重复的元素。 12 | 13 | 你的算法时间复杂度必须是 O(log n) 级别。 14 | 15 | **示例 1:** 16 | 17 | ``` 18 | 输入: nums = [4,5,6,7,0,1,2], target = 0 19 | 输出: 4 20 | ``` 21 | 22 | **示例 2:** 23 | 24 | ``` 25 | 输入: nums = [4,5,6,7,0,1,2], target = 3 26 | 输出: -1 27 | ``` 28 | -------------------------------------------------------------------------------- /solutions/leetcode/033-SearchInRotatedSortedArray/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 33.假设按照升序排序的数组在预先未知的某个点上进行了旋转。 2 | 3 | ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 4 | 5 | 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 6 | 7 | 你可以假设数组中不存在重复的元素。 8 | 9 | 你的算法时间复杂度必须是 O(log n) 级别。 10 | 11 | 示例 1: 12 | 13 | 输入: nums = [4,5,6,7,0,1,2], target = 0 14 | 输出: 4 15 | 示例 2: 16 | 17 | 输入: nums = [4,5,6,7,0,1,2], target = 3 18 | 输出: -1 19 | 20 | 思路:二分法 21 | 22 | 这道题让在旋转数组中搜索一个给定值,若存在返回坐标,若不存在返回-1。我们还是考虑二分搜索法,但是这道题的难点在于我们不知道原数组在哪旋转了,我们还是 23 | 用题目中给的例子来分析,对于数组[0 1 2 4 5 6 7] 共有下列七种旋转方法: 24 | 25 | 0  1  2   **4  5  6  7** 26 | 27 | 7  0  1   2  4  5  6 28 | 29 | 6  7  0   1  2  4  5 30 | 31 | 5  6  7   0  1  2  4 32 | 33 | 4  5  6  7  0  1  2 34 | 35 | 2  4  5  6  7  0  1 36 | 37 | 1  2  4  5  6  7  0 38 | 39 | 二分搜索法的关键在于获得了中间数后,判断下面要搜索左半段还是右半段,我们观察上面粗体的数字都是升序的,由此我们可以观察出规律,如果中间的数小于最右边 40 | 的数,则右半段是有序的,若中间数大于最右边数,则左半段是有序的,我们只要在有序的半段里用首尾两个数组来判断目标值是否在这一区域内,这样就可以确定保留 41 | 哪半边了. 42 | 43 | ```py 44 | def search(nums,target): 45 | l, r = 0, len(nums) - 1 46 | while l < r: 47 | mid = l + ((r-l)>>2) 48 | if nums[mid] == target: 49 | return mid 50 | if nums[mid] < nums[r]: 51 | if nums[mid] < target <= nums[r]: 52 | l = mid + 1 53 | else: 54 | r = mid - 1 55 | else: 56 | if nums[l] <= target < nums[mid] 57 | r = mid - 1 58 | else: 59 | l = mid + 1 60 | return -1 61 | ``` 62 | 63 | 时间复杂度:O(lgn) 64 | 空间复杂度:O(1) 65 | -------------------------------------------------------------------------------- /solutions/leetcode/036-ValidSudoku/official.md: -------------------------------------------------------------------------------- 1 | **36. 有效的数独** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/valid-sudoku/](https://leetcode-cn.com/problems/valid-sudoku/) 5 | -------------------------------------------------------------------------------- /solutions/leetcode/037-SudokuSolver/official.md: -------------------------------------------------------------------------------- 1 | **37. 解数独** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/sudoku-solver/](https://leetcode-cn.com/problems/sudoku-solver/) 5 | -------------------------------------------------------------------------------- /solutions/leetcode/048-RotateImage/README.md: -------------------------------------------------------------------------------- 1 | **48. 旋转图像** 2 | --- 3 | [https://leetcode-cn.com/problems/rotate-image/](https://leetcode-cn.com/problems/rotate-image/) 4 | 5 | 给定一个 n × n 的二维矩阵表示一个图像。 6 | 7 | 将图像顺时针旋转 90 度。 8 | 9 | **说明:** 10 | 11 | 你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。 12 | 请**不要**使用另一个矩阵来旋转图像。 13 | 14 | **示例 1:** 15 | 16 | ``` 17 | 给定 matrix = 18 | [ 19 | [1,2,3], 20 | [4,5,6], 21 | [7,8,9] 22 | ], 23 | 24 | 原地旋转输入矩阵,使其变为: 25 | [ 26 | [7,4,1], 27 | [8,5,2], 28 | [9,6,3] 29 | ] 30 | ``` 31 | 32 | **示例 2:** 33 | 34 | ``` 35 | 给定 matrix = 36 | [ 37 | [ 5, 1, 9,11], 38 | [ 2, 4, 8,10], 39 | [13, 3, 6, 7], 40 | [15,14,12,16] 41 | ], 42 | 43 | 原地旋转输入矩阵,使其变为: 44 | [ 45 | [15,13, 2, 5], 46 | [14, 3, 4, 1], 47 | [12, 6, 8, 9], 48 | [16, 7,10,11] 49 | ] 50 | ``` 51 | -------------------------------------------------------------------------------- /solutions/leetcode/048-RotateImage/zengdiqing.md: -------------------------------------------------------------------------------- 1 | 48.你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。 2 | 3 | 示例 1: 4 | 5 | 给定 matrix = 6 | [ 7 | [1,2,3], 8 | [4,5,6], 9 | [7,8,9] 10 | ], 11 | 12 | 原地旋转输入矩阵,使其变为: 13 | [ 14 | [7,4,1], 15 | [8,5,2], 16 | [9,6,3] 17 | ] 18 | 示例 2: 19 | 20 | 给定 matrix = 21 | [ 22 | [ 5, 1, 9,11], 23 | [ 2, 4, 8,10], 24 | [13, 3, 6, 7], 25 | [15,14,12,16] 26 | ], 27 | 28 | 原地旋转输入矩阵,使其变为: 29 | [ 30 | [15,13, 2, 5], 31 | [14, 3, 4, 1], 32 | [12, 6, 8, 9], 33 | [16, 7,10,11] 34 | ] 35 | 36 | 思路:先用一个临时变量放置非对角线的数字,然后再把几行数组反过来排列 37 | 38 | ``` 39 | def rotate(matrix): 40 | length = len(matrix) 41 | for i in range(length): 42 | for j in range(i+1,length): 43 | temp = matrix[i][j] 44 | matrix[i][j] = matrix[j][i] 45 | matrix[j][i] = temp 46 | for i in range(length): 47 | matrix[i] = matrix[i][::-1] 48 | return matrix 49 | ``` 50 | 时间复杂度:O(n^2) 51 | 空间复杂度:O(n) 52 | -------------------------------------------------------------------------------- /solutions/leetcode/050-powxN/bigablecat.md: -------------------------------------------------------------------------------- 1 | **50. Pow(x, n)** 2 | --- 3 | [https://leetcode-cn.com/problems/powx-n/](https://leetcode-cn.com/problems/powx-n/) 4 | 5 | 6 | * 网友高票Java解法,递归分治 7 | 8 | ```java 9 | 10 | public double myPow(double x, int n) { 11 | //如果n==0,返回1,因为x的0次方为1 12 | if (n == 0) 13 | return 1; 14 | if (n < 0) { 15 | //因为 n = -1*(-n),所以x的n次方等于x的-1次方的-n次方 16 | //所以n等于负数时进行如下两步操作 17 | // n = -n让n变为正 18 | n = -n; 19 | //让x成为x的倒数 20 | x = 1 / x; 21 | //判断原来的n值是否超出了JavaInteger的下界 22 | if (-n == Integer.MIN_VALUE) { 23 | //考虑到Java语言中Integer的取值范围在-2147483648到2147483647之间 24 | //Integer.MIN_VALUE = -2147483648, 25 | //Integer.MAX_VALUE = 2147483647, 26 | //当n的值在取值范围之外,编译无法通过,不予考虑 27 | //当 n = -2147483648 时,让 n = -n 得到 n = 2147483648 超过了Integer.MAX_VALUE=2147483647 28 | //为了避免这种情况,在n = -n = 2147483648后 29 | //让n-1 = 2147483647,同时取出一个x,按照奇数的计算方式返回结果 30 | return x * myPow(x, (n - 1)); 31 | } 32 | } 33 | //接下来进行分治,将求x的n次方转变为求x平方的(n/2)次方 34 | //判断n是否为偶数,如果是偶数,只需递归调用myPow,如果是奇数,取出一个x,再与myPow结果相乘 35 | return (n % 2 == 0) ? myPow(x * x, n / 2) : x * myPow(x * x, n / 2); 36 | } 37 | 38 | 39 | ``` 40 | 41 | **复杂度分析** 42 | 43 | 时间复杂度:O(logn), 44 | 每次递归,n就被2分一次,n/2/2..., 45 | 所以总共调用递归方法的次数是logn次, 46 | 递归方法中没有循环,只有常数级的操作, 47 | 所以总的时间复杂度是O(logn) 48 | 49 | 空间复杂度:O(logn), 50 | 每次递归都占用O(1)的空间 51 | 52 | --- 53 | 54 | **参考资料** 55 | 56 | * 网友高票Java解法: 57 | [https://leetcode.com/problems/powx-n/discuss/19546/Short-and-easy-to-understand-solution](https://leetcode.com/problems/powx-n/discuss/19546/Short-and-easy-to-understand-solution) 58 | -------------------------------------------------------------------------------- /solutions/leetcode/051-NQueens/official.md: -------------------------------------------------------------------------------- 1 | **51. N-皇后** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/n-queens/](https://leetcode-cn.com/problems/n-queens/) 5 | -------------------------------------------------------------------------------- /solutions/leetcode/052-N-QueensII/hatrick.md: -------------------------------------------------------------------------------- 1 | **52. N皇后 II** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/n-queens-ii/](https://leetcode-cn.com/problems/n-queens-ii/) 5 | 6 | ```java 7 | 8 | public class NQueenII { 9 | private int count = 0; 10 | 11 | public int totalNQueens(int n) { 12 | int[] x = new int[n]; 13 | queens(x, n, 0); 14 | return count; 15 | } 16 | 17 | private void queens(int[] x, int n, int row) { 18 | for (int i = 0; i < n; i++) { 19 | //判断是否合法 20 | if (check(x, n, row, i)) { 21 | //将皇后放在第row行,第i列 22 | x[row] = i; 23 | //如果是最后一行,则输出结果 24 | if (row == n - 1) { 25 | count++; 26 | //回溯,寻找下一个结果 27 | x[row] = 0; 28 | return; 29 | } 30 | //寻找下一行 31 | queens(x, n, row + 1); 32 | //回溯 33 | x[row] = 0; 34 | } 35 | } 36 | } 37 | 38 | /** 39 | * @param x 数组解 40 | * @param n 棋盘长宽 41 | * @param row 当前放置行 42 | * @param col 当前放置列 43 | * @return 44 | */ 45 | private boolean check(int[] x, int n, int row, int col) { 46 | for (int i = 0; i < row; i++) { 47 | if (x[i] == col || x[i] + i == col + row || x[i] - i == col - row) { 48 | return false; 49 | } 50 | } 51 | return true; 52 | } 53 | } 54 | 55 | ``` 56 | --- 57 | 58 | 59 | **参考资料** 60 | 61 | [https://blog.csdn.net/xygy8860/article/details/46861817](https://blog.csdn.net/xygy8860/article/details/46861817) 62 | -------------------------------------------------------------------------------- /solutions/leetcode/052-N-QueensII/official.md: -------------------------------------------------------------------------------- 1 | **52. N皇后 II** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/n-queens-ii/](https://leetcode-cn.com/problems/n-queens-ii/) 5 | -------------------------------------------------------------------------------- /solutions/leetcode/053-maximumSubarray/README.md: -------------------------------------------------------------------------------- 1 | **53. 最大子序和** 2 | --- 3 | [https://leetcode-cn.com/problems/maximum-subarray/](https://leetcode-cn.com/problems/maximum-subarray/) 4 | 5 | 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 6 | 7 | **示例:** 8 | 9 | ``` 10 | 输入: [-2,1,-3,4,-1,2,1,-5,4], 11 | 输出: 6 12 | 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 13 | ``` 14 | -------------------------------------------------------------------------------- /solutions/leetcode/053-maximumSubarray/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 53.给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 2 | 3 | 示例: 4 | 5 | 输入: [-2,1,-3,4,-1,2,1,-5,4], 6 | 输出: 6 7 | 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 8 | 9 | 思路:用DP来求解,只关注:当前值和当前值+过去的状态,是变好还是变坏 10 | 11 | 状态定义方程:maxSum = [nums[0] for i in range(n)] 12 | 13 | 状态转移:maxSum[i] = max(maxSum[i-1] + nums[i],nums[i]),一个是加上nums[i]的,另一个是从a[i]起头,重新开始。 14 | 15 | ```py 16 | class Solution: 17 | def maxSubArray(self, nums: List[int]) -> int: 18 | n = len(nums) 19 | maxSum = [nums[0] for i in range(n)] 20 | for i in range(1,n): 21 | maxSum[i] = max(maxSum[i-1] + nums[i],nums[i]) 22 | return max(maxSum) 23 | ``` 24 | 25 | 时间复杂度O(n) 26 | 空间复杂度O(1) 27 | -------------------------------------------------------------------------------- /solutions/leetcode/054-SpiralMatrix/README.md: -------------------------------------------------------------------------------- 1 | **54. 螺旋矩阵** 2 | --- 3 | [https://leetcode-cn.com/problems/spiral-matrix/](https://leetcode-cn.com/problems/spiral-matrix/) 4 | 5 | 给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。 6 | 7 | **示例 1:** 8 | 9 | ``` 10 | 输入: 11 | [ 12 | [ 1, 2, 3 ], 13 | [ 4, 5, 6 ], 14 | [ 7, 8, 9 ] 15 | ] 16 | 输出: [1,2,3,6,9,8,7,4,5] 17 | ``` 18 | 19 | **示例 2:** 20 | 21 | ``` 22 | 输入: 23 | [ 24 | [1, 2, 3, 4], 25 | [5, 6, 7, 8], 26 | [9,10,11,12] 27 | ] 28 | 输出: [1,2,3,4,8,12,11,10,9,5,6,7] 29 | ``` 30 | -------------------------------------------------------------------------------- /solutions/leetcode/054-SpiralMatrix/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 54.给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。 2 | 3 | 示例 1: 4 | 5 | 输入: 6 | [ 7 | [ 1, 2, 3 ], 8 | [ 4, 5, 6 ], 9 | [ 7, 8, 9 ] 10 | ] 11 | 输出: [1,2,3,6,9,8,7,4,5] 12 | 示例 2: 13 | 14 | 输入: 15 | [ 16 | [1, 2, 3, 4], 17 | [5, 6, 7, 8], 18 | [9,10,11,12] 19 | ] 20 | 输出: [1,2,3,4,8,12,11,10,9,5,6,7] 21 | 22 | 思路:用四个变量来控制辩解,方向总是“左右上下”,这个和Z字形变换很像。 23 | 24 | ```py 25 | def spiralOrder(matrix): 26 | if matrix == []: 27 | return [] 28 | res = [] 29 | maxUp = maxLeft = 0 30 | maxDown = len(matrix) - 1 31 | maxRight = len(matrix[0]) - 1 32 | direction = 0 # 0 go right , 1 go down, 2 go left, 3 up 33 | while True: 34 | if direction == 0: # go right 35 | for i in range(maxLeft,maxRight+1): 36 | res.append(matrix[maxUp][i]) 37 | maxUp += 1 38 | elif direction == 1: # 1 go down 39 | for i in range(maxUp,maxDown+1): 40 | res.append(matrix[i][maxRight]) 41 | maxRight -= 1 42 | elif direction == 2: # go left 43 | for i in reversed(range(maxLeft,maxRight+1)): 44 | res.append(matrix[maxDown][i]) 45 | maxDown -= 1 46 | else: # go up 47 | for i in reversed(range(maxUp,maxDown+1)): 48 | res.append(matrix[i][maxLeft]) 49 | maxLeft += 1 50 | if maxUp > maxDown or maxLeft > maxRight: 51 | return res 52 | direction = (direction + 1) % 4 # direction = 3之后就是0重新开始 53 | ``` 54 | 时间复杂度:O(m*n) 55 | 56 | 空间复杂度:O(1) 57 | -------------------------------------------------------------------------------- /solutions/leetcode/059-SpiralMatrixII/README.md: -------------------------------------------------------------------------------- 1 | **59. 螺旋矩阵 II** 2 | --- 3 | [https://leetcode-cn.com/problems/spiral-matrix-ii/](https://leetcode-cn.com/problems/spiral-matrix-ii/) 4 | 5 | 给定一个正整数 n,生成一个包含 1 到 n2 所有元素, 6 | 且元素按顺时针顺序螺旋排列的正方形矩阵。 7 | 8 | **示例:** 9 | 10 | ``` 11 | 输入: 3 12 | 输出: 13 | [ 14 | [ 1, 2, 3 ], 15 | [ 8, 9, 4 ], 16 | [ 7, 6, 5 ] 17 | ] 18 | ``` 19 | -------------------------------------------------------------------------------- /solutions/leetcode/059-SpiralMatrixII/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 59.给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。 2 | 3 | 示例: 4 | 5 | 输入: 3 6 | 输出: 7 | [ 8 | [ 1, 2, 3 ], 9 | [ 8, 9, 4 ], 10 | [ 7, 6, 5 ] 11 | ] 12 | 13 | 思路:和之前的那道螺旋矩阵题类似,只不过这次要自己生成一个矩阵 14 | 15 | ```py 16 | class Solution: 17 | def generateMatrix(self, n: int) -> List[List[int]]: 18 | curNum = 0 19 | matrix = [[0 for i in range(n)] for j in range(n)] #生成一个矩阵 20 | maxUp = maxLeft = 0 21 | maxDown = maxRight = n - 1 22 | direction = 0 23 | while True: 24 | if direction == 0: 25 | for i in range(maxLeft,maxRight+1): 26 | curNum += 1 27 | matrix[maxUp][i] = curNum #依次按顺序递增赋值 28 | maxUp += 1 29 | elif direction == 1: 30 | for i in range(maxUp,maxDown+1): 31 | curNum += 1 32 | matrix[i][maxRight] = curNum 33 | maxRight -= 1 34 | elif direction == 2: 35 | for i in reversed(range(maxLeft,maxRight+1)): 36 | curNum += 1 37 | matrix[maxDown][i] = curNum 38 | maxDown -= 1 39 | else: 40 | for i in reversed(range(maxUp,maxDown+1)): 41 | curNum += 1 42 | matrix[i][maxLeft] = curNum 43 | maxLeft += 1 44 | if curNum >= n*n: 45 | return matrix 46 | direction = (direction + 1) % 4 47 | ``` 48 | 时间复杂度O(N^2) 49 | 空间复杂度O(N) 50 | -------------------------------------------------------------------------------- /solutions/leetcode/062-UniquePaths/official.md: -------------------------------------------------------------------------------- 1 | **62. 不同路径** 2 | --- 3 | [https://leetcode-cn.com/problems/unique-paths/](https://leetcode-cn.com/problems/unique-paths/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/063-UniquePathsII/official.md: -------------------------------------------------------------------------------- 1 | **63. 不同路径 II** 2 | --- 3 | [https://leetcode-cn.com/problems/unique-paths-ii/](https://leetcode-cn.com/problems/unique-paths-ii/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/064-minimumPathSum/README.md: -------------------------------------------------------------------------------- 1 | **64. 最小路径和** 2 | --- 3 | [https://leetcode-cn.com/problems/minimum-path-sum/](https://leetcode-cn.com/problems/minimum-path-sum/) 4 | 5 | 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 6 | 7 | 说明:每次只能向下或者向右移动一步。 8 | 9 | **示例:** 10 | 11 | ``` 12 | 输入: 13 | [ 14 | [1,3,1], 15 | [1,5,1], 16 | [4,2,1] 17 | ] 18 | 输出: 7 19 | 解释: 因为路径 1→3→1→1→1 的总和最小。 20 | ``` 21 | -------------------------------------------------------------------------------- /solutions/leetcode/069-SqrtX/README.md: -------------------------------------------------------------------------------- 1 | **69. x 的平方根** 2 | --- 3 | [https://leetcode-cn.com/problems/sqrtx/](https://leetcode-cn.com/problems/sqrtx/) 4 | 5 | 实现 ```int sqrt(int x)``` 函数。 6 | 7 | 计算并返回 x 的平方根,其中 x 是非负整数。 8 | 9 | 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 10 | 11 | **示例 1:** 12 | 13 | ``` 14 | 输入: 4 15 | 输出: 2 16 | ``` 17 | 18 | **示例 2:** 19 | 20 | ``` 21 | 输入: 8 22 | 输出: 2 23 | 说明: 8 的平方根是 2.82842..., 24 | 由于返回类型是整数,小数部分将被舍去。 25 | ``` 26 | -------------------------------------------------------------------------------- /solutions/leetcode/069-SqrtX/bigablecat.md: -------------------------------------------------------------------------------- 1 | **69. x 的平方根** 2 | --- 3 | [https://leetcode-cn.com/problems/sqrtx/](https://leetcode-cn.com/problems/sqrtx/) 4 | 5 | * 网友高票Java题解: 6 | 7 | ```java 8 | /** 9 | * https://leetcode.com/problems/sqrtx/discuss/25047/A-Binary-Search-Solution 10 | * 网友高票答案 11 | * 12 | * @param x 13 | * @return 14 | */ 15 | public static int mySqrt(int x) { 16 | //如果x是0,平方根为0 17 | if (x == 0){ 18 | //直接返回结果0 19 | return 0; 20 | } 21 | //分别设定左右边界left和right 22 | //left从非负整数1开始,right到java运行的整数最大值上限Integer.MAX_VALUE为止 23 | int left = 1, right = x; 24 | //while (true) 进行一个无限循环,只能在方法体内结束循环 25 | while (true) { 26 | // 通过二分法不断缩小取值范围 27 | // 目标是找到一个中间值mid,如果x介于mid²和(mid+1)²之间 28 | // 那么mid就是x平方根的整数部分 29 | int mid = left + (right - left) / 2; 30 | // mid > x/mid 等价于 mid² > x 31 | // 说明mid本身比x的平方根大 32 | if (mid > x / mid) { 33 | //将mid-1赋值给右边界right,在小于mid的范围内继续寻找x的平方根 34 | right = mid - 1; 35 | } else { 36 | // mid + 1 > x/(mid + 1) 等价于 (mid + 1)² > x 37 | // 说明 (mid + 1) 比 x 的平方根大 38 | if (mid + 1 > x / (mid + 1)) 39 | // mid 小于或等于 x 的平方根 40 | // (mid + 1) 大于 x 的平方根 41 | // mid 即是要找的数字 42 | return mid; 43 | //如果 (mid + 1)² < 44 | left = mid + 1; 45 | } 46 | } 47 | } 48 | 49 | ``` 50 | 51 | **参考资料** 52 | 53 | * 网友高票Java解法: 54 | [https://leetcode.com/problems/sqrtx/discuss/25047/A-Binary-Search-Solution](https://leetcode.com/problems/sqrtx/discuss/25047/A-Binary-Search-Solution) 55 | -------------------------------------------------------------------------------- /solutions/leetcode/070-ClimbingStairs/README.md: -------------------------------------------------------------------------------- 1 | **70. 爬楼梯** 2 | --- 3 | [https://leetcode-cn.com/problems/climbing-stairs/](https://leetcode-cn.com/problems/climbing-stairs/) 4 | 5 | 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 6 | 7 | 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 8 | 9 | 注意:给定 n 是一个正整数。 10 | 11 | **示例 1:** 12 | 13 | ``` 14 | 输入: 2 15 | 输出: 2 16 | 解释: 有两种方法可以爬到楼顶。 17 | 1. 1 阶 + 1 阶 18 | 2. 2 阶 19 | ``` 20 | 21 | **示例 2:** 22 | 23 | ``` 24 | 输入: 3 25 | 输出: 3 26 | 解释: 有三种方法可以爬到楼顶。 27 | 1. 1 阶 + 1 阶 + 1 阶 28 | 2. 1 阶 + 2 阶 29 | 3. 2 阶 + 1 阶 30 | ``` 31 | -------------------------------------------------------------------------------- /solutions/leetcode/072-EditDistance/official.md: -------------------------------------------------------------------------------- 1 | **72. 编辑距离** 2 | --- 3 | [https://leetcode-cn.com/problems/edit-distance/](https://leetcode-cn.com/problems/edit-distance/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/075-SortColors/README.md: -------------------------------------------------------------------------------- 1 | **75. 颜色分类** 2 | --- 3 | [https://leetcode-cn.com/problems/sort-colors/](https://leetcode-cn.com/problems/sort-colors/) 4 | 5 | 给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 6 | 7 | 此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 8 | 9 | **注意:** 10 | 不能使用代码库中的排序函数来解决这道题。 11 | 12 | **示例:** 13 | 14 | ``` 15 | 输入: [2,0,2,1,1,0] 16 | 输出: [0,0,1,1,2,2] 17 | ``` 18 | 19 | **进阶:** 20 | 21 | * 一个直观的解决方案是使用计数排序的两趟扫描算法。 22 | 首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。 23 | 24 | * 你能想出一个仅使用常数空间的一趟扫描算法吗? 25 | -------------------------------------------------------------------------------- /solutions/leetcode/076-MinimumWindowSubstring/README.md: -------------------------------------------------------------------------------- 1 | **76. 最小覆盖子串** 2 | --- 3 | [https://leetcode-cn.com/problems/minimum-window-substring/](https://leetcode-cn.com/problems/minimum-window-substring/) 4 | 5 | 给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。 6 | 7 | **示例:** 8 | 9 | ``` 10 | 输入: S = "ADOBECODEBANC", T = "ABC" 11 | 输出: "BANC" 12 | ``` 13 | 14 | **说明:** 15 | 16 | * 如果 S 中不存这样的子串,则返回空字符串 ""。 17 | * 如果 S 中存在这样的子串,我们保证它是唯一的答案。 18 | -------------------------------------------------------------------------------- /solutions/leetcode/087-ScrambleString/official.md: -------------------------------------------------------------------------------- 1 | **87. 扰乱字符串** 2 | --- 3 | [https://leetcode-cn.com/problems/scramble-string/](https://leetcode-cn.com/problems/scramble-string/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/091-DecodeWays/official.md: -------------------------------------------------------------------------------- 1 | **91. 解码方法** 2 | --- 3 | [https://leetcode-cn.com/problems/decode-ways/](https://leetcode-cn.com/problems/decode-ways/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/095-UniqueBinarySearchTreesII/official.md: -------------------------------------------------------------------------------- 1 | **95. 不同的二叉搜索树 II** 2 | --- 3 | [https://leetcode-cn.com/problems/unique-binary-search-trees-ii/](https://leetcode-cn.com/problems/unique-binary-search-trees-ii/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/096-uniqueBinarySearchTrees/official.md: -------------------------------------------------------------------------------- 1 | **96. 不同的二叉搜索树** 2 | --- 3 | [https://leetcode-cn.com/problems/unique-binary-search-trees/](https://leetcode-cn.com/problems/unique-binary-search-trees/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/097-InterleavingString/official.md: -------------------------------------------------------------------------------- 1 | **97. 交错字符串** 2 | --- 3 | [https://leetcode-cn.com/problems/interleaving-string/](https://leetcode-cn.com/problems/interleaving-string/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/098-validateBinarySearchTree/BambooYH.md: -------------------------------------------------------------------------------- 1 | **98 判断叉查找树是否有效** 2 | --- 3 | [https://leetcode.com/problems/validate-binary-search-tree/](https://leetcode.com/problems/validate-binary-search-tree/) 4 | 5 | 解决方案: 6 | 方法一:**栈、中序遍历** 7 | **思路** 8 | 首先,我们要知道二叉搜索树的特点。 9 | - 若左子树不为空,则左子树节点值小于根节点的值 10 | - 若右字树不为空,则右字树节点值大于根节点的值 11 | - 任意节点的左右字树也为二叉搜索树 12 | - 没有键值相等的节点 13 | - [参考wiki](https://zh.wikipedia.org/zh-cn/%E4%BA%8C%E5%85%83%E6%90%9C%E5%B0%8B%E6%A8%B9) 14 | 15 | 所以了解了二叉搜索树的特点之后,我们可以知道,中序遍历二叉搜索树,得到的是一个递增的序列。所以此题只需进行中序遍历,判断是否是一个递增序列就可以了。 16 | **算法** 17 | 采用非递归的方式进行中序遍历,在遍历的过程中,判断是否是一个递增的序列,如果不是,则返回false 18 | **代码** 19 | ``` 20 | class Solution { 21 | public boolean isValidBST(TreeNode root) { 22 | if(root == null) 23 | return true; 24 | Stack stack = new Stack(); 25 | TreeNode pre = null; 26 | while(root != null || !stack.isEmpty()) { //当左子节点存在的时候,将左子节点加入栈中 27 | while(root != null) { 28 | stack.push(root); 29 | root = root.left; 30 | } 31 | //弹出栈顶节点 32 | root = stack.pop(); 33 | //如果当前节点小于等于前一个节点的值,则返回false 34 | if(pre != null && root.val <= pre.val) 35 | return false; 36 | //将pre指向当前节点 37 | pre = root; 38 | //继续遍历当前节点的右子节点 39 | root = root.right; 40 | } 41 | return true; 42 | } 43 | } 44 | ``` 45 | 复杂度分析 46 | 空间复杂度:O(h),h表示当前树的树高,最坏情况下为n,平均为logn 47 | 时间复杂度:O(n), 当前树的节点的总数 48 | -------------------------------------------------------------------------------- /solutions/leetcode/102-BinaryTreeLevelOrderTraversal/hatrick.md: -------------------------------------------------------------------------------- 1 | **二叉树的层序遍历** 2 | --- 3 | [https://leetcode.com/problems/binary-tree-level-order-traversal/](https://leetcode.com/problems/binary-tree-level-order-traversal/) 4 | 5 | 解决方案 6 | **思路** 7 | 使用广度优先探索,使用队列。 8 | 若根节点为空,直接返回; 9 | 否则将根节点入队,然后,判断队列是否为空,若不为空,则将队首节点出队,访问,并判断其左右子节点是否为空,若不为空,则压入队列。 10 | 11 | ``` 12 | class Solution{ 13 | List> res=new ArrayList(); 14 | public List> levelOrder(TreeNode root) { 15 | if(root==null) return res; //边界条件 16 | Queue q=new LinkedList(); //创建的队列用来存放结点,泛型注意是TreeNode 17 | q.add(root); 18 | while(!q.isEmpty()){ //队列为空说明已经遍历完所有元素,while语句用于循环每一个层次 19 | int count=q.size(); 20 | List list=new ArrayList(); 21 | while(count>0){ //遍历当前层次的每一个结点,每一层次的Count代表了当前层次的结点数目 22 | TreeNode temp=q.peek(); 23 | q.poll(); //遍历的每一个结点都需要将其弹出 24 | list.add(temp.val); 25 | if(temp.left!=null)q.add(temp.left); //迭代操作,向左探索 26 | if(temp.right!=null)q.add(temp.right); 27 | count--; 28 | } 29 | res.add(list); 30 | } 31 | return res; 32 | 33 | } 34 | } 35 | 36 | ``` 37 | **复杂度分析** 38 | 时间复杂度:O(NlogN) 39 | 空间复杂度:O(N+M) 40 | 41 | **参考资料** 42 | [https://www.cnblogs.com/patatoforsyj/p/9496127.html](https://www.cnblogs.com/patatoforsyj/p/9496127.html) 43 | -------------------------------------------------------------------------------- /solutions/leetcode/102-BinaryTreeLevelOrderTraversal/official.md: -------------------------------------------------------------------------------- 1 | **102. 二叉树的层次遍历** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/binary-tree-level-order-traversal/](https://leetcode-cn.com/problems/binary-tree-level-order-traversal/) 5 | -------------------------------------------------------------------------------- /solutions/leetcode/102-BinaryTreeLevelOrderTraversal/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | #### 二叉树的层次遍历 2 | 3 | https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ 4 | 5 | **思路**: 6 | 7 | 层次遍历需要借助队列这样一个辅助的数据结构. 8 | 9 | 1.题目给出从左到右访问节点,自然想到的就是BFS,广度优先搜索。每个节点访问且仅访问一次。所以时间复杂度是O(N),根节点先入队列,然后队列不空,取出头元素, 10 | 如果左孩子存在就入队列,否则什么都不做,右孩子同理。直到队列为空,则表示树层次遍历结束。 11 | 12 | 2.深度优先搜索DFS,也可以做。但是最好还是BFS 13 | 14 | 代码:(BFS) 15 | 16 | ``` 17 | class Solution: 18 | def levelOrder(self, root): 19 | """ 20 | :type root: TreeNode 21 | :rtype: List[List[int]] 22 | """ 23 | if not root: 24 | return [] #若根节点为空,则返回空列表 25 | result = [] #模拟一个队列存储节点 26 | queue = collections.deque() #双端队列 27 | queue.append(root) #首先将根节点入队 28 | 29 | while queue: 30 | level_size = len(queue) #记录同层节点的个数 31 | current_level = [] #使用列表来存储同层节点 32 | 33 | for _ in range(level_size): 34 | node = queue.popleft() #将同层节点依次出队 35 | current_level.append(node.val) 36 | if node.left: queue.append(node.left) #非空左孩子入队 37 | if node.right: queue.append(node.right) #非空右孩子入队 38 | result.append(current_level) 39 | return result 40 | ``` 41 | 42 | 时间复杂度是O(N) 43 | -------------------------------------------------------------------------------- /solutions/leetcode/104-MaximumDepthOfBinaryTree/official.md: -------------------------------------------------------------------------------- 1 | **104. 二叉树的最大深度** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/) 5 | -------------------------------------------------------------------------------- /solutions/leetcode/110-BalancedBinaryTree/README.md: -------------------------------------------------------------------------------- 1 | **110. 平衡二叉树** 2 | --- 3 | [https://leetcode-cn.com/problems/balanced-binary-tree/](https://leetcode-cn.com/problems/balanced-binary-tree/) 4 | 5 | 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 6 | 7 | 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 8 | 9 | 给定一个二叉树,判断它是否是高度平衡的二叉树。 10 | 11 | 本题中,一棵高度平衡二叉树定义为: 12 | 13 | >一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。 14 | 15 | **示例 1:** 16 | 17 | ``` 18 | 给定二叉树 [3,9,20,null,null,15,7] 19 | 20 | 3 21 | / \ 22 | 9 20 23 | / \ 24 | 15 7 25 | 返回 true 。 26 | ``` 27 | 28 | **示例 2:** 29 | 30 | ``` 31 | 给定二叉树 [1,2,2,3,3,null,null,4,4] 32 | 33 | 1 34 | / \ 35 | 2 2 36 | / \ 37 | 3 3 38 | / \ 39 | 4 4 40 | 返回 false 。 41 | ``` 42 | 43 | -------------------------------------------------------------------------------- /solutions/leetcode/110-BalancedBinaryTree/bigablecat.md: -------------------------------------------------------------------------------- 1 | **110. 平衡二叉树** 2 | --- 3 | [https://leetcode-cn.com/problems/balanced-binary-tree/](https://leetcode-cn.com/problems/balanced-binary-tree/) 4 | 5 | * 网友高票Java解法: 6 | 7 | ```java 8 | 9 | /** 10 | * 网友高票Java解法 11 | * 12 | * @param root 13 | * @return 14 | */ 15 | public boolean isBalanced(TreeNode root) { 16 | return height(root) != -1; 17 | } 18 | 19 | /** 20 | * 获取当前节点的树高 21 | * 如果是高度平衡的二叉树,返回树的真实高度 22 | * 如果不是高度平衡二叉树,返回-1 23 | * 24 | * @param node 25 | * @return 26 | */ 27 | public int height(TreeNode node) { 28 | //检查当前节点是否为空 29 | if (node == null) { 30 | //空节点返回0 31 | return 0; 32 | } 33 | //获取左子节点的树高 34 | int lH = height(node.left); 35 | //如果返回-1,说明左子节点不符合题意 36 | if (lH == -1) { 37 | return -1; 38 | } 39 | //同理判断右子节点 40 | int rH = height(node.right); 41 | if (rH == -1) { 42 | return -1; 43 | } 44 | //检查左右子节点高度差的绝对值是否不超过1 45 | if (lH - rH < -1 || lH - rH > 1) { 46 | //绝对值超过1,不符合题意,返回-1 47 | return -1; 48 | } 49 | //Math.max(lH,rH)返回左右子节点中高度较大的一个 50 | //在子节点中较大的高度上+1,即当前节点自身的高度1 51 | //返回的最终结果就是当前节点的树高 52 | return Math.max(lH, rH) + 1; 53 | } 54 | 55 | ``` 56 | 57 | **参考资料** 58 | 59 | * 网友高票答案: 60 | [https://leetcode.com/problems/balanced-binary-tree/discuss/35686/Java-solution-based-on-height-check-left-and-right-node-in-every-recursion-to-avoid-further-useless-search](https://leetcode.com/problems/balanced-binary-tree/discuss/35686/Java-solution-based-on-height-check-left-and-right-node-in-every-recursion-to-avoid-further-useless-search) 61 | 62 | -------------------------------------------------------------------------------- /solutions/leetcode/110-BalancedBinaryTree/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 110.给定一个二叉树,判断它是否是高度平衡的二叉树。 2 | 3 | 本题中,一棵高度平衡二叉树定义为: 4 | 5 | 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。 6 | 7 | 示例 1: 8 | 9 | 给定二叉树 [3,9,20,null,null,15,7] 10 | 11 | 3 12 | / \ 13 | 9 20 14 | / \ 15 | 15 7 16 | 返回 true 。 17 | 18 | 示例 2: 19 | 20 | 给定二叉树 [1,2,2,3,3,null,null,4,4] 21 | 22 | 1 23 | / \ 24 | 2 2 25 | / \ 26 | 3 3 27 | / \ 28 | 4 4 29 | 返回 false 。 30 | 31 | 思路:递归,判断左右子树最大高度差不超过1且左右子树均为平衡树 32 | 33 | ```py 34 | class Solution(object): 35 | def isBalanced(self, root): 36 | """ 37 | :type root: TreeNode 38 | :rtype: bool 39 | """ 40 | def getDepth(root): 41 | if not root: 42 | return 0 43 | return 1 + max(getDepth(root.left), getDepth(root.right)) #左右子树最大的深度,记住加一 44 | 45 | if not root: 46 | return True 47 | if abs(getDepth(root.left) - getDepth(root.right))>1: #判断左右子树的最大深度差是否超过1 48 | return False 49 | return self.isBalanced(root.left) and self.isBalanced(root.right) 50 | ``` 51 | 时间复杂度:O(n) 52 | -------------------------------------------------------------------------------- /solutions/leetcode/115-DistinctSubsequences/official.md: -------------------------------------------------------------------------------- 1 | **115. 不同的子序列** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/distinct-subsequences/](https://leetcode-cn.com/problems/distinct-subsequences/) 5 | -------------------------------------------------------------------------------- /solutions/leetcode/120-Triangle/official.md: -------------------------------------------------------------------------------- 1 | **120. 三角形最小路径和** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/triangle/](https://leetcode-cn.com/problems/triangle/) 5 | -------------------------------------------------------------------------------- /solutions/leetcode/121-bestTimeToBuyAndSellStock/official.md: -------------------------------------------------------------------------------- 1 | **121. 买卖股票的最佳时机** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/) 5 | -------------------------------------------------------------------------------- /solutions/leetcode/122-bestTimeToBuyAndSellStockII/SpecialYang.md: -------------------------------------------------------------------------------- 1 | **最佳时机买卖股票2** 2 | ---- 3 | https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ 4 | 5 | ### 思路一 6 | 题目的意思是不限买卖股票的次数,并且每次买股票的时候必须在上一股卖出之后,在此基础上求出最大利润。 7 | 我们只需求出所有的有序段的差值之和即可。遍历数组,找到第一个高峰,然后计算高峰与低谷的差值,更新新的低谷,然后再继续寻找下一个高峰,累加差值即可。 8 | **你必然有这样的疑问,我找到高峰之后,可能后面还有更高的峰,我为什么非的此时再卖而不是在更高的峰卖呢?这样真的能达到最大值吗**? 9 | 10 | 你这样想,你当前的高峰后面是另一个低谷,这个差值就是你分开买比一次性买到最高峰的多出来的部分啊,也就是重叠部分。如果你直接从低谷买到最高峰,那么这个差值你是赚不到。而你每一个低谷到第一个高峰都买卖啊,这个额外的差值你都赚到了。 11 | 12 | ![image](https://leetcode.com/media/original_images/122_maxprofit_1.PNG) 13 | A + B > C,对吧 14 | ```java 15 | public int maxProfit1(int[] prices) { 16 | int result = 0; 17 | int low = 0; 18 | int len = prices.length; 19 | for (int i = 0; i < len; i++) { 20 | //寻找当前碰到第一个高峰 21 | if (i + 1 == len || prices[i] >= prices[i + 1]) { 22 | result += prices[i] - prices[low]; 23 | //更新低谷 24 | low = i + 1; 25 | } 26 | } 27 | return result; 28 | } 29 | ``` 30 | 31 | ### 思路二 32 | 还是看上图,既然我们求的是所有的有序段的差值和,那么我们也可以不必每次都求出这个段区间后再求和。而是从小事做起,只要第二天比第一天高,我们就买卖。意味着我们不用考虑具体的有序段是什么,只需关注当前是有序,我们就累加利润即可。类似爬坡的过程,通过累加求出上图的中A的利润。 33 | 34 | ```java 35 | /** 36 | * 一阶段 37 | * 累加所有的增值即可 38 | * @param prices 39 | * @return 40 | */ 41 | public int maxProfit2(int[] prices) { 42 | int result = 0; 43 | for (int i = 1; i < prices.length; i++) { 44 | if (prices[i] > prices[i - 1]) { 45 | result += prices[i] - prices[i - 1]; 46 | } 47 | } 48 | return result; 49 | } 50 | ``` 51 | 参考: 52 | - https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/solution/ -------------------------------------------------------------------------------- /solutions/leetcode/123-BestTimeToBuyAndSellStockIII/official.md: -------------------------------------------------------------------------------- 1 | **123. 买卖股票的最佳时机 III** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/) 5 | -------------------------------------------------------------------------------- /solutions/leetcode/131-PalindromePartitioning/official.md: -------------------------------------------------------------------------------- 1 | **131. 分割回文串** 2 | --- 3 | [https://leetcode-cn.com/problems/palindrome-partitioning/](https://leetcode-cn.com/problems/palindrome-partitioning/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/132-PalindromePartitioningII/official.md: -------------------------------------------------------------------------------- 1 | **132. 分割回文串 II** 2 | --- 3 | [https://leetcode-cn.com/problems/palindrome-partitioning-ii/](https://leetcode-cn.com/problems/palindrome-partitioning-ii/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/139-WordBreak/official.md: -------------------------------------------------------------------------------- 1 | **139. 单词拆分** 2 | --- 3 | [https://leetcode-cn.com/problems/word-break/](https://leetcode-cn.com/problems/word-break/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/140-WordBreakII/official.md: -------------------------------------------------------------------------------- 1 | **140. 单词拆分 II** 2 | --- 3 | [https://leetcode-cn.com/problems/word-break-ii/](https://leetcode-cn.com/problems/word-break-ii/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/141-linkedListCycle/official.md: -------------------------------------------------------------------------------- 1 | **141. 环形链表** 2 | --- 3 | [https://leetcode-cn.com/problems/linked-list-cycle/](https://leetcode-cn.com/problems/linked-list-cycle/) 4 | 5 | 方法一:哈希表 6 | 思路 7 | 8 | 我们可以通过检查一个结点此前是否被访问过来判断链表是否为环形链表。 9 | 10 | 常用的方法是使用哈希表。 11 | 12 | 算法 13 | 14 | 我们遍历所有结点并在哈希表中存储每个结点的引用(或内存地址)。 15 | 16 | 如果当前结点为空结点 null(即已检测到链表尾部的下一个结点), 17 | 18 | 那么我们已经遍历完整个链表,并且该链表不是环形链表。 19 | 20 | 如果当前结点的引用已经存在于哈希表中,那么返回 true(即该链表为环形链表)。 21 | 22 | ```java 23 | 24 | public boolean hasCycle(ListNode head) { 25 | //新建一个set用于存储从链表中遍历出的结点 26 | Set nodesSeen = new HashSet<>(); 27 | //如果当前结点不为空,循环继续 28 | while (head != null) { 29 | //set中如果已经存在当前结点,说明该链表是环形链表,返回true 30 | if (nodesSeen.contains(head)) { 31 | return true; 32 | } else { 33 | //否则将当前结点添加到set 34 | nodesSeen.add(head); 35 | } 36 | //将下一个结点赋值给结点缓存head 37 | head = head.next; 38 | } 39 | //链表所有结点遍历结束没有在set里找到重复结点,说明当前链表没有环,返回false 40 | return false; 41 | } 42 | 43 | ``` 44 | 45 | **复杂度分析** 46 | 47 | 时间复杂度: 48 | O(n), 对于含有 n个元素的链表,我们访问每个元素最多一次。 添加一个结点到哈希表中只需要花费 O(1) 的时间。 49 | 50 | 空间复杂度: 51 | O(n), 空间取决于添加到哈希表中的元素数目,最多可以添加 n 个元素。 52 | 53 | --- 54 | 55 | 56 | **参考资料** 57 | 58 | * 本题leetCode官方题解: 59 | [https://leetcode-cn.com/articles/linked-list-cycle/](https://leetcode-cn.com/articles/linked-list-cycle/) 60 | 61 | * 本题leetCode英文官方题解: 62 | [https://leetcode.com/articles/linked-list-cycle/](https://leetcode.com/articles/linked-list-cycle/) -------------------------------------------------------------------------------- /solutions/leetcode/142-linkedListCycleII/official.md: -------------------------------------------------------------------------------- 1 | **142. 环形链表 II** 2 | --- 3 | [https://leetcode-cn.com/problems/linked-list-cycle-ii/](https://leetcode-cn.com/problems/linked-list-cycle-ii/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/144-BinaryTreePreorderTraversal/README.md: -------------------------------------------------------------------------------- 1 | **144. 二叉树的前序遍历** 2 | --- 3 | [https://leetcode-cn.com/problems/binary-tree-preorder-traversal/](https://leetcode-cn.com/problems/binary-tree-preorder-traversal/) 4 | 5 | 给定一个二叉树,返回它的 前序 遍历。 6 | 7 | **示例:** 8 | 9 | ``` 10 | 输入: [1,null,2,3] 11 | 1 12 | \ 13 | 2 14 | / 15 | 3 16 | 17 | 输出: [1,2,3] 18 | ``` 19 | -------------------------------------------------------------------------------- /solutions/leetcode/144-BinaryTreePreorderTraversal/bigablecat.md: -------------------------------------------------------------------------------- 1 | **144. 二叉树的前序遍历** 2 | --- 3 | [https://leetcode-cn.com/problems/binary-tree-preorder-traversal/](https://leetcode-cn.com/problems/binary-tree-preorder-traversal/) 4 | 5 | * 网友高票Java解法: 6 | 7 | ```java 8 | 9 | /** 10 | * 前序遍历(DLR),是二叉树遍历的一种,首先访问根结点然后遍历左子树,最后遍历右子树 11 | * 12 | * 网友高票Java解法 13 | * 14 | * @param node 15 | * @return 16 | */ 17 | public List preorderTraversal(TreeNode node) { 18 | //创建一个链表 19 | List list = new LinkedList(); 20 | //创建一个栈对象,用于存储右节点 21 | Stack rights = new Stack(); 22 | //当前节点非空时进行遍历 23 | while(node != null) { 24 | //将当前节点的值存入链表 25 | list.add(node.val); 26 | //如果当前节点存在右子节点 27 | if (node.right != null) { 28 | //将右子节点存入栈 29 | rights.push(node.right); 30 | } 31 | //获取当前节点的左子节点并赋值给node 32 | node = node.left; 33 | //node == null表示刚才获取的左子节点为空 34 | //rights.isEmpty()表示存放右子节点的栈非空 35 | if (node == null && !rights.isEmpty()) { 36 | //弹出栈最顶端的元素并赋值给node 37 | node = rights.pop(); 38 | } 39 | //最终赋值的node将在下一次循环把val存入链表list 40 | } 41 | //返回最终结果 42 | return list; 43 | } 44 | 45 | ``` 46 | 47 | --- 48 | 49 | **参考资料** 50 | 51 | * 网友高票Java解法: 52 | [https://leetcode.com/problems/binary-tree-preorder-traversal/discuss/45266/Accepted-iterative-solution-in-Java-using-stack.](https://leetcode.com/problems/binary-tree-preorder-traversal/discuss/45266/Accepted-iterative-solution-in-Java-using-stack.) 53 | -------------------------------------------------------------------------------- /solutions/leetcode/146-lruCache/official.md: -------------------------------------------------------------------------------- 1 | **146. LRU缓存机制** 2 | --- 3 | [https://leetcode-cn.com/problems/lru-cache/](https://leetcode-cn.com/problems/lru-cache/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/152-MaximumProductSubarray/README.md: -------------------------------------------------------------------------------- 1 | **152. 乘积最大子序列** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/maximum-product-subarray/](https://leetcode-cn.com/problems/maximum-product-subarray/) 5 | 6 | 给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。 7 | 8 | **示例 1:** 9 | 10 | ``` 11 | 输入: [2,3,-2,4] 12 | 输出: 6 13 | 解释: 子数组 [2,3] 有最大乘积 6。 14 | ``` 15 | 16 | **示例 2:** 17 | 18 | ``` 19 | 输入: [-2,0,-1] 20 | 输出: 0 21 | 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。 22 | ``` 23 | -------------------------------------------------------------------------------- /solutions/leetcode/152-MaximumProductSubarray/SpecialYang.md: -------------------------------------------------------------------------------- 1 | **乘积最大子序列** 2 | --- 3 | https://leetcode.com/problems/maximum-product-subarray/ 4 | 5 | 典型的动态规划问题,说实话,第一次做没做出来,菜是原罪,主要卡在了判断当前最大值上面,因为乘积的特性,使得当前的不是最大值可能由于后面的负负得正从而晋升为最大值。 6 | 7 | 卡在上面的原因,思维一直停留在和最大子序列那道题。在那道题里,我们判断当前最大值为之前的连续最大和加上当前的数字,或者只有当前的数字,即`dp[i] = max(dp[i - 1] + num[i], num[i])`。若加上当前的值的连续和还没有只有当前值大,说明之前的连续和没有贡献,所以新的子序列要从当前值开始。 8 | 9 | 在乘积里就不能这么做了,因为即使乘以当前值的累积没有只有当前值大,这种情路发生在dp[i - 1]为负数,num[i]为正数时。如果仅仅按照最大连续和的做法,就会开启新的序列,前面的dp[i - 1]就会丢弃。这时如果num[i + 1]为负数,那么`dp[i - 1] * num[i] * num[i + 1]` 显然比`num[i] * num[i + 1]`大,所以我们就会丢失这个最大值。 10 | 11 | 牛逼的思路就是我们不仅仅要记录以当前位置结尾累积的最大值,还要记录对应的最小值,并且在访问到负数时,之前的最大值与最小值要交换一下,以便之后的正确更新。 12 | 13 | 记录的最大最小值,我们就可以应对各种情况了,最大值可以在遇到正数时依旧最大,遇到负数可变为最小;最小值在遇到负数翻身别为最大,遇到正数可变为最小。 14 | 15 | ```java 16 | /** 17 | * 维护已i结尾的乘积最大值,最小值 18 | * 19 | * 遇到负数,交换最大最小值,因为乘以负数时,最小值会变为最大值 20 | * @param nums 21 | * @return 22 | */ 23 | public int maxProduct2(int[] nums) { 24 | int result = nums[0]; 25 | for (int i = 1, min = result, max = result; i < nums.length; i++) { 26 | //遇到负数,交换以i - 1结尾的最大值,最小值 27 | if (nums[i] < 0) { 28 | int temp = min; 29 | min = max; 30 | max = temp; 31 | } 32 | max = Math.max(nums[i], max * nums[i]); 33 | min = Math.min(nums[i], min * nums[i]); 34 | result = Math.max(result, max); 35 | } 36 | return result; 37 | } 38 | ``` 39 | 复杂度: 40 | - 时间复杂度:遍历一遍,O(n) 41 | - 空间复杂度:3个变量,O(1) 42 | 43 | 参考:https://leetcode.com/problems/maximum-product-subarray/discuss/48230/Possibly-simplest-solution-with-O(n)-time-complexity -------------------------------------------------------------------------------- /solutions/leetcode/152-MaximumProductSubarray/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 152.给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。 2 | 3 | 示例 1: 4 | 5 | 输入: [2,3,-2,4] 6 | 输出: 6 7 | 解释: 子数组 [2,3] 有最大乘积 6。 8 | 示例 2: 9 | 10 | 输入: [-2,0,-1] 11 | 输出: 0 12 | 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。 13 | 14 | 思路:乘积最大子序列,和53是不一样的,因为乘积可正可负,之前的DP方程不能保证结果。而且要用两个dp数组,其中maxdp[i]表示子数组[0, i]范围内并且一定包 15 | 含nums[i]数字的最大子数组乘积,mindp[i]表示子数组[0, i]范围内并且一定包含nums[i]数字的最小子数组乘积,初始化时maxdp[0]和mindp[0]都初始化为 16 | nums[0],其余都初始化为0。那么从数组的第二个数字开始遍历,那么此时的最大值和最小值只会在这三个数字之间产生,即maxdp[i-1]*nums[i],mindp[i- 17 | 1]*nums[i],和nums[i]。所以我们用三者中的最大值来更新maxdp[i],用最小值来更新mindp[i],然后用maxdp[i]来更新结果res即可,由于最终的结果不一定会包 18 | 括nums[n-1]这个数字,所以maxdp[n-1]不一定是最终解,不断更新的结果res才是,参见代码如下: 19 | 20 | ```py 21 | def solution(nums): 22 | maxdp = [nums[0]]*len(nums) 23 | mindp = [nums[0]]*len(nums) 24 | 25 | for i in range(1,len(nums)): 26 | maxdp[i] = max(mindp[i-1]*nums[i],maxdp[i-1]*nums[i],nums[i]) 27 | mindp[i] = min(maxdp[i-1]*nums[i],mindp[i-1]*nums[i],nums[i]) 28 | return max(maxdp) 29 | ``` 30 | 时间复杂度O(n) 31 | 空间复杂度O(n) 32 | -------------------------------------------------------------------------------- /solutions/leetcode/153-FindMinimumInRotatedSortedArray/README.md: -------------------------------------------------------------------------------- 1 | **153. 寻找旋转排序数组中的最小值** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/](https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/) 5 | 6 | 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 7 | 8 | ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 9 | 10 | 请找出其中最小的元素。 11 | 12 | 你可以假设数组中不存在重复元素。 13 | 14 | **示例 1:** 15 | 16 | ``` 17 | 输入: [3,4,5,1,2] 18 | 输出: 1 19 | ``` 20 | 21 | **示例 2:** 22 | 23 | ``` 24 | 输入: [4,5,6,7,0,1,2] 25 | 输出: 0 26 | ``` 27 | -------------------------------------------------------------------------------- /solutions/leetcode/153-FindMinimumInRotatedSortedArray/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 153.假设按照升序排序的数组在预先未知的某个点上进行了旋转。 2 | 3 | ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 4 | 5 | 请找出其中最小的元素。 6 | 7 | 你可以假设数组中不存在重复元素。 8 | 9 | 示例 1: 10 | 11 | 输入: [3,4,5,1,2] 12 | 输出: 1 13 | 示例 2: 14 | 15 | 输入: [4,5,6,7,0,1,2] 16 | 输出: 0 17 | 18 | 思路:首先要判断这个有序数组是否旋转了,通过比较第一个和最后一个数的大小,如果第一个数小,则没有旋转,直接返回这个数。如果第一个数大,就要进一步搜索。 19 | 我们定义left和right两个指针分别指向开头和结尾,还要找到中间那个数,然后和left指的数比较,如果中间的数大,则继续二分查找右半段数组,反之查找左半段。 20 | 终止条件是当左右两个指针相邻,返回小的那个。 21 | 22 | ```py 23 | def solution(nums): 24 | l, r = 0, len(nums) - 1 25 | while l <= r: 26 | mid = l + ((r - l) >> 1) 27 | if nums[mid] < nums[mid - 1]: 28 | return nums[mid] 29 | elif nums[mid] < nums[l]: 30 | r = mid - 1 31 | elif nums[mid] > nums[r]: 32 | l = mid + 1 33 | else: 34 | return nums[i] 35 | ``` 36 | 时间复杂度O(lgN) 37 | 空间复杂度O(1) 38 | -------------------------------------------------------------------------------- /solutions/leetcode/160-IntersectionOfTwoLinkedLists/README.md: -------------------------------------------------------------------------------- 1 | **160. 相交链表** 2 | --- 3 | [https://leetcode-cn.com/problems/intersection-of-two-linked-lists/](https://leetcode-cn.com/problems/intersection-of-two-linked-lists/) 4 | 5 | 编写一个程序,找到两个单链表相交的起始节点。 6 | 7 | 如下面的两个链表: 8 | ![160_statement](https://raw.githubusercontent.com/hollischuang/algorithm/master/images/160_statement.png) 9 | 10 | 11 | 在节点 c1 开始相交。 12 | 13 | **示例 1:** 14 | ![160_example_1](https://raw.githubusercontent.com/hollischuang/algorithm/master/images/160_example_1.png) 15 | 16 | 17 | 输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3 18 | 输出:Reference of the node with value = 8 19 | 输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。 20 | 21 | 22 | **示例 2:** 23 | ![160_example_2](https://raw.githubusercontent.com/hollischuang/algorithm/master/images/160_example_2.png) 24 | 25 | ``` 26 | 输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 27 | 输出:Reference of the node with value = 2 28 | 输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。 29 | ``` 30 | 31 | **示例 3:** 32 | ![160_example_3](https://raw.githubusercontent.com/hollischuang/algorithm/master/images/160_example_3.png) 33 | 34 | ``` 35 | 输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2 36 | 输出:null 37 | 输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。 38 | 解释:这两个链表不相交,因此返回 null。 39 | ``` 40 | 41 | **注意:** 42 | 43 | * 如果两个链表没有交点,返回 null. 44 | * 在返回结果后,两个链表仍须保持原有的结构。 45 | * 可假定整个链表结构中没有循环。 46 | * 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。 47 | -------------------------------------------------------------------------------- /solutions/leetcode/167-TwoSumII/README.md: -------------------------------------------------------------------------------- 1 | **167. 两数之和 II - 输入有序数组** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/](https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/) 5 | 6 | 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。 7 | 8 | 函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。 9 | 10 | **说明:** 11 | 12 | * 返回的下标值(index1 和 index2)不是从零开始的。 13 | * 你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。 14 | 15 | **示例:** 16 | 17 | ``` 18 | 输入: numbers = [2, 7, 11, 15], target = 9 19 | 输出: [1,2] 20 | 解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。 21 | ``` 22 | -------------------------------------------------------------------------------- /solutions/leetcode/169-majorityElement/README.md: -------------------------------------------------------------------------------- 1 | **169. 求众数** 2 | --- 3 | [https://leetcode-cn.com/problems/majority-element/](https://leetcode-cn.com/problems/majority-element/) 4 | 5 | 给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 6 | 7 | 你可以假设数组是非空的,并且给定的数组总是存在众数。 8 | 9 | 示例 1: 10 | 11 | ``` 12 | 输入: [3,2,3] 13 | 输出: 3 14 | ``` 15 | 16 | 示例 2: 17 | 18 | ``` 19 | 输入: [2,2,1,1,1,2,2] 20 | 输出: 2 21 | ``` 22 | -------------------------------------------------------------------------------- /solutions/leetcode/169-majorityElement/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 2 | 3 | 你可以假设数组是非空的,并且给定的数组总是存在众数。 4 | 5 | 示例 1: 6 | 7 | 输入: [3,2,3] 8 | 输出: 3 9 | 示例 2: 10 | 11 | 输入: [2,2,1,1,1,2,2] 12 | 输出: 2 13 | 14 | 思路: 15 | 16 | 1.最容易想到的就是众数的定义,先排序,然后取出中间的数,那个数一定是众数。 17 | 18 | ```py 19 | class Solution(object): 20 | def majorityElement(self, nums): 21 | """ 22 | :type nums: List[int] 23 | :rtype: int 24 | """ 25 | nums.sort() 26 | return nums[len(nums)//2] 27 | ``` 28 | 时间复杂度:O(nlogn) 29 | 空间复杂度:O(1) 30 | 31 | 2.摩尔投票法 32 | 33 | 我们先将数组中的第一个数假设为众数,然后进行统计其出现的次数,如果遇到同样的数,则计数器自动加一,否则计数器减一,如果计数器减到了0,则更换下一个数字为 34 | 候选者。一定会有超过半数的数字存在,如果计数器减到0之后,说明目前不是候选数字的个数已经跟候选者的出现个数相同了,那么这个候选者已经很weak,不一定能出现 35 | 超过半数,但是如果后面又大量出现之前的候选者的话,又会被重新变为候选者,直到最终验证为正确的众数。 36 | 37 | ```py 38 | class Solution(object): 39 | def majorityElement(self, nums): 40 | """ 41 | :type nums: List[int] 42 | :rtype: int 43 | """ 44 | res = cnt = 0 45 | for num in nums: 46 | if cnt == 0: 47 | res = num 48 | cnt += 1 49 | elif res == num: 50 | cnt += 1 51 | else: 52 | cnt -= 1 53 | return res 54 | ``` 55 | 时间复杂度:O(n) 56 | 空间复杂度:O(1) 57 | 58 | 59 | -------------------------------------------------------------------------------- /solutions/leetcode/188-bestTimeToBuyAndSellStockIV/official.md: -------------------------------------------------------------------------------- 1 | **188. 买卖股票的最佳时机 IV** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/) 5 | -------------------------------------------------------------------------------- /solutions/leetcode/191-NumberOf1Bits/README.md: -------------------------------------------------------------------------------- 1 | **191. 位1的个数** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/number-of-1-bits/](https://leetcode-cn.com/problems/number-of-1-bits/) 5 | 6 | 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 7 | 8 | 9 | **示例 1:** 10 | 11 | ``` 12 | 输入:00000000000000000000000000001011 13 | 输出:3 14 | 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 15 | ``` 16 | 17 | **示例 2:** 18 | ``` 19 | 输入:00000000000000000000000010000000 20 | 输出:1 21 | 解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。 22 | ``` 23 | 24 | **示例 3:** 25 | 26 | ``` 27 | 输入:11111111111111111111111111111101 28 | 输出:31 29 | 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。 30 | ``` 31 | 32 | **提示:** 33 | 34 | * 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。 35 | * 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。 36 | 37 | **进阶:** 38 | 如果多次调用这个函数,你将如何优化你的算法? 39 | 40 | -------------------------------------------------------------------------------- /solutions/leetcode/198-houseRobber/README.md: -------------------------------------------------------------------------------- 1 | **198. 打家劫舍** 2 | --- 3 | [https://leetcode-cn.com/problems/house-robber/](https://leetcode-cn.com/problems/house-robber/) 4 | 5 | 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 6 | 7 | 给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。 8 | 9 | **示例 1:** 10 | 11 | ``` 12 | 输入: [1,2,3,1] 13 | 输出: 4 14 | 解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 15 | 偷窃到的最高金额 = 1 + 3 = 4 。 16 | ``` 17 | 18 | **示例 2:** 19 | 20 | ``` 21 | 输入: [2,7,9,3,1] 22 | 输出: 12 23 | 解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。 24 | 偷窃到的最高金额 = 2 + 9 + 1 = 12 。 25 | ``` 26 | -------------------------------------------------------------------------------- /solutions/leetcode/198-houseRobber/hatrick.md: -------------------------------------------------------------------------------- 1 | **198. 打家劫舍** 2 | --- 3 | [https://leetcode-cn.com/problems/house-robber/](https://leetcode-cn.com/problems/house-robber/) 4 | 5 | **思路** 6 | 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统, 7 | 如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下, 8 | 能够偷窃到的最高金额。 9 | 10 | 1、首先想一想如果是暴力如何做? 11 | 12 | 假设从最后一家店铺开始抢,那么只会遇到2种情况,即:抢这家店和下下家店,或者不抢这家店。 13 | 所以我们得到递归的公式: 14 | Math.max(solve(nums,index-1),solve(nums,index-2)+nums[index]); 15 | 16 | 2、上面的暴力算法虽然能够得到正确的结果,但是显然递归的效率是很低的,如果有n家店铺,每家店铺有2种可能,那么时间复杂度就是2的n次方。那么如何优化呢? 17 | 18 | 我们分析一下: 19 | 如果我们开始抢的是第n-1家店,那么后面可以是(n-3,n-4,n-5,n-6....); 20 | 如果我们开始抢的是第n-2家店,那么后面可以是(n-4,n-5,n-6,....); 21 | 那么这两种情况显然n-3之后的n-4,n-5,n-6,....都重复计算了。显然这里有非常大的优化空间。通常我们使用空间来换时间,即用一个数组记录每次计算的结果, 22 | 这样每次情况只需要计算一次,再次遇到只需直接返回结果即可,大大优化了时间 23 | 24 | 25 | ```java 26 | class Solution { 27 | public static int[] result; 28 | public int solve(int[] nums,int index){ 29 | if(index < 0){ 30 | return 0; 31 | } 32 | if(result[index] >= 0){ 33 | return result[index]; 34 | } 35 | result[index]=Math.max(solve(nums,index-1),solve(nums,index-2)+nums[index]); 36 | return result[index]; 37 | } 38 | public int rob(int[] nums) { 39 | result = new int[nums.length]; 40 | for(int i=0;i s1 = new Stack<>(); 16 | //辅助栈 17 | private Stack s2 = new Stack<>(); 18 | 19 | public MyQueue() { 20 | } 21 | 22 | public void push(int x) { 23 | //如果是第一次入栈 主栈和辅助栈都为空 24 | if (s1.empty()) { 25 | //第一次进来将flag置为进栈的值 26 | flag = x; 27 | } 28 | //如果第二次进来话,需要将前面进栈的值弹出,并放到辅助栈里面 29 | while (!s1.empty()) { 30 | s2.push(s1.pop()); 31 | } 32 | //保证当前栈中push值得时候是干净的栈,模拟队列 33 | s1.push(x); 34 | //将辅助栈中的值弹出,放到主栈中,保证了主栈中先进先出的特性 35 | while (!s2.empty()) { 36 | s1.push(s2.pop()); 37 | } 38 | } 39 | 40 | public int pop() { 41 | //直接弹栈 出来的就是最先进去的哪一个 42 | int num = s1.pop(); 43 | if (!s1.empty()) { 44 | //然后将当前的s1栈顶的元素赋值给标志位 45 | flag = s1.peek(); 46 | } 47 | return num; 48 | } 49 | 50 | public int peek() { 51 | //取标志位 52 | return flag; 53 | } 54 | 55 | public boolean empty() { 56 | return s1.empty(); 57 | } 58 | } 59 | 60 | ``` 61 | **复杂度分析** 62 | 时间复杂度:O(N^2) 63 | 空间复杂度:O(N^2) 64 | 65 | **参考资料** 66 | [https://blog.csdn.net/LaputaFallen/article/details/79998961?utm_source=blogxgwz5](https://blog.csdn.net/LaputaFallen/article/details/79998961?utm_source=blogxgwz5) -------------------------------------------------------------------------------- /solutions/leetcode/225-implementStackUsingQueues/official.md: -------------------------------------------------------------------------------- 1 | **225. 用队列实现栈** 2 | --- 3 | [https://leetcode-cn.com/problems/implement-stack-using-queues/](https://leetcode-cn.com/problems/implement-stack-using-queues/) 4 | 5 | -------------------------------------------------------------------------------- /solutions/leetcode/230-KthSmallestElementInABST/README.md: -------------------------------------------------------------------------------- 1 | **230. 二叉搜索树中第K小的元素** 2 | --- 3 | [https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/](https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/) 4 | 5 | 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。 6 | 7 | **说明:** 8 | 你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。 9 | 10 | **示例 1:** 11 | 12 | ``` 13 | 输入: root = [3,1,4,null,2], k = 1 14 | 3 15 | / \ 16 | 1 4 17 | \ 18 | 2 19 | 输出: 1 20 | ``` 21 | 22 | **示例 2:** 23 | 24 | ``` 25 | 输入: root = [5,3,6,2,4,null,null,1], k = 3 26 | 5 27 | / \ 28 | 3 6 29 | / \ 30 | 2 4 31 | / 32 | 1 33 | 输出: 3 34 | ``` 35 | 36 | **进阶:** 37 | 如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化 kthSmallest 函数? 38 | -------------------------------------------------------------------------------- /solutions/leetcode/230-KthSmallestElementInABST/bigablecat.md: -------------------------------------------------------------------------------- 1 | **230. 二叉搜索树中第K小的元素** 2 | --- 3 | [https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/](https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/) 4 | 5 | * 网友高票Java解法: 6 | 7 | ```java 8 | 9 | /** 10 | * 11 | * 网友高票Java解法1:递归查找二叉搜索树 12 | * 13 | */ 14 | public int kthSmallest(TreeNode root, int k) { 15 | //计算左子树的节点总数 16 | int count = countNodes(root.left); 17 | //如果k小于或等于左子树的节点总数 18 | if (k <= count) { 19 | //直接计算并放回左子树中的第k个最小值 20 | //因为二叉搜索树的左子节点值小于根结点值 21 | return kthSmallest(root.left, k); 22 | } else if (k > count + 1) { 23 | //如果k大于左子树节点总数 24 | //返回右子树的第k - 1 - count个最小值 25 | //k -1 减去了当前节点 26 | return kthSmallest(root.right, k - 1 - count); 27 | } 28 | //返回当前节点的值 29 | return root.val; 30 | } 31 | 32 | /** 33 | * 计算当前树的节点总数 34 | * 35 | * @param n 36 | * @return 37 | */ 38 | public int countNodes(TreeNode n) { 39 | //如果树根结点为空,返回0 40 | if (n == null) return 0; 41 | //否则分别计算左子树和右子树的节点总数 42 | // 1+表示将当前节点计入总数 43 | return 1 + countNodes(n.left) + countNodes(n.right); 44 | } 45 | 46 | 47 | ``` 48 | 49 | --- 50 | 51 | **参考资料** 52 | 53 | * 网友高票Java解法: 54 | [https://leetcode.com/problems/kth-smallest-element-in-a-bst/discuss/63660/3-ways-implemented-in-JAVA-(Python)%3A-Binary-Search-in-order-iterative-and-recursive](https://leetcode.com/problems/kth-smallest-element-in-a-bst/discuss/63660/3-ways-implemented-in-JAVA-(Python)%3A-Binary-Search-in-order-iterative-and-recursive) 55 | -------------------------------------------------------------------------------- /solutions/leetcode/231-PowerOfTwo/hatrick.md: -------------------------------------------------------------------------------- 1 | **231. 2的幂** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/power-of-two/](https://leetcode-cn.com/problems/power-of-two/) 5 | 思路: 6 | 解法一: 7 | 直接判断当前这个数字是否等于1,如果等于1则当前是2的0次幂,其次判断当前的数字取模 8 | 能否除尽,如果不能直接返回,如果能就继续计算 9 | ```java 10 | private boolean is2reverse(int n) { 11 | if (n == 1) { 12 | return true; 13 | } 14 | if (n >= 2 && n % 2 == 0) { 15 | return is2reverse(n / 2); 16 | } 17 | return false; 18 | } 19 | 20 | ``` 21 | **复杂度分析** 22 | 时间复杂度:O(N) 23 | 空间复杂度:O(1) 24 | --- 25 | 解法二: 26 | 2的次幂,意味着n&(n-1)的值为0,如果不是2的次幂那么返回值不是0了 27 | ```java 28 | private boolean is2reverse(int n) { 29 | if (n < 0) { 30 | return false; 31 | } 32 | int x = n & (n - 1); 33 | return x == 0; 34 | } 35 | ``` 36 | 37 | **复杂度分析** 38 | 时间复杂度:O(1) 39 | 空间复杂度:O(1) 40 | --- 41 | **参考资料** 42 | 43 | * 网友高票Java解法: 44 | [https://blog.csdn.net/chenchaofuck1/article/details/51226899](https://blog.csdn.net/chenchaofuck1/article/details/51226899) 45 | -------------------------------------------------------------------------------- /solutions/leetcode/231-PowerOfTwo/official.md: -------------------------------------------------------------------------------- 1 | **231. 2的幂** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/power-of-two/](https://leetcode-cn.com/problems/power-of-two/) 5 | -------------------------------------------------------------------------------- /solutions/leetcode/232-implementQueueUsingStacks/README.md: -------------------------------------------------------------------------------- 1 | **232. 用栈实现队列** 2 | --- 3 | [https://leetcode-cn.com/problems/implement-queue-using-stacks/](https://leetcode-cn.com/problems/implement-queue-using-stacks/) 4 | 5 | 使用栈实现队列的下列操作: 6 | 7 | * push(x) -- 将一个元素放入队列的尾部。 8 | * pop() -- 从队列首部移除元素。 9 | * peek() -- 返回队列首部的元素。 10 | * empty() -- 返回队列是否为空。 11 | 12 | 示例: 13 | 14 | ``` 15 | MyQueue queue = new MyQueue(); 16 | 17 | queue.push(1); 18 | queue.push(2); 19 | queue.peek(); // 返回 1 20 | queue.pop(); // 返回 1 21 | queue.empty(); // 返回 false 22 | ``` 23 | 24 | 说明: 25 | 26 | * 你只能使用标准的栈操作 -- 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。 27 | * 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。 28 | * 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。 29 | -------------------------------------------------------------------------------- /solutions/leetcode/239-slidingWindowMaximum/official.md: -------------------------------------------------------------------------------- 1 | **239. 滑动窗口最大值** 2 | --- 3 | [https://leetcode-cn.com/problems/sliding-window-maximum/](https://leetcode-cn.com/problems/linked-list-cycle-ii/) 4 | 5 | -------------------------------------------------------------------------------- /solutions/leetcode/241-DifferentWaysToAddParentheses/README.md: -------------------------------------------------------------------------------- 1 | **241. 为运算表达式设计优先级** 2 | --- 3 | [https://leetcode-cn.com/problems/different-ways-to-add-parentheses/](https://leetcode-cn.com/problems/different-ways-to-add-parentheses/) 4 | 5 | 给定一个含有数字和运算符的字符串,为表达式添加括号,改变其运算优先级以求出不同的结果。你需要给出所有可能的组合的结果。有效的运算符号包含 +, - 以及 * 。 6 | 7 | **示例 1:** 8 | ``` 9 | 输入: "2-1-1" 10 | 输出: [0, 2] 11 | 解释: 12 | ((2-1)-1) = 0 13 | (2-(1-1)) = 2 14 | ``` 15 | 16 | **示例 2:** 17 | 18 | ``` 19 | 输入: "2*3-4*5" 20 | 输出: [-34, -14, -10, -10, 10] 21 | 解释: 22 | (2*(3-(4*5))) = -34 23 | ((2*3)-(4*5)) = -14 24 | ((2*(3-4))*5) = -10 25 | (2*((3-4)*5)) = -10 26 | (((2*3)-4)*5) = 10 27 | ``` 28 | -------------------------------------------------------------------------------- /solutions/leetcode/242-ValidAnagram/README.md: -------------------------------------------------------------------------------- 1 | **242. 有效的字母异位词** 2 | --- 3 | [https://leetcode-cn.com/problems/valid-anagram/](https://leetcode-cn.com/problems/valid-anagram/) 4 | 5 | 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词。 6 | 7 | **示例 1:** 8 | 9 | ``` 10 | 输入: s = "anagram", t = "nagaram" 11 | 输出: true 12 | ``` 13 | 14 | **示例 2:** 15 | 16 | ``` 17 | 输入: s = "rat", t = "car" 18 | 输出: false 19 | ``` 20 | 21 | **说明:** 22 | 你可以假设字符串只包含小写字母。 23 | 24 | **进阶:** 25 | 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况? 26 | -------------------------------------------------------------------------------- /solutions/leetcode/242-ValidAnagram/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 242.有效的异位字符串 2 | 3 | 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词。 4 | 5 | 示例 1: 6 | 7 | 输入: s = "anagram", t = "nagaram" 8 | 输出: true 9 | 示例 2: 10 | 11 | 输入: s = "rat", t = "car" 12 | 输出: false 13 | 说明: 14 | 你可以假设字符串只包含小写字母。 15 | 16 | 思路:使用哈希表,通过统计出现的次数,来判断,数量一致就可以。 17 | 18 | ```py 19 | class Solution: 20 | def isAnagram(self, s, t): 21 | """ 22 | :type s: str 23 | :type t: str 24 | :rtype: bool 25 | """ 26 | dic1, dic2 = {}, {} 27 | for item in s: 28 | dic1[item] = dic1.get(item, 0) + 1 29 | for item in t: 30 | dic2[item] = dic2.get(item, 0) + 1 31 | 32 | return dic1 == dic2 33 | ``` 34 | 时间复杂度:O(s*t) 35 | 36 | 空间复杂度:O(n) 37 | -------------------------------------------------------------------------------- /solutions/leetcode/260-SingleNumberIII/README.md: -------------------------------------------------------------------------------- 1 | **260. 只出现一次的数字 III** 2 | --- 3 | [https://leetcode-cn.com/problems/single-number-iii/](https://leetcode-cn.com/problems/single-number-iii/) 4 | 5 | 给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。 6 | 7 | 示例 : 8 | 9 | ``` 10 | 输入: [1,2,1,3,2,5] 11 | 输出: [3,5] 12 | ``` 13 | 14 | 注意: 15 | 16 | 1. 结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。 17 | 2. 你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现? 18 | -------------------------------------------------------------------------------- /solutions/leetcode/260-SingleNumberIII/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。 2 | 3 | 示例 : 4 | 5 | 输入: [1,2,1,3,2,5] 6 | 输出: [3,5] 7 | 8 | 思路: 9 | 10 | 如果使用O(1)的空间复杂度要怎么做呢?我们很快想到通过位运算。直接对每个nums的元素做xor,最后我们得到的结果就是两个单一元素a和b的xor。因为a和b不相同, 11 | 所以它们之间必定会存在至少一个bit不同,也就是说a xor b的结果中至少有一个bit是1。我们从这么多的bit中挑选出一个,然后其余位置为0,那我们就构成了这样的 12 | 一种mask。例如00...100 13 | 14 | 这样的mask和a和b中元素与元素的话,必定有一个结果是0,另外一个结果是mask,这样我们就将a和b给分开了。那么问题就变成了,怎么构建这样的mask?我们使用一个 15 | 简单的策略就是a xor b的最右边的1作为flag。那要怎么得到最右边的1呢?这就涉及到补码的概念,我们知道负数在计算机中使用补码表示的,也就是反码加1。 16 | 17 | num:5 18 | 原码:0101 19 | 反码:1010 20 | --------- 21 | num:-5 22 | 补码:1011 23 | 24 | 那么我们通过num&-num就可以取出最右边的1了。现在我们就可以遍历nums然后,通过mask就可以判断nums中的那些元素的右边第一位是1(根据上面例子),我们将这些数 25 | 分成一类,将右边第一位是1的数分成为另外一类,并且我们的a和b也就被分到不同的组中。这两组数字的个数不一定相同,但是最后一定是可以相互通过xor消除,最后只剩 26 | a和b。 27 | 28 | ```py 29 | from operator import xor 30 | class Solution(object): 31 | def singleNumber(self, nums): 32 | """ 33 | :type nums: List[int] 34 | :rtype: List[int] 35 | """ 36 | mask = 0 37 | for i in nums: #遍历整个数组,求xor的结果 38 | mask ^= i 39 | mask &= -mask #取出最右的1 40 | result = [0]*2 41 | for num in nums: 42 | if num & mask: #开始遍历得到需要的结果 43 | result[0] ^= num 44 | else: 45 | result[1] ^= num 46 | return result 47 | ``` 48 | 时间复杂度O(n) 49 | 空间复杂度O(1) 50 | -------------------------------------------------------------------------------- /solutions/leetcode/264-UglyNumberII/official.md: -------------------------------------------------------------------------------- 1 | **264. 丑数 II** 2 | --- 3 | [https://leetcode-cn.com/problems/ugly-number-ii/](https://leetcode-cn.com/problems/ugly-number-ii/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/279-PerfectSquares/README.md: -------------------------------------------------------------------------------- 1 | **279. 完全平方数** 2 | --- 3 | [https://leetcode-cn.com/problems/perfect-squares/](https://leetcode-cn.com/problems/perfect-squares/) 4 | 5 | 给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。 6 | 7 | **示例 1:** 8 | 9 | ``` 10 | 输入: n = 12 11 | 输出: 3 12 | 解释: 12 = 4 + 4 + 4. 13 | ``` 14 | 15 | **示例 2:** 16 | 17 | ``` 18 | 输入: n = 13 19 | 输出: 2 20 | 解释: 13 = 4 + 9. 21 | ``` 22 | -------------------------------------------------------------------------------- /solutions/leetcode/279-PerfectSquares/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 279.完全平方数 2 | 3 | https://leetcode-cn.com/problems/perfect-squares/ 4 | 5 | 给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。 6 | 7 | 示例 1: 8 | 9 | 输入: n = 12 10 | 输出: 3 11 | 解释: 12 = 4 + 4 + 4. 12 | 示例 2: 13 | 14 | 输入: n = 13 15 | 输出: 2 16 | 解释: 13 = 4 + 9. 17 | 18 | **思路:** 19 | 1.DP动态规划,关键在于状态的定义和状态方程,我们要知道12最少有多少个数构成,实际上如果我们走了一步的话,要知道11,8,3对应的步数,如果我们不走, 20 | 就需要知道12的步数,我们只要通过比较是走0步小,还是走1步那个更小即可。 21 | 22 | 状态转移方程: 23 | num[n] = min(num[n],num[n-i**2]+1) 24 | 25 | 所以可以先定一个n大小的数组(static类型),需要使数组初始化为无穷大 26 | 27 | ``` 28 | class Solution: 29 | _dp = list() #放到全局,能节省很多时间 30 | def numSquares(self, n): 31 | """ 32 | :type n: int 33 | :rtype: int 34 | """ 35 | dp = self._dp 36 | dp = [float('inf') for i in range(n+1)] #状态定义 37 | dp[0] = 0 38 | for i in range(n+1): 39 | j = 1 40 | while i + j**2 <= n: 41 | dp[i + j**2] = min(dp[i + j**2],dp[i] + 1) #状态转移方程 42 | j+=1 43 | return dp[n] 44 | ``` 45 | 但是这种方法时间复杂度O(n^2)超时了,参考了别人的代码: 46 | 47 | ``` 48 | class Solution: 49 | _dp = [0] 50 | def numSquares(self, n): 51 | dp = self._dp 52 | while len(dp) <= n: 53 | dp += list((min(dp[-i*i] for i in range(1,int(len(dp)**0.5+1)))+1,)) #这里的int无法初始化list,我们只有通过加上一个',', 54 | 将int变成tuple才可以初始化。 55 | return dp[n] 56 | ``` 57 | 这个时候时间复杂度是O(NlogN),时间大大减少 58 | 59 | 参考:https://www.codetd.com/article/2640989 60 | -------------------------------------------------------------------------------- /solutions/leetcode/300-LongestIncreasingSubsequence/README.md: -------------------------------------------------------------------------------- 1 | **300. 最长上升子序列** 2 | --- 3 | [https://leetcode-cn.com/problems/longest-increasing-subsequence/](https://leetcode-cn.com/problems/longest-increasing-subsequence/) 4 | 5 | 给定一个无序的整数数组,找到其中最长上升子序列的长度。 6 | 7 | **示例:** 8 | 9 | ``` 10 | 输入: [10,9,2,5,3,7,101,18] 11 | 输出: 4 12 | 解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。 13 | ``` 14 | 15 | **说明:** 16 | 17 | * 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可 18 | * 你算法的时间复杂度应该为 O(n2) 19 | 20 | **进阶:** 21 | 你能将算法的时间复杂度降低到 O(n log n) 吗? 22 | 23 | -------------------------------------------------------------------------------- /solutions/leetcode/303-rangeSumQueryImmutable/BambooYH.md: -------------------------------------------------------------------------------- 1 | **区域和检索 - 数组不可变** 2 | 3 | [https://leetcode.com/problems/range-sum-query-immutable/](https://leetcode.com/problems/range-sum-query-immutable/) 4 | 5 | 解决方案: 6 | 方法一:**辅助数组** 7 | **思路**: 8 | 此题的要求是求区间和,如果按照题意,直接暴力解决,肯定会超时。所以我们要想一个办法,遍历一遍,就能把结果存在一个辅助数组中。然后当我们要求结果的时候,直接取出来就行了。因为是求一个连续区间的和。比如说求[i,j]的和,如果我们知道了[0,j]和[0,i-1]的和,然后相减,就可以得到[i,j]的和 9 | **算法**: 10 | 我们要求SumRange(i,j),我们可以用`sum[j+1]-sum[i]`这个公式来求,其中sum[i]表示0到i-1的和。所以我们可以遍历一遍,求出sum[i],然后通过上面的式子来取得结果。 11 | 代码: 12 | ``` 13 | public class NumArray { 14 | private int[] sum; 15 | 16 | public NumArray(int[] nums) { 17 | //初始化数组 18 | sum = new int[nums.length + 1]; 19 | //遍历数组,求出sum[i] 20 | for (int i = 0; i < nums.length; i++) { 21 | sum[i + 1] = sum[i] + nums[i]; 22 | } 23 | } 24 | 25 | public int sumRange(int i, int j) { 26 | //两者相减,就是所求的 27 | return sum[j + 1] - sum[i]; 28 | } 29 | } 30 | 31 | ``` 32 | 复杂度分析 33 | 假设数组长度为N 34 | 空间复杂度:O(N) 35 | 时间复杂度:O(1),每次查询时间复杂度是O(1),计算的时间复杂度O(N) 36 | -------------------------------------------------------------------------------- /solutions/leetcode/303-rangeSumQueryImmutable/README.md: -------------------------------------------------------------------------------- 1 | **303. 区域和检索 - 数组不可变** 2 | --- 3 | [https://leetcode-cn.com/problems/range-sum-query-immutable/](https://leetcode-cn.com/problems/range-sum-query-immutable/) 4 | 5 | 给定一个整数数组 nums,求出数组从索引 i 到 j (i ≤ j) 范围内元素的总和,包含 i, j 两点。 6 | 7 | **示例:** 8 | 9 | ``` 10 | 给定 nums = [-2, 0, 3, -5, 2, -1],求和函数为 sumRange() 11 | 12 | sumRange(0, 2) -> 1 13 | sumRange(2, 5) -> -1 14 | sumRange(0, 5) -> -3 15 | ``` 16 | 17 | **说明:** 18 | 19 | 1. 你可以假设数组不可变。 20 | 2. 会多次调用 sumRange 方法。 21 | -------------------------------------------------------------------------------- /solutions/leetcode/304-RangeSumQuery2DImmutable/official.md: -------------------------------------------------------------------------------- 1 | **304. 二维区域和检索 - 矩阵不可变** 2 | --- 3 | [https://leetcode-cn.com/problems/range-sum-query-2d-immutable/](https://leetcode-cn.com/problems/range-sum-query-2d-immutable/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/309-BestTimeToBuyAndSellStockWithCooldown/README.md: -------------------------------------------------------------------------------- 1 | **303. 区域和检索 - 数组不可变** 2 | --- 3 | [https://leetcode-cn.com/problems/range-sum-query-immutable/](https://leetcode-cn.com/problems/range-sum-query-immutable/) 4 | 5 | 给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。​ 6 | 7 | 设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票): 8 | 9 | * 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票) 10 | * 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天) 11 | 12 | **示例:** 13 | 14 | ``` 15 | 输入: [1,2,3,0,2] 16 | 输出: 3 17 | 解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出] 18 | ``` 19 | -------------------------------------------------------------------------------- /solutions/leetcode/312-BurstBalloons/official.md: -------------------------------------------------------------------------------- 1 | **312. 戳气球** 2 | --- 3 | [https://leetcode-cn.com/problems/burst-balloons/](https://leetcode-cn.com/problems/burst-balloons/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/321-CreateMaximumNumber/README.md: -------------------------------------------------------------------------------- 1 | **321. 拼接最大数** 2 | --- 3 | [https://leetcode-cn.com/problems/create-maximum-number/](https://leetcode-cn.com/problems/create-maximum-number/) 4 | 5 | **难度** 6 | 困难 7 | 8 | **题目描述** 9 | 10 | 给定长度分别为 m 和 n 的两个数组,其元素由 0-9 构成,表示两个自然数各位上的数字。现在从这两个数组中选出 k (k <= m + n) 个数字拼接成一个新的数,要求从同一个数组中取出的数字保持其在原数组中的相对顺序。 11 | 12 | 求满足该条件的最大数。结果返回一个表示该最大数的长度为 k 的数组。 13 | 14 | 说明: 请尽可能地优化你算法的时间和空间复杂度。 15 | 16 | **示例 1:** 17 | ``` 18 | 输入: 19 | nums1 = [3, 4, 6, 5] 20 | nums2 = [9, 1, 2, 5, 8, 3] 21 | k = 5 22 | 输出: 23 | [9, 8, 6, 5, 3] 24 | ``` 25 | 26 | **示例 2:** 27 | ``` 28 | 输入: 29 | nums1 = [6, 7] 30 | nums2 = [6, 0, 4] 31 | k = 5 32 | 输出: 33 | [6, 7, 6, 0, 4] 34 | ``` 35 | 36 | **示例 3:** 37 | ``` 38 | 输入: 39 | nums1 = [3, 9] 40 | nums2 = [8, 9] 41 | k = 3 42 | 输出: 43 | [9, 8, 9] 44 | ``` 45 | 46 | 47 | **相关话题** 48 | 贪心算法,动态规划 -------------------------------------------------------------------------------- /solutions/leetcode/322-CoinChange/official.md: -------------------------------------------------------------------------------- 1 | **322. 零钱兑换** 2 | --- 3 | [https://leetcode-cn.com/problems/coin-change/](https://leetcode-cn.com/problems/coin-change/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/343-IntegerBreak/README.md: -------------------------------------------------------------------------------- 1 | **343. 整数拆分** 2 | --- 3 | [https://leetcode-cn.com/problems/integer-break/](https://leetcode-cn.com/problems/integer-break/) 4 | 5 | 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 6 | 7 | **示例 1:** 8 | 9 | ``` 10 | 输入: 2 11 | 输出: 1 12 | 解释: 2 = 1 + 1, 1 × 1 = 1。 13 | ``` 14 | 15 | **示例 2:** 16 | 17 | ``` 18 | 输入: 10 19 | 输出: 36 20 | 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。 21 | ``` 22 | 23 | 说明: 你可以假设 n 不小于 2 且不大于 58。 24 | 25 | -------------------------------------------------------------------------------- /solutions/leetcode/343-IntegerBreak/hatrick.md: -------------------------------------------------------------------------------- 1 | **343. 整数拆分** 2 | --- 3 | [https://leetcode-cn.com/problems/integer-break/](https://leetcode-cn.com/problems/integer-break/) 4 | 5 | 解决方案 6 | **思路** 7 | 建立一个乘积数组,数组的下标i存放这i所能拆分之后的最大乘积,然后下标为n的数的最大乘积可以表示为两个更小的数所能拆分的乘积之和, 8 | 而这两个更小的数可以进一步拆分,不过这一步已经被记录在乘积数组中了,我们不必再考虑进一步的拆分 9 | ``` 10 | class Solution { 11 | public int integerBreak(int n) { 12 | int[] product =new int[n+1]; 13 | //product数组用来存放数i所能拆分的最大乘积 14 | product[1]=1; 15 | for(int i=1;i<=n;i++) 16 | { 17 | int a=1,b=i-1; 18 | while(a<=b&&a+b==i) 19 | { 20 | int multi =(product[a]>a?product[a]:a)*(product[b]>b?product[b]:b); 21 | //将数i拆分成a和b,要想产生最大乘积,我们需要选出a所拆分出的乘积和a本身中较大的一个数 22 | if(product[i]= 0 and j < n: 44 | if matrix[i][j] <= target: 45 | res += i+1 #如果左下角的数比target小,那么就向右移 46 | j += 1 47 | else: #反之向上移动 48 | i -= 1 49 | 50 | return res 51 | ``` 52 | 53 | 时间复杂度O(nlgX),X为最大值和最小值的差值 54 | -------------------------------------------------------------------------------- /solutions/leetcode/392-IsSubsequence/official.md: -------------------------------------------------------------------------------- 1 | **392. 判断子序列** 2 | --- 3 | [https://leetcode-cn.com/problems/is-subsequence/](https://leetcode-cn.com/problems/is-subsequence/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/403-FrogJump/README.md: -------------------------------------------------------------------------------- 1 | **403. 青蛙过河** 2 | --- 3 | [https://leetcode-cn.com/problems/frog-jump/](https://leetcode-cn.com/problems/frog-jump/) 4 | 5 | **难度** 6 | 困难 7 | 8 | **题目描述** 9 | 10 | 一只青蛙想要过河。 假定河流被等分为 x 个单元格,并且在每一个单元格内都有可能放有一石子(也有可能没有)。 青蛙可以跳上石头,但是不可以跳入水中。 11 | 12 | 给定石子的位置列表(用单元格序号升序表示), **请判定青蛙能否成功过河**(即能否在最后一步跳至最后一个石子上)。 开始时, 青蛙默认已站在第一个石子上,并可以假定它第一步只能跳跃一个单位(即只能从单元格1跳至单元格2)。 13 | 14 | 如果青蛙上一步跳跃了 k 个单位,那么它接下来的跳跃距离只能选择为 k - 1、k 或 k + 1个单位。 另请注意,青蛙只能向前方(终点的方向)跳跃。 15 | 16 | **请注意:** 17 | 18 | * 石子的数量 ≥ 2 且 < 1100; 19 | * 每一个石子的位置序号都是一个非负整数,且其 < 231; 20 | * 第一个石子的位置永远是0。 21 | 22 | **示例 1:** 23 | ```shell 24 | [0,1,3,5,6,8,12,17] 25 | 26 | 总共有8个石子。 27 | 第一个石子处于序号为0的单元格的位置, 第二个石子处于序号为1的单元格的位置, 28 | 第三个石子在序号为3的单元格的位置, 以此定义整个数组... 29 | 最后一个石子处于序号为17的单元格的位置。 30 | 31 | 返回 true。即青蛙可以成功过河,按照如下方案跳跃: 32 | 跳1个单位到第2块石子, 然后跳2个单位到第3块石子, 接着 33 | 跳2个单位到第4块石子, 然后跳3个单位到第6块石子, 34 | 跳4个单位到第7块石子, 最后,跳5个单位到第8个石子(即最后一块石子)。 35 | ``` 36 | 37 | **示例 2:** 38 | ```shell 39 | 40 | [0,1,2,3,4,8,9,11] 41 | 42 | 返回 false。青蛙没有办法过河。 43 | 这是因为第5和第6个石子之间的间距太大,没有可选的方案供青蛙跳跃过去。 44 | ``` 45 | 46 | **相关话题** 47 | 贪心算法,动态规划 -------------------------------------------------------------------------------- /solutions/leetcode/409-LongestPalindrome/README.md: -------------------------------------------------------------------------------- 1 | **409. 最长回文串** 2 | --- 3 | [https://leetcode-cn.com/problems/longest-palindrome/](https://leetcode-cn.com/problems/longest-palindrome/) 4 | 5 | 给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。 6 | 7 | 在构造过程中,请注意区分大小写。比如 "Aa" 不能当做一个回文字符串。 8 | 9 | 注意: 10 | 假设字符串的长度不会超过 1010。 11 | 12 | 示例 1: 13 | 14 | ``` 15 | 输入: 16 | "abccccdd" 17 | 18 | 输出: 19 | 7 20 | 21 | 解释: 22 | 我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。 23 | ``` 24 | -------------------------------------------------------------------------------- /solutions/leetcode/409-LongestPalindrome/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | **409. 最长回文串** 2 | --- 3 | [https://leetcode-cn.com/problems/longest-palindrome/](https://leetcode-cn.com/problems/longest-palindrome/) 4 | 5 | 给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。 6 | 7 | 在构造过程中,请注意区分大小写。比如 "Aa" 不能当做一个回文字符串。 8 | 9 | 注意: 10 | 假设字符串的长度不会超过 1010。 11 | 12 | 示例 1: 13 | 14 | ``` 15 | 输入: 16 | "abccccdd" 17 | 18 | 输出: 19 | 7 20 | 21 | 解释: 22 | 我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。 23 | ``` 24 | 25 | 思路:这道回文字符串包括以前的回文字符串的题目都比较重要,由于这里的字符串可以打乱,所以问题就转化成了求偶数个字符的个数,我们了解的回文字符串都知道, 26 | 回文串主要有两种形式,一个是左右完全对称的,比如noon,还有一种是以中心字符为中心,左右对称,比如bob,那么统计出来所有偶数个字符的出现总和,然后如果有 27 | 奇数个字符的化,我们取出其最大偶数,然后最后结果加上1就可以啦。 28 | 29 | ```py 30 | class Solution: 31 | def longestPalindrome(self, s: str) -> int: 32 | dict1 = {} #用来存储出现过的字符和出现的次数 33 | j = 0 #存储回文长度 34 | z = 0 #统计单数次字符的个数 35 | for i in range(len(s)): 36 | if s[i] in dict1: 37 | dict1[s[i]] += 1 #出现的字符作为键,次数作为value值 38 | else: 39 | dict1[s[i]] = 1 40 | for v in dict1: #对构建好的字典进行遍历 41 | if (dict1[v] + 1) % 2==0: #出现单数次字符次数减一 42 | j+=(dict1[v]-1) 43 | z+=1 44 | if dict1[v] % 2 == 0: #出现偶数次字符,一定可以构造 45 | j+=dict1[v] 46 | if z > 0: 47 | return j+1 48 | else: 49 | return j 50 | ``` 51 | 这个时间复杂度较高:O(n^2) 52 | 空间复杂度O(n) 53 | -------------------------------------------------------------------------------- /solutions/leetcode/410-SplitArrayLargestSum/hatrick.md: -------------------------------------------------------------------------------- 1 | **410. 分割数组的最大值** 2 | --- 3 | [https://leetcode-cn.com/problems/split-array-largest-sum/](https://leetcode-cn.com/problems/split-array-largest-sum/) 4 | 5 | 解决方案 6 | **思路** 7 | 使用二分法,首先可以发现,难点在于怎么判断分割是否可行,可以发现,当m=1的时候肯定可行(和最大,全部元素在一块), 8 | 当m=nums.length的时候也可行(和最小,为全部元素中的最大值),那么就二分这个最大和最小值就可以了,判断是否可分, 9 | 可分就将和缩小,使得需要的m值变小;反之则扩大 10 | ``` 11 | //使用二分法进行动态查找 12 | public int splitArray(int[] nums, int m) { 13 | long left = 0, right = 0; 14 | for (int n: nums) { 15 | right += n; 16 | } 17 | if (m == 1) { 18 | return (int)right; 19 | } 20 | long result = 0; 21 | long mid; 22 | while (left <= right) { 23 | mid = left+right >> 1; 24 | if (judge(mid, nums, m)) { 25 | result = mid; 26 | right = mid-1; 27 | } else { 28 | left = mid+1; 29 | } 30 | } 31 | return (int)result; 32 | } 33 | 34 | private boolean judge(long mid, int[] nums, int m) { 35 | int sum = 0; 36 | for (int i = 0; i < nums.length; i++) { 37 | if (nums[i] > mid) { 38 | return false; 39 | } 40 | if (sum + nums[i] > mid) { 41 | sum = nums[i]; 42 | m--; 43 | } else { 44 | sum += nums[i]; 45 | } 46 | } 47 | return m >= 1; 48 | } 49 | ``` 50 | **复杂度分析** 51 | 平均时间复杂度:O(nlogn) 52 | 空间复杂度:O(1) 53 | 54 | **参考资料** 55 | [https://blog.csdn.net/zhangjingao/article/details/86607677](https://blog.csdn.net/zhangjingao/article/details/86607677) -------------------------------------------------------------------------------- /solutions/leetcode/410-SplitArrayLargestSum/official.md: -------------------------------------------------------------------------------- 1 | **410. 分割数组的最大值** 2 | --- 3 | [https://leetcode-cn.com/problems/split-array-largest-sum/](https://leetcode-cn.com/problems/split-array-largest-sum/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/413-arithmeticSlices/official.md: -------------------------------------------------------------------------------- 1 | **413. 等差数列划分** 2 | --- 3 | [https://leetcode-cn.com/problems/arithmetic-slices/](https://leetcode-cn.com/problems/arithmetic-slices/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/416-PartitionEqualSubsetSum/README.md: -------------------------------------------------------------------------------- 1 | **416. 分割等和子集** 2 | --- 3 | [https://leetcode-cn.com/problems/partition-equal-subset-sum/](https://leetcode-cn.com/problems/partition-equal-subset-sum/) 4 | 5 | 给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 6 | 7 | **注意:** 8 | 9 | 1. 每个数组中的元素不会超过 100 10 | 2. 数组的大小不会超过 200 11 | 12 | **示例 1:** 13 | 14 | ``` 15 | 输入: [1, 5, 11, 5] 16 | 17 | 输出: true 18 | 19 | 解释: 数组可以分割成 [1, 5, 5] 和 [11]. 20 | ``` 21 | 22 | **示例 2:** 23 | 24 | ``` 25 | 输入: [1, 2, 3, 5] 26 | 27 | 输出: false 28 | ``` 29 | 30 | 解释: 数组不能分割成两个元素和相等的子集. 31 | -------------------------------------------------------------------------------- /solutions/leetcode/446-ArithmeticSlicesIISubsequence/official.md: -------------------------------------------------------------------------------- 1 | **446. 等差数列划分 II - 子序列** 2 | --- 3 | [https://leetcode-cn.com/problems/arithmetic-slices-ii-subsequence/](https://leetcode-cn.com/problems/arithmetic-slices-ii-subsequence/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/455-AssignCookies/README.md: -------------------------------------------------------------------------------- 1 | **455. 分发饼干** 2 | --- 3 | [https://leetcode-cn.com/problems/assign-cookies/](https://leetcode-cn.com/problems/assign-cookies/) 4 | 5 | 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 6 | 7 | **注意:** 8 | 9 | 你可以假设胃口值为正。 10 | 一个小朋友最多只能拥有一块饼干。 11 | 12 | **示例 1:** 13 | 14 | ``` 15 | 输入: [1,2,3], [1,1] 16 | 17 | 输出: 1 18 | 19 | 解释: 20 | 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 21 | 虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 22 | 所以你应该输出1。 23 | ``` 24 | 25 | **示例 2:** 26 | 27 | ``` 28 | 输入: [1,2], [1,2,3] 29 | 30 | 输出: 2 31 | 32 | 解释: 33 | 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 34 | 你拥有的饼干数量和尺寸都足以让所有孩子满足。 35 | 所以你应该输出2. 36 | ``` 37 | -------------------------------------------------------------------------------- /solutions/leetcode/455-AssignCookies/SpecialYang.md: -------------------------------------------------------------------------------- 1 | **分发饼干** 2 | https://leetcode.com/problems/assign-cookies/ 3 | --- 4 | ### 思路一 5 | 说实话,我看的是英文版,第一次竟然没读懂题意了,打扰了! 6 | 后来看了翻译,才明白题意:现在有一堆孩子,每个孩子的胃口不一样,有一堆饼干,饼干的大小也不一。我们的目标是把这些饼干尽可能多的分配给这些小朋友,求出最多满足多少个小朋友。 7 | 1. 只要饼干的尺寸大于等于孩子胃口,才可以满足 8 | 2. 一个饼干只能分给一个小朋友,一个小朋友只能吃一个饼干 9 | 10 | 11 | 典型的**贪心**做法,我们只需把最接近孩子胃口的饼干分配给对应的孩子即可,这样我们就可以把更大的饼干分给胃口更大的孩子。即优先使用最满足孩子胃口的饼干分配。 12 | 13 | 我们可以对孩子和饼干分配从小到大排序,然后遍历饼干,判断饼干与当前孩子大小关系,若满足,则分配给孩子,换下一个孩子和下一个饼干;若不满足,换下一个饼干与当前的孩子比较。 14 | ```java 15 | /** 16 | * 优先把尺寸接近孩子胃口的饼干分发 17 | * 18 | * 局部最优 19 | * @param g 20 | * @param s 21 | * @return 22 | */ 23 | public int findContentChildren(int[] g, int[] s) { 24 | Arrays.sort(g); 25 | Arrays.sort(s); 26 | int child = 0, size = 0; 27 | while (child < g.length && size < s.length) { 28 | if (g[child] <= s[size++]) { 29 | child++; 30 | } 31 | } 32 | return child; 33 | } 34 | ``` -------------------------------------------------------------------------------- /solutions/leetcode/455-AssignCookies/bigablecat.md: -------------------------------------------------------------------------------- 1 | **455. 分发饼干** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/assign-cookies/](https://leetcode-cn.com/problems/assign-cookies/) 5 | 6 | * 网友高票Java解法 7 | 8 | ```java 9 | 10 | public int findContentChildren(int[] g, int[] s) { 11 | //调用java.util.Arrays.sort排序方法 12 | //分别给孩子期望和饼干大小排序 13 | Arrays.sort(g); 14 | Arrays.sort(s); 15 | int i = 0; //定义数组g的下标初始值i 16 | //遍历数组s 17 | for (int j = 0; i < g.length && j < s.length; j++) { 18 | //g[i]是数组g在i位置的元素,表示第i个孩子的胃口 19 | //s[j]是数组s在j位置的元素,表示第j个饼干的尺寸 20 | //经过排序,g[i]从孩子最小的胃口开始 21 | //g[i]<=s[j]说明j位置的饼干可以满足第i个孩子 22 | //此时让i++,看s[j]是否能满足更大胃口的孩子 23 | if (g[i] <= s[j]) i++; 24 | } 25 | //最后返回的i就是最多能满足多少个孩子 26 | return i; 27 | } 28 | 29 | ``` 30 | 31 | **复杂度分析** 32 | 33 | 时间复杂度:O(nlogn), 34 | 设两个数组的长度分别是 m 和 n 35 | Arrays.sort使用的DualPivotQuickSort在经典快排基础上改进, 36 | 时间复杂度稳定为O(nlogn), 37 | Arrays.sort使用了两次,所以排序的时间复杂度是 38 | mlogm + nlogn, 39 | for循环内虽然对两个数组进行操作, 40 | 但是两个数组都没有被重复从头遍历, 41 | 所以最坏情况的遍历次数是两个数组的长度之和 42 | m+n, 43 | 最终的时间复杂度是 44 | O(mlogm + nlogn + m + n) = O(nlogn) 45 | 46 | 空间复杂度:O(n), 47 | Arrays.sort排序方法的空间复杂度是O(n), 48 | 使用了两次,所以空间复杂度是O(2n), 49 | 最终的空间复杂度是O(n) 50 | 51 | --- 52 | 53 | **参考资料** 54 | 55 | * 网友高票Java解法: 56 | [https://leetcode.com/problems/assign-cookies/discuss/93987/Simple-Greedy-Java-Solution](https://leetcode.com/problems/assign-cookies/discuss/93987/Simple-Greedy-Java-Solution) 57 | -------------------------------------------------------------------------------- /solutions/leetcode/462-MinimumMovesToEqualArrayElementsII/README.md: -------------------------------------------------------------------------------- 1 | **462. 最少移动次数使数组元素相等 II** 2 | --- 3 | [https://leetcode-cn.com/problems/minimum-moves-to-equal-array-elements-ii/](https://leetcode-cn.com/problems/minimum-moves-to-equal-array-elements-ii/) 4 | 5 | 给定一个非空整数数组,找到使所有数组元素相等所需的最小移动数,其中每次移动可将选定的一个元素加1或减1。 您可以假设数组的长度最多为10000。 6 | 7 | ``` 8 | 例如: 9 | 10 | 输入: 11 | [1,2,3] 12 | 13 | 输出: 14 | 2 15 | 16 | 说明: 17 | 只有两个动作是必要的(记得每一步仅可使其中一个元素加1或减1): 18 | 19 | [1,2,3] => [2,2,3] => [2,2,2] 20 | ``` 21 | -------------------------------------------------------------------------------- /solutions/leetcode/462-MinimumMovesToEqualArrayElementsII/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 给定一个非空整数数组,找到使所有数组元素相等所需的最小移动数,其中每次移动可将选定的一个元素加1或减1。 您可以假设数组的长度最多为10000。 2 | 3 | 例如: 4 | 5 | 输入: 6 | [1,2,3] 7 | 8 | 输出: 9 | 2 10 | 11 | 说明: 12 | 只有两个动作是必要的(记得每一步仅可使其中一个元素加1或减1): 13 | 14 | [1,2,3] => [2,2,3] => [2,2,2] 15 | 16 | 思路: 17 | 18 | 本题主要是通过查找中间位置的数,然后进行移动步数,最后将移动步数全部求和.先排序,把中间位置的数拿出来,然后计算数组中每个数字与中间数的差值的绝对值 19 | 相加即可 20 | 21 | ```py 22 | class Solution(object): 23 | def minMoves2(self, nums): 24 | """ 25 | :type nums: List[int] 26 | :rtype: int 27 | """ 28 | temp = [] 29 | nums.sort() 30 | mid = len(nums)/2 #二分 31 | mid_num = nums[mid] #取出中间的数 32 | nums.remove(nums[mid]) 33 | for i in nums: 34 | if mid_num >= i: #数组中每个数字与中间数的差值 35 | step = mid_num - i 36 | temp.append(step) 37 | else: 38 | step = i - mid_num 39 | temp.append(step) 40 | return sum(temp) 41 | ``` 42 | 时间复杂度:O(nlogn) 43 | 空间复杂度:O(n) 44 | -------------------------------------------------------------------------------- /solutions/leetcode/464-CanIWin/official.md: -------------------------------------------------------------------------------- 1 | **464. 我能赢吗** 2 | --- 3 | [https://leetcode-cn.com/problems/can-i-win/](https://leetcode-cn.com/problems/can-i-win/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/472-ConcatenatedWords/official.md: -------------------------------------------------------------------------------- 1 | **472. 连接词** 2 | --- 3 | [https://leetcode-cn.com/problems/concatenated-words/](https://leetcode-cn.com/problems/concatenated-words/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/474-OnesAndZeroes/hatrick.md: -------------------------------------------------------------------------------- 1 | **474. 一和零** 2 | --- 3 | [https://leetcode-cn.com/problems/ones-and-zeroes/](https://leetcode-cn.com/problems/ones-and-zeroes/) 4 | 5 | 解决方案 6 | **思路** 7 | 和01背包是很相似的题目,只不过背包问题是装一种东西,而我们这道题要求的是装上两种东西,也就是1和0。 8 | 我们的1和0相当于两类物品,n和m就是它们所对应的容量。 9 | 我们的到第i个字符串时, 它所对应的可以组成最多的字符串个数则就对应为: 10 | dp[m][n]=MAX(dp[m][n],dp[m-count0][n-count1]+1) 11 | 所以我们要做的就是在迭代字符串的时候,即时更新dp[m][n];也就是说每多一个字符串,我就计算一下加进来这个字符串之后,我所能拼接成的最大字符串数量。 12 | 也就是说 当我只有一个字符串的时候,我求出我的dp[m][n],当我有两个字符串的时候,我根据上面的情况,在继续求出我现在的dp[m][n], 每多一个,就更新一下。 13 | 注意dp[m][n]是随着迭代而更新的 14 | ``` 15 | class Solution { 16 | //0-1背包问题,优化存储空间 17 | public int findMaxForm(String[] strs, int m, int n) { 18 | int l = strs.length; 19 | int zeros, ones; 20 | // dp[i][j]代表遍历到当前字符串时使用i个0和j个1所能组成的最大字符串数量 21 | int[][] dp = new int[m+1][n+1]; 22 | for(int i = 0; i < l ; i++){ 23 | zeros = 0; 24 | ones = 0; 25 | for(int j = 0; j < strs[i].length(); j++){ 26 | if(strs[i].charAt(j) == '0'){ 27 | zeros++; 28 | }else{ 29 | ones++; 30 | } 31 | } 32 | for(int j = m; j >= zeros; j--){ 33 | for(int k = n; k >= ones; k--){ 34 | dp[j][k] = Math.max(dp[j][k], dp[j-zeros][k-ones] + 1); 35 | } 36 | } 37 | } 38 | return dp[m][n]; 39 | } 40 | } 41 | ``` 42 | **复杂度分析** 43 | 时间复杂度:O(n) 44 | 空间复杂度:O(n) 45 | 46 | **参考资料** 47 | [https://blog.csdn.net/qq_38595487/article/details/84235304](https://blog.csdn.net/qq_38595487/article/details/84235304) -------------------------------------------------------------------------------- /solutions/leetcode/474-OnesAndZeroes/official.md: -------------------------------------------------------------------------------- 1 | **474. 一和零** 2 | --- 3 | [https://leetcode-cn.com/problems/ones-and-zeroes/](https://leetcode-cn.com/problems/ones-and-zeroes/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/486-PredictTheWinner/official.md: -------------------------------------------------------------------------------- 1 | **486. 预测赢家** 2 | --- 3 | [https://leetcode-cn.com/problems/predict-the-winner/](https://leetcode-cn.com/problems/predict-the-winner/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/494-TargetSum/official.md: -------------------------------------------------------------------------------- 1 | **494. 目标和** 2 | --- 3 | [https://leetcode-cn.com/problems/target-sum/](https://leetcode-cn.com/problems/target-sum/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/504-Base7/README.md: -------------------------------------------------------------------------------- 1 | **504. 七进制数** 2 | --- 3 | [https://leetcode-cn.com/problems/base-7/](https://leetcode-cn.com/problems/base-7/) 4 | 5 | 给定一个整数,将其转化为7进制,并以字符串形式输出。 6 | 7 | 示例 1: 8 | 9 | ``` 10 | 输入: 100 11 | 输出: "202" 12 | ``` 13 | 14 | 示例 2: 15 | 16 | ``` 17 | 输入: -7 18 | 输出: "-10" 19 | ``` 20 | 21 | 注意: 输入范围是 [-1e7, 1e7] 。 22 | -------------------------------------------------------------------------------- /solutions/leetcode/504-Base7/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 给定一个整数,将其转化为7进制,并以字符串形式输出。 2 | 3 | 示例 1: 4 | 5 | 输入: 100 6 | 输出: "202" 7 | 示例 2: 8 | 9 | 输入: -7 10 | 输出: "-10" 11 | 注意: 输入范围是 [-1e7, 1e7] 。 12 | 13 | 思路: 14 | 15 | 直接把获取到的数据的模对7取余,再加在后面成为字符串。每次取余之后都要除以7.注意最后要判断正负 16 | 17 | ```py 18 | class Solution(object): 19 | def convertToBase7(self, num): 20 | """ 21 | :type num: int 22 | :rtype: str 23 | """ 24 | if num == 0: 25 | return "0" 26 | else: 27 | res = str() 28 | n = abs(num) 29 | while n: 30 | res = str(n%7) + res 31 | n = n//7 32 | return res if num>0 else '-'+res 33 | ``` 34 | 时间复杂度:O(n) 35 | 空间复杂度:O(n) 36 | -------------------------------------------------------------------------------- /solutions/leetcode/513-FindBottomLeftTreeValue/README.md: -------------------------------------------------------------------------------- 1 | **513. 找树左下角的值** 2 | --- 3 | [https://leetcode-cn.com/problems/find-bottom-left-tree-value/](https://leetcode-cn.com/problems/find-bottom-left-tree-value/) 4 | 5 | 给定一个二叉树,在树的最后一行找到最左边的值。 6 | 7 | **示例 1:** 8 | 9 | ``` 10 | 输入: 11 | 12 | 2 13 | / \ 14 | 1 3 15 | 16 | 输出: 17 | 1 18 | ``` 19 | 20 | **示例 2:** 21 | 22 | ``` 23 | 输入: 24 | 25 | 1 26 | / \ 27 | 2 3 28 | / / \ 29 | 4 5 6 30 | / 31 | 7 32 | 33 | 输出: 34 | 7 35 | ``` 36 | 37 | 38 | 注意: 您可以假设树(即给定的根节点)不为 NULL。 39 | 40 | -------------------------------------------------------------------------------- /solutions/leetcode/513-FindBottomLeftTreeValue/bigablecat.md: -------------------------------------------------------------------------------- 1 | **513. 找树左下角的值** 2 | --- 3 | [https://leetcode-cn.com/problems/find-bottom-left-tree-value/](https://leetcode-cn.com/problems/find-bottom-left-tree-value/) 4 | 5 | * 网友高票Java解法: 6 | 7 | ```java 8 | /** 9 | * 网友高票Java解法 10 | * 11 | * @param root 12 | * @return 13 | */ 14 | public int findBottomLeftValue(TreeNode root) { 15 | //定义一个队列 16 | Queue queue = new LinkedList<>(); 17 | //将当前节点加入队列 18 | queue.add(root); 19 | //如果队列非空,继续循环 20 | while (!queue.isEmpty()) { 21 | //从队列中取出第一个元素,赋值给root 22 | root = queue.poll(); 23 | //如果root右子节点非空 24 | //将右子节点加入队列 25 | if (root.right != null) 26 | queue.add(root.right); 27 | //同理将左子节点加入队列 28 | if (root.left != null) 29 | queue.add(root.left); 30 | 31 | //队列先进先出 32 | //右子节点先被放进Queue,会在下一轮循环中先出 33 | //这个解法的思路是不断搜索树的节点 34 | //将节点按照右-左的顺序存入队列 35 | //再在下一轮循环中弹出队列顶端的节点 36 | //最终队列只留下树最后一行的左节点 37 | } 38 | //返回最后一行左节点的值 39 | return root.val; 40 | } 41 | 42 | 43 | ``` 44 | 45 | **参考资料** 46 | 47 | * 网友高票Java解法: 48 | [https://leetcode.com/problems/find-bottom-left-tree-value/discuss/98779/Right-to-Left-BFS-(Python-%2B-Java)](https://leetcode.com/problems/find-bottom-left-tree-value/discuss/98779/Right-to-Left-BFS-(Python-%2B-Java)) 49 | -------------------------------------------------------------------------------- /solutions/leetcode/513-FindBottomLeftTreeValue/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 513.给定一个二叉树,在树的最后一行找到最左边的值。 2 | 3 | 示例 1: 4 | 5 | 输入: 6 | 7 | 2 8 | 9 | / \ 10 | 11 | 1 3 12 | 13 | 输出: 14 | 1 15 | 16 | 17 | 示例 2: 18 | 19 | 输入: 20 | 21 | 1 22 | / \ 23 | 2 3 24 | / / \ 25 | 4 5 6 26 | / 27 | 7 28 | 29 | 输出: 30 | 7 31 | 32 | 33 | 注意: 您可以假设树(即给定的根节点)不为 NULL。 34 | 35 | 思路:可以用队列来层次遍历, 36 | 37 | ```py 38 | class Solution: 39 | def findBottomLeftValue(self, root: TreeNode) -> int: 40 | result, queue = [], [root] 41 | while queue: 42 | temp = [] 43 | result = queue[0].val #取出每一层根的val 44 | for node in queue: 45 | if node.left: 46 | temp.append(node.left) #层次遍历 47 | if node.right: 48 | temp.append(node.right) 49 | queue = temp 50 | return result 51 | ``` 52 | 时间复杂度:O(n^2) 53 | 空间复杂度:O(n) 54 | -------------------------------------------------------------------------------- /solutions/leetcode/514-FreedomTrail/hatrick.md: -------------------------------------------------------------------------------- 1 | **514. 自由之路** 2 | --- 3 | [https://leetcode-cn.com/problems/freedom-trail/](https://leetcode-cn.com/problems/freedom-trail/) 4 | 解决方案 5 | **思路** 6 | 路径搜索问题,或者字符串匹配问题,可以正向或者逆向匹配. 7 | 动态规划记录当前的状态result[i][j],即当前匹配到key的第i个字母,ring的第j个字母在12点方向, 8 | 要匹配key的下一个字母时,可以从上一个状态顺时针或者逆时针转移到现在的状态. 9 | ``` 10 | class Solution { 11 | public int findRotateSteps(String ring, String key) { 12 | if (ring == null || key == null) return 0; 13 | int m = ring.length(); 14 | int n = key.length(); 15 | int[][] result = new int[n][m]; 16 | for (int i = 0; i < n; i++) { 17 | for (int j = 0; j < m; j++) { 18 | result[i][j] = Integer.MAX_VALUE; 19 | } 20 | } 21 | for (int i = 0; i < n; i++) { 22 | for (int j = 0; j < m; j++) { 23 | if (key.charAt(i) == ring.charAt(j)) { 24 | if (i == 0) { 25 | result[i][j] = Math.min(j, m - j); 26 | } else { 27 | for (int k = 0; k < m; k++) { 28 | if (result[i - 1][k] != Integer.MAX_VALUE) 29 | result[i][j] = Math.min(result[i][j], result[i - 1][k] + Math.min(Math.abs(j - k), m - Math.abs(j - k))); 30 | } 31 | } 32 | } 33 | } 34 | } 35 | int ans = result[n - 1][0]; 36 | for (int j = 1; j < m; j++) { 37 | if (ans > result[n - 1][j]) 38 | ans = result[n - 1][j]; 39 | } 40 | return ans + n; 41 | } 42 | } 43 | ``` 44 | **复杂度分析** 45 | 平均时间复杂度:O(n*n*n) 46 | 空间复杂度:O(n) 47 | 48 | **参考资料** 49 | [https://www.cnblogs.com/kexinxin/p/10372522.html](https://www.cnblogs.com/kexinxin/p/10372522.html) -------------------------------------------------------------------------------- /solutions/leetcode/514-FreedomTrail/official.md: -------------------------------------------------------------------------------- 1 | **514. 自由之路** 2 | --- 3 | [https://leetcode-cn.com/problems/freedom-trail/](https://leetcode-cn.com/problems/freedom-trail/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/516-LongestPalindromicSubsequence/passself.md: -------------------------------------------------------------------------------- 1 | ##516. 最长回文子序列 2 | 3 | LeetCode 地址 [https://leetcode-cn.com/problems/longest-palindromic-subsequence/](https://leetcode-cn.com/problems/longest-palindromic-subsequence/) 4 | 5 | **解法一 暴力求解:** 6 | 7 | 找到字符串的所有子串,遍历每一个子串以验证它们是否为回文串。一个子串由子串的起点和终点确定,因此对于一个长度为n的字符串,共有n^2个子串。这些子串的平均长度大约是n/2,因此这个解法的时间复杂度是O(n^3)。 8 | 9 | 这样的方式很容易造成超时,比较不可取。 10 | 11 | 12 | **解法二 动态规划** 13 | 14 | 回文字符串的子串也是回文,比如P[i,j](表示以i开始以j结束的子串)是回文字符串,那么dp[i+1,j-1]也是回文字符串。这样最长回文子串就能分解成一系列子问题了。 15 | 16 | 核心思路就是从左开始遍历,然后不断的从原字符串中拿出1到length-1长度的字串,进行判断 17 | 这里用一个二维数组来表示回文字符串的起始位置和结束位置 18 | 19 | 时间复杂度 O(n^2) 20 | 21 | ``` 22 | public static int longestPalindromeSubseq(String s) { 23 | if (s == null || s.length() == 0) { 24 | return 0; 25 | } 26 | int[][] dp = new int[s.length()][s.length()]; 27 | 28 | for (int i = s.length() - 1; i >= 0; --i) { 29 | dp[i][i] = 1; 30 | for (int j = i + 1; j < s.length(); ++j) { 31 | if (s.charAt(j) == s.charAt(i)) { 32 | dp[i][j] = dp[i + 1][j - 1] + 2; 33 | } else { 34 | dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]); 35 | } 36 | } 37 | } 38 | 39 | return dp[0][s.length() - 1]; 40 | } 41 | ``` 42 | 43 | -------------------------------------------------------------------------------- /solutions/leetcode/517-SuperWashingMachines/official.md: -------------------------------------------------------------------------------- 1 | **517. 超级洗衣机** 2 | --- 3 | [https://leetcode-cn.com/problems/super-washing-machines/](https://leetcode-cn.com/problems/super-washing-machines/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/523-ContinuousSubarraySum/official.md: -------------------------------------------------------------------------------- 1 | **523. 连续的子数组和** 2 | --- 3 | [https://leetcode-cn.com/problems/continuous-subarray-sum/](https://leetcode-cn.com/problems/continuous-subarray-sum/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/551-StudentAttendanceRecordI/official.md: -------------------------------------------------------------------------------- 1 | **551. 学生出勤记录 I** 2 | --- 3 | [https://leetcode-cn.com/problems/student-attendance-record-i/](https://leetcode-cn.com/problems/student-attendance-record-i/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/552-StudentAttendanceRecordII/official.md: -------------------------------------------------------------------------------- 1 | **552. 学生出勤记录 II** 2 | --- 3 | [https://leetcode-cn.com/problems/student-attendance-record-ii/](https://leetcode-cn.com/problems/student-attendance-record-ii/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/576-OutOfBoundaryPaths/official.md: -------------------------------------------------------------------------------- 1 | **576. 出界的路径数** 2 | --- 3 | [https://leetcode-cn.com/problems/out-of-boundary-paths/](https://leetcode-cn.com/problems/out-of-boundary-paths/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/583-DeleteOperationForTwoStrings/README.md: -------------------------------------------------------------------------------- 1 | **583. 两个字符串的删除操作** 2 | --- 3 | [https://leetcode-cn.com/problems/delete-operation-for-two-strings/](https://leetcode-cn.com/problems/delete-operation-for-two-strings/) 4 | 5 | 给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。 6 | 7 | **示例 1:** 8 | 9 | ``` 10 | 输入: "sea", "eat" 11 | 输出: 2 12 | 解释: 第一步将"sea"变为"ea",第二步将"eat"变为"ea" 13 | ``` 14 | 15 | **说明:** 16 | 17 | * 给定单词的长度不超过500 18 | * 给定单词中的字符只含有小写字母 19 | -------------------------------------------------------------------------------- /solutions/leetcode/629-KInversePairsArray/official.md: -------------------------------------------------------------------------------- 1 | **629. K个逆序对数组** 2 | --- 3 | [https://leetcode-cn.com/problems/k-inverse-pairs-array/](https://leetcode-cn.com/problems/k-inverse-pairs-array/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/646-MaximumLengthOfPairChain/official.md: -------------------------------------------------------------------------------- 1 | **646. 最长数对链** 2 | --- 3 | [https://leetcode-cn.com/problems/maximum-length-of-pair-chain/](https://leetcode-cn.com/problems/maximum-length-of-pair-chain/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/647-PalindromicSubstrings/official.md: -------------------------------------------------------------------------------- 1 | **647. 回文子串** 2 | --- 3 | [https://leetcode-cn.com/problems/palindromic-substrings/](https://leetcode-cn.com/problems/palindromic-substrings/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/650-2KeysKeyboard/mahone.md: -------------------------------------------------------------------------------- 1 | **650. 只有两个键的键盘** 2 | --- 3 | [https://leetcode-cn.com/problems/2-keys-keyboard/](https://leetcode-cn.com/problems/2-keys-keyboard/) 4 | 5 | 6 | 解决方案 7 | **思路** 8 | 思路1: 将n分解为m个数字的乘积并且m个数字的和最小,即把一个数分解为n个质数的和 9 | 10 | ``` 11 | public int minStep(int n){ 12 | int result = 0; 13 | int d = 2; 14 | while (n >1){ 15 | //继续将剩下的进行分解 16 | while (n % d == 0 ){ 17 | //加上次数 18 | result += d; 19 | //计算剩下的n 20 | n =n / d; 21 | } 22 | d++; 23 | } 24 | return result; 25 | } 26 | ``` 27 | 28 | **复杂度分析** 29 | 时间复杂度:O(√n),当n是素数平方时,我们的循环耗时O(√n) 30 | 空间复杂度:O(1),空间只使用了result和d 31 | 32 | **参考资料** 33 | * 本题leetCode英文官方题解: 34 | [https://leetcode.com/problems/2-keys-keyboard/solution/](https://leetcode.com/problems/2-keys-keyboard/solution/) -------------------------------------------------------------------------------- /solutions/leetcode/650-2KeysKeyboard/official.md: -------------------------------------------------------------------------------- 1 | **650. 只有两个键的键盘** 2 | --- 3 | [https://leetcode-cn.com/problems/2-keys-keyboard/](https://leetcode-cn.com/problems/2-keys-keyboard/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/664-StrangePrinter/official.md: -------------------------------------------------------------------------------- 1 | **664. 奇怪的打印机** 2 | --- 3 | [https://leetcode-cn.com/problems/strange-printer/](https://leetcode-cn.com/problems/strange-printer/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/673-NumberOfLongestIncreasingSubsequence/README.md: -------------------------------------------------------------------------------- 1 | **673. 最长递增子序列的个数** 2 | --- 3 | [https://leetcode-cn.com/problems/number-of-longest-increasing-subsequence/](https://leetcode-cn.com/problems/number-of-longest-increasing-subsequence/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/684-RedundantConnection/README.md: -------------------------------------------------------------------------------- 1 | **684. 冗余连接** 2 | --- 3 | [https://leetcode-cn.com/problems/redundant-connection/](https://leetcode-cn.com/problems/redundant-connection/) 4 | 5 | 在本问题中, 树指的是一个连通且无环的无向图。 6 | 7 | 输入一个图,该图由一个有着N个节点 (节点值不重复1, 2, ..., N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边。 8 | 9 | 结果图是一个以边组成的二维数组。每一个边的元素是一对[u, v] ,满足 u < v,表示连接顶点u 和v的无向图的边。 10 | 11 | 返回一条可以删去的边,使得结果图是一个有着N个节点的树。如果有多个答案,则返回二维数组中最后出现的边。答案边 [u, v] 应满足相同的格式 u < v。 12 | 13 | **示例 1:** 14 | 15 | ``` 16 | 输入: [[1,2], [1,3], [2,3]] 17 | 输出: [2,3] 18 | 解释: 给定的无向图为: 19 | 1 20 | / \ 21 | 2 - 3 22 | ``` 23 | 24 | **示例 2:** 25 | 26 | ``` 27 | 输入: [[1,2], [2,3], [3,4], [1,4], [1,5]] 28 | 输出: [1,4] 29 | 解释: 给定的无向图为: 30 | 5 - 1 - 2 31 | | | 32 | 4 - 3 33 | ``` 34 | 35 | **注意:** 36 | 37 | * 输入的二维数组大小在 3 到 1000。 38 | * 二维数组中的整数在1到N之间,其中N是输入数组的大小。 39 | 40 | **更新(2017-09-26):** 41 | LeetCode已经重新检查了问题描述及测试用例,明确图是**无向图**。 42 | 对于有向图详见[冗余连接II](https://leetcode-cn.com/problems/redundant-connection-ii/) 43 | 44 | -------------------------------------------------------------------------------- /solutions/leetcode/689-MaximumSumOf3Non-OverlappingSubarrays/official.md: -------------------------------------------------------------------------------- 1 | **689. 三个无重叠子数组的最大和** 2 | --- 3 | [https://leetcode-cn.com/problems/maximum-sum-of-3-non-overlapping-subarrays/](https://leetcode-cn.com/problems/maximum-sum-of-3-non-overlapping-subarrays/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/691-StickersToSpellWord/official.md: -------------------------------------------------------------------------------- 1 | **691. 贴纸拼词** 2 | --- 3 | [https://leetcode-cn.com/problems/stickers-to-spell-word/](https://leetcode-cn.com/problems/stickers-to-spell-word/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/695-MaxAreaOfIsland/README.md: -------------------------------------------------------------------------------- 1 | **695. 岛屿的最大面积** 2 | --- 3 | [https://leetcode-cn.com/problems/max-area-of-island/](https://leetcode-cn.com/problems/max-area-of-island/) 4 | 5 | 给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合。你可以假设二维矩阵的四个边缘都被水包围着。 6 | 7 | 找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为0。) 8 | 9 | **示例 1:** 10 | 11 | ``` 12 | [[0,0,1,0,0,0,0,1,0,0,0,0,0], 13 | [0,0,0,0,0,0,0,1,1,1,0,0,0], 14 | [0,1,1,0,1,0,0,0,0,0,0,0,0], 15 | [0,1,0,0,1,1,0,0,1,0,1,0,0], 16 | [0,1,0,0,1,1,0,0,1,1,1,0,0], 17 | [0,0,0,0,0,0,0,0,0,0,1,0,0], 18 | [0,0,0,0,0,0,0,1,1,1,0,0,0], 19 | [0,0,0,0,0,0,0,1,1,0,0,0,0]] 20 | ``` 21 | 22 | 对于上面这个给定矩阵应返回 6。注意答案不应该是11,因为岛屿只能包含水平或垂直的四个方向的‘1’。 23 | 24 | **示例 2:** 25 | 26 | ``` 27 | [[0,0,0,0,0,0,0,0]] 28 | ``` 29 | -------------------------------------------------------------------------------- /solutions/leetcode/698-PartitionToKEqualSumSubsets/official.md: -------------------------------------------------------------------------------- 1 | **698. 划分为k个相等的子集** 2 | --- 3 | [https://leetcode-cn.com/problems/partition-to-k-equal-sum-subsets/](https://leetcode-cn.com/problems/partition-to-k-equal-sum-subsets/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/703-KthLargestElementInAStream/BambooYH.md: -------------------------------------------------------------------------------- 1 | **703. 数据流中的第K大元素** 2 | --- 3 | [https://leetcode.com/problems/kth-largest-element-in-a-stream/](https://leetcode.com/problems/kth-largest-element-in-a-stream/) 4 | **解决方案** 5 | 方法一:**堆** 6 | **思路** 7 | 这个题跟其他两题有点类似,一个是找给定数组中的第K大元素,一个是找数据流的中位数。我们分别讨论一下: 8 | 数组中的第K大元素,这个我们一般用快排来找,因为首先数组元素的个数是固定的,而快排每趟都能确定一个数的最终位置,所以在给数组排序的过程中,就可以找到第K大的数。 9 | 数据流中的第K大元素,因为是数据流,所以数据的个数是不固定的,这时候用快排就不合适了,因为最坏的情况下,第K大的元素一直在变,每次都需要重新排序。而且占用的空间也越来越大,这时候的空间复杂度和时间复杂度都是不能接受的。所以用最小堆是最合适的,我们只要保证最小堆的大小是K,那么堆顶的元素,肯定就是第K大的元素。同理可以用最大堆来找第K小元素 10 | 数据流的中位数,这个题跟上一个还不一样,不但数据个数是不固定的,找的“第K大元素”也一直在变化。但因为每次找的都是中位数,所以我们可以用两个堆来实现,一个最大堆,一个最小堆。用两个堆来“平分”数据流 11 | **算法** 12 | 创建一个最小堆,在将数据加入堆的过程中,如果待加入元素大于堆顶元素,则弹出堆顶元素,将待加入元素放入堆中,保证堆的大小是K,这样堆顶的元素就是我们要找的第K大的元素 13 | ``` 14 | class KthLargest { 15 | //优先队列是用堆实现的 16 | final PriorityQueue q; 17 | final int k; 18 | 19 | public KthLargest(int k, int[] a) { 20 | //初始化k和优先队列 21 | this.k = k; 22 | q = new PriorityQueue<>(k); 23 | for (int n : a) 24 | add(n); 25 | } 26 | 27 | public int add(int n) { 28 | //如果当前堆的元素个数小于K,则直接放入 29 | if (q.size() < k) 30 | q.offer(n); 31 | //如果待加入元素n大于堆顶元素,则弹出堆顶元素,将n放入堆中 32 | else if (q.peek() < n) { 33 | q.poll(); 34 | q.offer(n); 35 | } 36 | //返回堆顶元素 37 | return q.peek(); 38 | } 39 | } 40 | ``` 41 | **复杂度分析** 42 | 空间复杂度:O(K) 43 | 时间复杂度:O(n),n为数据流的长度 44 | 45 | **参考资料** 46 | leetCode Discuss 47 | [https://leetcode.com/problems/kth-largest-element-in-a-stream/discuss/149050/Java-Priority-Queue](https://leetcode.com/problems/kth-largest-element-in-a-stream/discuss/149050/Java-Priority-Queue) 48 | -------------------------------------------------------------------------------- /solutions/leetcode/712-MinimumASCIIDeleteSumforTwoStrings/official.md: -------------------------------------------------------------------------------- 1 | **712. 两个字符串的最小ASCII删除和** 2 | --- 3 | [https://leetcode-cn.com/problems/minimum-ascii-delete-sum-for-two-strings/](https://leetcode-cn.com/problems/minimum-ascii-delete-sum-for-two-strings/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/714-BestTimeToBuyAndSellStockWithTransactionFee/official.md: -------------------------------------------------------------------------------- 1 | **714. 买卖股票的最佳时机含手续费** 2 | --- 3 | [https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/718-MaximumLengthOfRepeatedSubarray/mahone.md: -------------------------------------------------------------------------------- 1 | **718. 最长重复子数组** 2 | --- 3 | [https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/](https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/) 4 | 5 | 解决方案 6 | **思路** 7 | 思路1: 我们通过动态规划(dp)的方式来解决这种问题,动态规划的问题多数有重叠子问题这个特点,为减少计算,对每一个字问题,只解一次,将不同阶段的不同状态保存在一个二位数组中。 8 | 9 | ``` 10 | public int findLength(int n) { 11 | int aLength = A.length; 12 | int bLength = B.length; 13 | //定义一个二维数组,如果dp[i][j],则A数组中的第i个取值和B中的第j个值一定相等 14 | int[][] dp = new int[aLength + 1][bLength + 1]; 15 | int result = 0; 16 | //循环比对值,并个二维数组赋值 17 | for (int i = 1; i < dp.length; i++) { 18 | for (int j = 1; j < dp[i].length; j++) { 19 | dp[i][j] = A[i - 1] == B[j - 1] ? dp[i - 1][j - 1] + 1 : 0; 20 | //这个取最大的值即代表最大重复的子数组大小 21 | result = Math.max(result, dp[i][j]); 22 | } 23 | } 24 | return result; 25 | } 26 | ``` 27 | 28 | **复杂度分析** 29 | 时间复杂度:O(N) 循环所有数组元素,由于两层循环,每次查找花费O(1)时间,所以最后复杂度为O(M*N),M,N分别是A,B数组的大小 30 | 空间复杂度:O(M*N),空间使用dp 31 | 32 | 33 | **参考资料** 34 | * 本题leetCode英文官方题解: 35 | [https://leetcode.com/articles/maximum-length-of-repeated-subarray/](https://leetcode.com/articles/maximum-length-of-repeated-subarray/) -------------------------------------------------------------------------------- /solutions/leetcode/718-MaximumLengthOfRepeatedSubarray/official.md: -------------------------------------------------------------------------------- 1 | **718. 最长重复子数组** 2 | --- 3 | [https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/](https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/730-CountDifferentPalindromicSubsequences/official.md: -------------------------------------------------------------------------------- 1 | **730. 统计不同回文子字符串** 2 | --- 3 | [https://leetcode-cn.com/problems/count-different-palindromic-subsequences/](https://leetcode-cn.com/problems/count-different-palindromic-subsequences/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/740-DeleteAndEarn/official.md: -------------------------------------------------------------------------------- 1 | **740. 删除与获得点数** 2 | --- 3 | [https://leetcode-cn.com/problems/delete-and-earn/](https://leetcode-cn.com/problems/delete-and-earn/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/746-minCostClimbingStairs/official.md: -------------------------------------------------------------------------------- 1 | **746. 使用最小花费爬楼梯** 2 | --- 3 | [https://leetcode-cn.com/problems/min-cost-climbing-stairs/](https://leetcode-cn.com/problems/min-cost-climbing-stairs/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/764-LargestPlusSign/official.md: -------------------------------------------------------------------------------- 1 | **764. 最大加号标志** 2 | --- 3 | [https://leetcode-cn.com/problems/largest-plus-sign/](https://leetcode-cn.com/problems/largest-plus-sign/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/785-IsGraphBipartite/README.md: -------------------------------------------------------------------------------- 1 | **785. 判断二分图** 2 | --- 3 | [https://leetcode-cn.com/problems/is-graph-bipartite/](https://leetcode-cn.com/problems/is-graph-bipartite/) 4 | 5 | 给定一个无向图graph,当这个图为二分图时返回true。 6 | 7 | 如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图。 8 | 9 | graph将会以邻接表方式给出,graph[i]表示图中与节点i相连的所有节点。每个节点都是一个在0到graph.length-1之间的整数。这图中没有自环和平行边: graph[i] 中不存在i,并且graph[i]中没有重复的值。 10 | 11 | ``` 12 | 示例 1: 13 | 输入: [[1,3], [0,2], [1,3], [0,2]] 14 | 输出: true 15 | 解释: 16 | 无向图如下: 17 | 0----1 18 | | | 19 | | | 20 | 3----2 21 | 我们可以将节点分成两组: {0, 2} 和 {1, 3}。 22 | ``` 23 | 24 | ``` 25 | 示例 2: 26 | 输入: [[1,2,3], [0,2], [0,1,3], [0,2]] 27 | 输出: false 28 | 解释: 29 | 无向图如下: 30 | 0----1 31 | | \ | 32 | | \ | 33 | 3----2 34 | 我们不能将节点分割成两个独立的子集。 35 | ``` 36 | 37 | **注意:** 38 | 39 | * graph 的长度范围为 [1, 100]。 40 | * graph[i] 中的元素的范围为 [0, graph.length - 1]。 41 | * graph[i] 不会包含 i 或者有重复的值。 42 | * 图是无向的: 如果j 在 graph[i]里边, 那么 i 也会在 graph[j]里边。 43 | -------------------------------------------------------------------------------- /solutions/leetcode/787-CheapestFlightsWithinKStops/official.md: -------------------------------------------------------------------------------- 1 | **787. K 站中转内最便宜的航班** 2 | --- 3 | [https://leetcode-cn.com/problems/cheapest-flights-within-k-stops/](https://leetcode-cn.com/problems/cheapest-flights-within-k-stops/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/790-DominoAndTrominoTiling/mahone.md: -------------------------------------------------------------------------------- 1 | **790. 多米诺和托米诺平铺** 2 | --- 3 | [https://leetcode-cn.com/problems/domino-and-tromino-tiling/](https://leetcode-cn.com/problems/domino-and-tromino-tiling/](https://leetcode-cn.com/problems/domino-and-tromino-tiling/) 4 | 5 | 解决方案 6 | **思路** 7 | 思路1:此道题目根据相关数据来推到结论,得到计算每一个的公式,在根据公式来计算相应的结果。 8 | 公式推到如下: 9 | dp[n]=dp[n-1]+dp[n-2]+ 2*(dp[n-3]+...+d[0]) 10 | =dp[n-1]+dp[n-2]+dp[n-3]+dp[n-3]+2*(dp[n-4]+...+d[0]) 11 | =dp[n-1]+dp[n-3]+(dp[n-2]+dp[n-3]+2*(dp[n-4]+...+d[0])) 12 | =dp[n-1]+dp[n-3]+dp[n-1] 13 | =2*dp[n-1]+dp[n-3] 14 | 15 | ``` 16 | public int numTilings(int N){ 17 | //result: dp[i] = 2*dp[i-1] + dp[i-3]; 18 | int md = 1000000007; 19 | //map to save value 20 | Map valueMap = new HashMap<>(1001); 21 | valueMap.put(1,1L); 22 | valueMap.put(2,2L); 23 | valueMap.put(3,5L); 24 | if (N <=3){ 25 | return valueMap.get(N).intValue(); 26 | } 27 | for (int i = 4; i <= N;++i) { 28 | //根据来计算值 29 | Long tmp = 2 * valueMap.get(i - 1) + valueMap.get(i - 3); 30 | //取余 31 | Long value = tmp % md; 32 | valueMap.put(i,Long.valueOf(value)); 33 | } 34 | return valueMap.get(N).intValue(); 35 | } 36 | ``` 37 | 38 | **复杂度分析** 39 | 时间复杂度:O(N) ,由于计算N的值需要得到之前的数据,因此循环计算,时间复杂度位o(N) 40 | 空间复杂度:O(M*N),空间使用dp 41 | 42 | 43 | **参考资料** 44 | [https://leetcode.com/problems/domino-and-tromino-tiling/discuss/116581/Detail-and-explanation-of-O(n)-solution-why-dpn2*dn-1%2Bdpn-3](https://leetcode.com/problems/domino-and-tromino-tiling/discuss/116581/Detail-and-explanation-of-O(n)-solution-why-dpn2*dn-1%2Bdpn-3) -------------------------------------------------------------------------------- /solutions/leetcode/790-DominoAndTrominoTiling/official.md: -------------------------------------------------------------------------------- 1 | **790. 多米诺和托米诺平铺** 2 | --- 3 | [https://leetcode-cn.com/problems/domino-and-tromino-tiling/](https://leetcode-cn.com/problems/domino-and-tromino-tiling/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/801-MinimumSwapsToMakeSequencesIncreasing/official.md: -------------------------------------------------------------------------------- 1 | **801. 使序列递增的最小交换次数** 2 | --- 3 | [https://leetcode-cn.com/problems/minimum-swaps-to-make-sequences-increasing/](https://leetcode-cn.com/problems/minimum-swaps-to-make-sequences-increasing/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/808-SoupServings/official.md: -------------------------------------------------------------------------------- 1 | **808. 分汤** 2 | --- 3 | [https://leetcode-cn.com/problems/soup-servings/](https://leetcode-cn.com/problems/soup-servings/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/813-LargestSumOfAverages/official.md: -------------------------------------------------------------------------------- 1 | **813. 最大平均值和的分组** 2 | --- 3 | [https://leetcode-cn.com/problems/largest-sum-of-averages/](https://leetcode-cn.com/problems/largest-sum-of-averages/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/837-New21Game/official.md: -------------------------------------------------------------------------------- 1 | **837. 新21点** 2 | --- 3 | [https://leetcode-cn.com/problems/new-21-game/](https://leetcode-cn.com/problems/new-21-game/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/838-PushDominoes/official.md: -------------------------------------------------------------------------------- 1 | **838. 推多米诺** 2 | --- 3 | [https://leetcode-cn.com/problems/push-dominoes/](https://leetcode-cn.com/problems/push-dominoes/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/847-ShortestPathVisitingAllNodes/official.md: -------------------------------------------------------------------------------- 1 | **847. 访问所有节点的最短路径** 2 | --- 3 | [https://leetcode-cn.com/problems/shortest-path-visiting-all-nodes/](https://leetcode-cn.com/problems/shortest-path-visiting-all-nodes/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/860-lemonadeChange/BambooYH.md: -------------------------------------------------------------------------------- 1 | **柠檬水找零** 2 | --- 3 | [https://leetcode.com/problems/lemonade-change/](https://leetcode.com/problems/lemonade-change/) 4 | 解决方案: 5 | 方法一:**贪心** 6 | **思路** 7 | 总共有5、10、20三种纸币,如果给的是5元,不用找零。如果给的是10元,肯定要找5元。关键给的是20元,如何找零。我们应该尽量找一张10元和一张5元,这种方法永远比找三张5元的要好。20元不会用于找零。 8 | 9 | **算法** 10 | 我们用两个变量来分别记录5、10纸币的数量。然后根据上面所说规则进行找零。 11 | ``` 12 | class Solution { 13 | public boolean lemonadeChange(int[] bills) { 14 | //res[0]记录5元纸币的数量,res[1]记录10元纸币的数量,20元的不用记录,因为不会用来找零 15 | int[] res = new int[2]; 16 | for(int i = 0; i < bills.length; i++) { 17 | //如果付的是5元,不用找零 18 | if(bills[i] == 5) { 19 | res[0]++; 20 | //如果付的是10元,找5元 21 | }else if(bills[i] == 10) { 22 | if(res[0] == 0) { 23 | return false; 24 | } 25 | res[0]--; 26 | res[1]++; 27 | //如果付的是20元,尽量找一张10元和一张3元,如果没有的话,在找三张5元。 28 | }else if(bills[i] == 20) { 29 | if(res[1] >= 1 && res[0] >= 1) { 30 | res[1]--; 31 | res[0]--; 32 | }else if(res[1] == 0 && res[0]>= 3) { 33 | res[0] -= 3; 34 | }else { 35 | return false; 36 | } 37 | } 38 | } 39 | return true; 40 | } 41 | } 42 | ``` 43 | 复杂度分析: 44 | 假设数组长度为n 45 | 时间复杂度:O(n) 46 | 空间复杂度:O(1) -------------------------------------------------------------------------------- /solutions/leetcode/860-lemonadeChange/official.md: -------------------------------------------------------------------------------- 1 | **860. 柠檬水找零** 2 | --- 3 | [https://leetcode-cn.com/problems/lemonade-change/](https://leetcode-cn.com/problems/lemonade-change/) 4 | 5 | -------------------------------------------------------------------------------- /solutions/leetcode/873-LengthOfLongestFibonacciSubsequence/official.md: -------------------------------------------------------------------------------- 1 | **873. 最长的斐波那契子序列的长度** 2 | --- 3 | [https://leetcode-cn.com/problems/length-of-longest-fibonacci-subsequence/](https://leetcode-cn.com/problems/length-of-longest-fibonacci-subsequence/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/874-walkingRobotSimulation/official.md: -------------------------------------------------------------------------------- 1 | **874. 模拟行走机器人** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/walking-robot-simulation/](https://leetcode-cn.com/problems/walking-robot-simulation/) 5 | -------------------------------------------------------------------------------- /solutions/leetcode/875-KokoEatingBananas/sandao.md: -------------------------------------------------------------------------------- 1 | ## **875. Koko吃香蕉** 2 | 3 | https://leetcode.com/problems/koko-eating-bananas/ 4 | 5 | 解决方案 6 | **思路** 7 | 8 | 假设piles为[A,B,C,D....],最终求出来的值为K,我们可以得出下列公式: 9 | $$ 10 | Math.ceil({A \over K})+Math.ceil({B \over K})+Math.ceil({C \over K})+...<=H 11 | $$ 12 | 可以简略为 13 | $$ 14 | {A \over K}+{B \over K}+{C \over K}+...<=H 15 | $$ 16 | 此时我们能大致得出K=(A+B+C+……)/H 17 | 18 | 此时的出来的K应该是小于我们的最终值的,递增套入公式,求出消耗时间小于H的K的最大值 19 | 20 | ```java 21 | public static int minEatingSpeed(int[] piles, int H) { 22 | //step1:求出相近值 23 | double sum = 0; 24 | for (int i: piles){ 25 | sum += (double)i/H; 26 | } 27 | int k = (int)sum; 28 | //step2:从相似值开始往上找,套入公式 29 | for (;;k++){ 30 | int h = 0; 31 | for (int i: piles){ 32 | double s = Math.ceil((double)i/k); 33 | h += s; 34 | } 35 | //求出了当前情况下需要消耗的时间h,这个时间必须小于规定的H 36 | if (h <= H ){ 37 | return k; 38 | } 39 | } 40 | } 41 | ``` 42 | 43 | **参考资料** 44 | 45 | 无 -------------------------------------------------------------------------------- /solutions/leetcode/877-stoneGame/official.md: -------------------------------------------------------------------------------- 1 | **877. 石子游戏** 2 | --- 3 | [https://leetcode-cn.com/problems/stone-game/](https://leetcode-cn.com/problems/stone-game/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/898-BitwiseORsOfSubarrays/official.md: -------------------------------------------------------------------------------- 1 | **898. 子数组按位或操作** 2 | --- 3 | [https://leetcode-cn.com/problems/bitwise-ors-of-subarrays/](https://leetcode-cn.com/problems/bitwise-ors-of-subarrays/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/903-ValidPermutationsForDISequence/official.md: -------------------------------------------------------------------------------- 1 | **903. DI 序列的有效排列** 2 | --- 3 | [https://leetcode-cn.com/problems/valid-permutations-for-di-sequence/](https://leetcode-cn.com/problems/valid-permutations-for-di-sequence/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/903-ValidPermutationsForDISequence/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | ![903. DI 序列的有效排列](https://leetcode-cn.com/problems/valid-permutations-for-di-sequence/) 2 | 3 | 我们给出 S,一个源于 {'D', 'I'} 的长度为 n 的字符串 。(这些字母代表 “减少” 和 “增加”。) 4 | 有效排列 是对整数 {0, 1, ..., n} 的一个排列 P[0], P[1], ..., P[n],使得对所有的 i: 5 | 6 | 如果 S[i] == 'D',那么 P[i] > P[i+1],以及; 7 | 如果 S[i] == 'I',那么 P[i] < P[i+1]。 8 | 有多少个有效排列?因为答案可能很大,所以请返回你的答案模 10^9 + 7. 9 | 10 | 11 | 12 | 示例: 13 | 14 | 输入:"DID" 15 | 输出:5 16 | 解释: 17 | (0, 1, 2, 3) 的五个有效排列是: 18 | (1, 0, 3, 2) 19 | (2, 0, 3, 1) 20 | (2, 1, 3, 0) 21 | (3, 0, 2, 1) 22 | (3, 1, 2, 0) 23 | 24 | 思路: 25 | 26 | 为了能进行状态转移,定义dp[i][j]表示:使用1-i这些数字的情况下,以j结尾的合理数组个数,计算dp[i][j]的过程如下: 27 | 28 | 1. 如果s[i-2]=='D',说明第i-1位的数要比j大,第i-1位的数据范围是[j+1,i],j在第i位上,所以就把大于等于j的数都往左shift一位(这样2者是等价的,满足A一 29 | 定满足B,满足B一定满足A),这样前i-1位就又是连续的[1,i-1],就可以继续用DP数组的含义。具体到代码就是,k的范围是range(j,i),而不是range(j+1,i) 30 | 31 | 2. 如果s[i-2]=='I',数字i不在前i-1位,不用shift 32 | 33 | ```py 34 | class Solution: 35 | def numPermsDISequence(self, S): 36 | mod = 10**9 + 7 37 | n = len(S)+1 #n设置为字符数列长度加1 38 | dp = [[0 for _ in range(n+1)] for _ in range(n+1)] #设置状态定义 39 | dp[1][1]=1 40 | for i in range(2,n+1): 41 | for j in range(1,i+1): 42 | if S[i-2] == 'D': #对于D来说 43 | for k in range(j,i): #列出状态转移方程 44 | dp[i][j]+=dp[i-1][k] 45 | dp[i][j]%=mod #得到最后结果 46 | else: #对于I来说 47 | for k in range(1,j): 48 | dp[i][j]+=dp[i-1][k] #同样的操作 49 | dp[i][j]%=mod 50 | return sum(dp[n])%mod 51 | ``` 52 | 时间复杂度:显然是O(N^3) 53 | 54 | 空间复杂度:O(n) 55 | 56 | 57 | ![参考](https://blog.csdn.net/zjucor/article/details/82557070) 58 | -------------------------------------------------------------------------------- /solutions/leetcode/920-NumberOfMusicPlaylists/passself.md: -------------------------------------------------------------------------------- 1 | #920. 播放列表的数量 2 | 3 | Leetcode 地址 [https://leetcode-cn.com/problems/number-of-music-playlists/](https://leetcode-cn.com/problems/number-of-music-playlists/) 4 | 5 | **题目分析** 6 | 7 | 你的音乐播放器里有 N 首不同的歌,在旅途中,你的旅伴想要听 L 首歌(不一定不同,即,允许歌曲重复)。请你为她按如下规则创建一个播放列表,dp的方式[参考](https://blog.csdn.net/qq_17550379/article/details/82992083)。 8 | 9 | **思路:** 10 | 11 | 可以暴力枚举所有集合,然后对这些集合中相同元素的位置比较,如果 K){ 36 | dp[i][j] = (dp[i][j] + (dp[i-1][j] * (j-K))%mod)%mod; 37 | } 38 | } 39 | } 40 | return (int)dp[L][N]; 41 | } 42 | } 43 | ``` 44 | **时间复杂度** O(L*N) 45 | 46 | **空间复杂度** O(L*N) 47 | 48 | 49 | -------------------------------------------------------------------------------- /solutions/leetcode/931-MinimumFallingPathSum/hatrick.md: -------------------------------------------------------------------------------- 1 | **931. 下降路径最小和** 2 | --- 3 | [https://leetcode-cn.com/problems/minimum-falling-path-sum/](https://leetcode-cn.com/problems/minimum-falling-path-sum/) 4 | 5 | 解决方案 6 | **思路** 7 | 开二维数组,存第一行的所有数,从第二行开始,找每个位置能从上一行哪些位置下降过来,将其中的最小值赋值就可以了。其实就是上面的图,将指向反过来看就可以了: 8 | 那么除了两端的特殊情况,其他都是能从3个位置下降过来,有状态转移方程: 9 | dp[i][j] = A[i][j] + Min(dp[i-1][j-1],dp[i-1][j],dp[i-1][j+1]) 10 | 注意判定最左边和最右边两种情况就行了。另外,竟然破天荒给了数据范围,当n = 1的时候只有一个下降数组就是本身,这个判定一下就行。 11 | 最终答案要for循环遍历一下最下面一层,看最小值是多少。最小值就是答案。 12 | 13 | ``` 14 | class Solution { 15 | public static int[][] dp; 16 | 17 | public static int Min(int a,int b){ 18 | return a < b ? a : b; 19 | } 20 | 21 | public int minFallingPathSum(int[][] A) { 22 | int len = A[0].length; 23 | if(len == 1) return A[0][0]; 24 | dp = new int[len][len]; 25 | for(int i = 0;i < len;i++){ 26 | dp[0][i] = A[0][i]; 27 | } 28 | for(int i = 1;i < len;i++){ 29 | for(int j = 0;j < len;j++){ 30 | if(j == 0){ 31 | dp[i][j] = A[i][j] + Min(dp[i-1][j],dp[i-1][j+1]); 32 | }else{ 33 | if(j == len-1){ 34 | dp[i][j] = A[i][j] + Min(dp[i-1][j],dp[i-1][j-1]); 35 | }else{ 36 | dp[i][j] = A[i][j] + Min(Min(dp[i-1][j],dp[i-1][j+1]),dp[i-1][j-1]); 37 | } 38 | } 39 | } 40 | } 41 | int ans = 20000; 42 | for(int i = 0;i < len;i++){ 43 | ans = Min(ans,dp[len-1][i]); 44 | } 45 | return ans; 46 | } 47 | } 48 | 49 | ``` 50 | 51 | 52 | **参考资料** 53 | [https://www.itbox.info/p/139142/leetcode-minimum-falling-path-sum](https://www.itbox.info/p/139142/leetcode-minimum-falling-path-sum) -------------------------------------------------------------------------------- /solutions/leetcode/931-MinimumFallingPathSum/official.md: -------------------------------------------------------------------------------- 1 | **931. 下降路径最小和** 2 | --- 3 | [https://leetcode-cn.com/problems/minimum-falling-path-sum/](https://leetcode-cn.com/problems/minimum-falling-path-sum/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/935-KnightDialer/official.md: -------------------------------------------------------------------------------- 1 | **935. 骑士拨号器** 2 | --- 3 | [https://leetcode-cn.com/problems/knight-dialer/](https://leetcode-cn.com/problems/knight-dialer/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/940-DistinctSubsequencesII/official.md: -------------------------------------------------------------------------------- 1 | **940. 不同的子序列 II** 2 | --- 3 | 4 | [https://leetcode-cn.com/problems/distinct-subsequences-ii/](https://leetcode-cn.com/problems/distinct-subsequences-ii/) 5 | -------------------------------------------------------------------------------- /solutions/leetcode/943-FindTheShortestSuperstring/official.md: -------------------------------------------------------------------------------- 1 | **943. 最短超级串** 2 | --- 3 | [https://leetcode-cn.com/problems/find-the-shortest-superstring/](https://leetcode-cn.com/problems/find-the-shortest-superstring/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/956-TallestBillboard/official.md: -------------------------------------------------------------------------------- 1 | **956. 最高的广告牌** 2 | --- 3 | [https://leetcode-cn.com/problems/tallest-billboard/](https://leetcode-cn.com/problems/tallest-billboard/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/964-LeastOperatorsToExpressNumber/official.md: -------------------------------------------------------------------------------- 1 | **964. 表示数字的最少运算符** 2 | --- 3 | [https://leetcode-cn.com/problems/least-operators-to-express-number/](https://leetcode-cn.com/problems/least-operators-to-express-number/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/967-NumbersWithSameConsecutiveDifferences/official.md: -------------------------------------------------------------------------------- 1 | **967. 连续差相同的数字** 2 | --- 3 | [https://leetcode-cn.com/problems/numbers-with-same-consecutive-differences/](https://leetcode-cn.com/problems/numbers-with-same-consecutive-differences/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/968-BinaryTreeCameras/official.md: -------------------------------------------------------------------------------- 1 | **968. 监控二叉树** 2 | --- 3 | [https://leetcode-cn.com/problems/binary-tree-cameras/](https://leetcode-cn.com/problems/binary-tree-cameras/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/968-BinaryTreeCameras/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | **968. Binary Tree Cameras** 2 | 3 | [Binary Tree Cameras](https://leetcode.com/problems/binary-tree-cameras/) 4 | 5 | **思路:** 6 | 7 | 最小点覆盖和最大独立集都比较简单,只有2个状态,分别是标记和不标记 8 | 9 | 对于最小支配集,每个子树3个状态: 10 | 11 | 状态0:根被标记,整个子树都被覆盖的最小标记数目 12 | 13 | 状态1:根未被标记,整个子树被覆盖,且至少有一个子节点被标记 14 | 15 | 状态2:根未被标记,整个子树被覆盖,且没有子节点被标记 16 | 17 | 每个状态如何递归: 18 | 19 | 1.状态0:每个子树的3个状态的最小值之和+1: 20 | 21 | dp[root][0] = min(dp[root.left])+min(dp[root.right])+1 22 | 23 | 2.状态1:【如果根没有孩子,dp[root][1]为INF】根未被标记时子树不可以是状态3。所以是前两个状态取最小值之和。但是如果每个子节点的最小值都是状态1,那么就 24 | 和根是状态1的假设矛盾了。所以要挑一个节点取状态0,这必然会使结果增加,那么选增加得最少的那个,即dp[u][0]-dp[u][1]最小的那个指定为状态0。 25 | 26 | 不可能是状态3是因为如果根没有标记,儿子没有标记,根还被覆盖了,可能是根的父亲标记了,但是如果孙子也没有标记,那么儿子就不可能被标记,矛盾。 27 | 28 | 2.状态2:此时子树只可能是状态1。 29 | 30 | dp[root][2] = dp[root.left][1]+dp[root.right][1] 31 | 32 | 最后取根节点的状态1和状态0里最小的那个 33 | 34 | ```py 35 | class Solution: 36 | def minCameraCover(self, root: TreeNode) -> int: 37 | INF = 0x7fffffff 38 | def solve(root): 39 | if root.left and root.right: 40 | left = solve(root.left) #左右子树递归 41 | right = solve(root.right) 42 | return min(left)+min(right)+1, min(left[0]+min(right[:-1]), min(left[:-1])+right[0]),left[1]+right[1] 43 | res = None 44 | if root.left: #求解满足状态0,1的情况 45 | res = solve(root.left) 46 | elif root.right: 47 | res = solve(root.right) 48 | if res!=None: 49 | return min(res)+1, res[0], res[1] 50 | return 1, INF, 0 51 | return min(solve(root)[:-1]) 52 | ``` 53 | 时间复杂度是O(nlogn) 54 | 55 | [参考](https://blog.csdn.net/lemonmillie/article/details/87825550) 56 | -------------------------------------------------------------------------------- /solutions/leetcode/975-OddEvenJump/official.md: -------------------------------------------------------------------------------- 1 | **975. 奇偶跳** 2 | --- 3 | [https://leetcode-cn.com/problems/odd-even-jump/](https://leetcode-cn.com/problems/odd-even-jump/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/982-TriplesWithBitwiseANDEqualToZero/official.md: -------------------------------------------------------------------------------- 1 | **982. 按位与为零的三元组** 2 | --- 3 | [https://leetcode-cn.com/problems/triples-with-bitwise-and-equal-to-zero/](https://leetcode-cn.com/problems/triples-with-bitwise-and-equal-to-zero/) 4 | -------------------------------------------------------------------------------- /solutions/leetcode/sample/concise.md: -------------------------------------------------------------------------------- 1 | >精简版答案示例,摘自本题的leetCode官方题解 2 | 3 | **141. 环形链表** 4 | --- 5 | [https://leetcode-cn.com/problems/linked-list-cycle/](https://leetcode-cn.com/problems/linked-list-cycle/) 6 | 7 | 方法一:哈希表 8 | ```java 9 | 10 | public boolean hasCycle(ListNode head) { 11 | //新建一个set用于存储从链表中遍历出的结点 12 | Set nodesSeen = new HashSet<>(); 13 | //如果当前结点不为空,循环继续 14 | while (head != null) { 15 | //set中如果已经存在当前结点,说明该链表是环形链表,返回true 16 | if (nodesSeen.contains(head)) { 17 | return true; 18 | } else { 19 | //否则将当前结点添加到set 20 | nodesSeen.add(head); 21 | } 22 | //将下一个结点赋值给结点缓存head 23 | head = head.next; 24 | } 25 | //链表所有结点遍历结束没有在set里找到重复结点,说明当前链表没有环,返回false 26 | return false; 27 | } 28 | 29 | ``` 30 | 31 | --- 32 | 33 | 34 | **参考资料** 35 | 36 | * 本题leetCode官方题解: 37 | [https://leetcode-cn.com/articles/linked-list-cycle/](https://leetcode-cn.com/articles/linked-list-cycle/) 38 | 39 | * 本题leetCode英文官方题解: 40 | [https://leetcode.com/articles/linked-list-cycle/](https://leetcode.com/articles/linked-list-cycle/) -------------------------------------------------------------------------------- /solutions/leetcode/sample/concise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hollischuang/algorithm/05c9121a00f99652ead193a0d9e7d2dadadae397/solutions/leetcode/sample/concise.png -------------------------------------------------------------------------------- /solutions/leetcode/sample/full.md: -------------------------------------------------------------------------------- 1 | >详尽版答案示例,摘自本题的leetCode官方题解 2 | 3 | **141. 环形链表** 4 | --- 5 | [https://leetcode-cn.com/problems/linked-list-cycle/](https://leetcode-cn.com/problems/linked-list-cycle/) 6 | 7 | 摘要 8 | 9 | 本文适用于初学者。 10 | 11 | 它涉及了以下几个概念:链表,哈希表和双指针。 12 | 13 | 解决方案 14 | 15 | 方法一:哈希表 16 | 17 | 思路 18 | 19 | 我们可以通过检查一个结点此前是否被访问过来判断链表是否为环形链表。 20 | 21 | 常用的方法是使用哈希表。 22 | 23 | 算法 24 | 25 | 我们遍历所有结点并在哈希表中存储每个结点的引用(或内存地址)。 26 | 27 | 如果当前结点为空结点 null(即已检测到链表尾部的下一个结点),那么我们已经遍历完整个链表,并且该链表不是环形链表。 28 | 29 | 如果当前结点的引用已经存在于哈希表中,那么返回 true(即该链表为环形链表)。 30 | 31 | 32 | ```java 33 | 34 | public boolean hasCycle(ListNode head) { 35 | //新建一个set用于存储从链表中遍历出的结点 36 | Set nodesSeen = new HashSet<>(); 37 | //如果当前结点不为空,循环继续 38 | while (head != null) { 39 | //set中如果已经存在当前结点,说明该链表是环形链表,返回true 40 | if (nodesSeen.contains(head)) { 41 | return true; 42 | } else { 43 | //否则将当前结点添加到set 44 | nodesSeen.add(head); 45 | } 46 | //将下一个结点赋值给结点缓存head 47 | head = head.next; 48 | } 49 | //链表所有结点遍历结束没有在set里找到重复结点,说明当前链表没有环,返回false 50 | return false; 51 | } 52 | 53 | ``` 54 | 55 | **复杂度分析** 56 | 57 | 时间复杂度: 58 | O(n), 对于含有 n个元素的链表,我们访问每个元素最多一次。 添加一个结点到哈希表中只需要花费 O(1) 的时间。 59 | 60 | 空间复杂度: 61 | O(n), 空间取决于添加到哈希表中的元素数目,最多可以添加 n 个元素。 62 | 63 | --- 64 | 65 | 66 | **参考资料** 67 | 68 | * 本题leetCode官方题解: 69 | [https://leetcode-cn.com/articles/linked-list-cycle/](https://leetcode-cn.com/articles/linked-list-cycle/) 70 | 71 | * 本题leetCode英文官方题解: 72 | [https://leetcode.com/articles/linked-list-cycle/](https://leetcode.com/articles/linked-list-cycle/) -------------------------------------------------------------------------------- /solutions/leetcode/sample/full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hollischuang/algorithm/05c9121a00f99652ead193a0d9e7d2dadadae397/solutions/leetcode/sample/full.png -------------------------------------------------------------------------------- /solutions/剑指Offer/003-数组中重复的数字/README.md: -------------------------------------------------------------------------------- 1 | **3. 数组中重复的数字** 2 | --- 3 | 4 | 在一个长度为n的数组里的所有数字都在0到n-1的范围内。 5 | 数组中某些数字是重复的,但不知道有几个数字是重复的。 6 | 也不知道每个数字重复几次。 7 | 请找出数组中任意一个重复的数字。 8 | 例如, 9 | 如果输入长度为7的数组{2,3,1,0,2,5,3}, 10 | 那么对应的输出是第一个重复的数字2。 11 | 12 | **牛客网链接** 13 | 14 | [https://www.nowcoder.com/practice/623a5ac0ea5b4e5f95552655361ae0a8?tpId=13&tqId=11203&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking](https://www.nowcoder.com/practice/623a5ac0ea5b4e5f95552655361ae0a8?tpId=13&tqId=11203&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) 15 | -------------------------------------------------------------------------------- /solutions/剑指Offer/004-二维数组中的查找/README.md: -------------------------------------------------------------------------------- 1 | **4. 二维数组中的查找** 2 | --- 3 | 4 | 在一个二维数组中(每个一维数组的长度相同), 5 | 每一行都按照从左到右递增的顺序排序, 6 | 每一列都按照从上到下递增的顺序排序。 7 | 请完成一个函数, 8 | 输入这样的一个二维数组和一个整数, 9 | 判断数组中是否含有该整数。 10 | 11 | **牛客网链接** 12 | 13 | [https://www.nowcoder.com/practice/abc3fe2ce8e146608e868a70efebf62e?tpId=13&tqId=11154&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking](https://www.nowcoder.com/practice/abc3fe2ce8e146608e868a70efebf62e?tpId=13&tqId=11154&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) 14 | 15 | -------------------------------------------------------------------------------- /solutions/剑指Offer/004-二维数组中的查找/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | **4.二维数组中的查找** 2 | 3 | 思路: 4 | 5 | 首先选取数组中右上角的数字,如果该数字等于要查找的数字,则查找过程结束;如果数字大于要查找的数字,则剔除这个数字所在的列;如果该数字小于要查找的数字,则 6 | 剔除这个数字所在的行。也就是说,如果要查找的数字不在数组的右上角,则每一次都在数组的查找范围中剔除一行或者一列,这样每一步都可以缩小查找的范围,知道找到 7 | 查找的数字。 8 | 9 | ```py 10 | class Solution: 11 | # array 二维列表 12 | def Find(self, target, array): 13 | if array == []: 14 | return False 15 | num_row = len(array) 16 | num_col = len(array[0]) 17 | 18 | i = num_col - 1 19 | j = 0 20 | while i>=0 and j target: 22 | i-=1 23 | elif array[j][i] < target: 24 | j+=1 25 | else: 26 | return True 27 | ``` 28 | 时间复杂度:O(n^2) 29 | 空间复杂度:O(n) 30 | -------------------------------------------------------------------------------- /solutions/剑指Offer/005-替换空格/README.md: -------------------------------------------------------------------------------- 1 | **5. 替换空格** 2 | --- 3 | 4 | 请实现一个函数,将一个字符串中的每个空格替换成“%20”。 5 | 例如,当字符串为We Are Happy. 6 | 则经过替换之后的字符串为We%20Are%20Happy。 7 | 8 | **牛客网链接** 9 | 10 | [https://www.nowcoder.com/practice/4060ac7e3e404ad1a894ef3e17650423?tpId=13&tqId=11155&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking](https://www.nowcoder.com/practice/4060ac7e3e404ad1a894ef3e17650423?tpId=13&tqId=11155&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) 11 | 12 | -------------------------------------------------------------------------------- /solutions/剑指Offer/005-替换空格/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | **思路:** 2 | 3 | 因为一个空格要替换成三个字符(%20),所以当遍历到一个空格时,需要在尾部填充两个任意字符。令p1指向字符串原来的末尾位置,p2指向字符串现在的末尾位置。 4 | p1和p2从后向前遍历,当p1遍历到一个空格时,就需要令p2指向的位置依次填充02%,否则就填充上p1指向字符的值。 5 | 6 | ```py 7 | class Solution: 8 | def replaceSpace(self, s): 9 | if not isinstance(s,str) or len(s) <= 0 or s == None: 10 | return '' 11 | spaceNum = 0 12 | for i in s: 13 | if i == "": 14 | spaceNum += 1 15 | newStrLen = len(s) + spaceNum*2 16 | newStr = newStrLen*[None] 17 | indexOfOriginal, indexOfNew = len(s) - 1, newStrLen - 1 18 | while indexOfNew >= 0 and indexOfOriginal <= indexOfNew: 19 | if s[indexOfOriginal] == '': 20 | newStr[indexOfNew-2:indexOfNew+1] = ['%','2','0'] 21 | indexOfNew -= 3 22 | indexOfOriginal -= 1 23 | else: 24 | newStr[indexOfNew] = s[indexOfOriginal] 25 | indexOfNew -= 1 26 | indexOfOriginal -= 1 27 | return ''.join(newStr) 28 | 29 | ``` 30 | 时间复杂度:O(n) 31 | 32 | 空间复杂度:O(n) 33 | -------------------------------------------------------------------------------- /solutions/剑指Offer/006-从尾到头打印链表/README.md: -------------------------------------------------------------------------------- 1 | **6. 从尾到头打印链表** 2 | --- 3 | 4 | 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList 5 | 6 | **牛客网链接** 7 | 8 | [https://www.nowcoder.com/practice/d0267f7f55b3412ba93bd35cfa8e8035?tpId=13&tqId=11156&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking](https://www.nowcoder.com/practice/d0267f7f55b3412ba93bd35cfa8e8035?tpId=13&tqId=11156&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) 9 | -------------------------------------------------------------------------------- /solutions/剑指Offer/006-从尾到头打印链表/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | **思路:** 2 | 3 | 使用链表头插法为逆序的特点 4 | 5 | 头结点和第一个结点的区别: 6 | 7 | 头结点是头插法中使用的一个额外结点,这个结点不存储值。 8 | 9 | 第一个节点就是链表的第一个真正存储值得结点。 10 | 11 | 这道题也可以使用递归和栈来解决。 12 | 13 | ```py 14 | class Solution: 15 | # 返回从尾部到头部的列表值序列,例如[1,2,3] 16 | def printListFromTailToHead(self, listNode): 17 | # write code here 18 | if not listNode: 19 | return [] 20 | result = [] 21 | 22 | while listNode: 23 | result.insert(0,listNode.val) 24 | listNode = listNode.next 25 | return result 26 | ``` 27 | -------------------------------------------------------------------------------- /solutions/剑指Offer/007-重建二叉树/README.md: -------------------------------------------------------------------------------- 1 | **7. 重建二叉树** 2 | --- 3 | 4 | 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。 5 | 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 6 | 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}, 7 | 则重建二叉树并返回。 8 | 9 | **牛客网链接** 10 | 11 | [https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=13&tqId=11157&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking](https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=13&tqId=11157&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) 12 | -------------------------------------------------------------------------------- /solutions/剑指Offer/007-重建二叉树/zengdiqing1994.md: -------------------------------------------------------------------------------- 1 | 2 | **7.重建二叉树** 3 | 4 | 思路:我们知道前序遍历的第一个值为根节点的值,使用这个值将中序遍历结果分成两个部分,左部分为树的左子数中序遍历结果,右部分为树的右子树中序遍历的结果 5 | 6 | ```py 7 | class TreeNode: 8 | def __init__(self, x): # 初始化树 9 | self.val = x 10 | self.left = None 11 | self.right = None 12 | class Solution: 13 | # 返回构造的TreeNode根节点 14 | def reConstructBinaryTree(self, pre, tin): 15 | # write code here 16 | if not pre and not tin: 17 | return None 18 | root = TreeNode(pre[0]) # 前序遍历的root 19 | if set(pre) != set(tin): #判断其他情况 20 | return None 21 | i = tin.index(pre[0]) #看前序遍历的root在中序遍历的哪个位置 22 | root.left = self.reConstructBinaryTree(pre[1:i+1],tin[:i]) #开始递归 23 | root.right = self.reConstructBinaryTree(pre[i+1:],tin[i+1:]) 24 | return root 25 | ``` 26 | 时间复杂度O(n^2) 27 | -------------------------------------------------------------------------------- /solutions/剑指Offer/008-二叉树的下一个结点/README.md: -------------------------------------------------------------------------------- 1 | **8. 二叉树的下一个结点** 2 | --- 3 | 4 | 给定一个二叉树和其中的一个结点, 5 | 请找出中序遍历顺序的下一个结点并且返回。 6 | 注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。 7 | 8 | **牛客网链接** 9 | 10 | [https://www.nowcoder.com/practice/9023a0c988684a53960365b889ceaf5e?tpId=13&tqId=11210&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking](https://www.nowcoder.com/practice/9023a0c988684a53960365b889ceaf5e?tpId=13&tqId=11210&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) 11 | -------------------------------------------------------------------------------- /solutions/剑指Offer/009-用两个栈实现队列/README.md: -------------------------------------------------------------------------------- 1 | **9. 用两个栈实现队列** 2 | --- 3 | 4 | 用两个栈来实现一个队列, 5 | 完成队列的Push和Pop操作。 6 | 队列中的元素为int类型。 7 | 8 | **牛客网链接** 9 | 10 | [https://www.nowcoder.com/practice/54275ddae22f475981afa2244dd448c6?tpId=13&tqId=11158&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking](https://www.nowcoder.com/practice/54275ddae22f475981afa2244dd448c6?tpId=13&tqId=11158&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) 11 | -------------------------------------------------------------------------------- /solutions/剑指Offer/README.md: -------------------------------------------------------------------------------- 1 | 《剑指Offer》题解 2 | --- 3 | 4 | ![剑指Offer](http://download.broadview.com.cn/ScreenShow/170410b0ad51bfe7dcdd) 5 | 6 | * 随书代码官方下载地址: 7 | 8 | [http://www.broadview.com.cn/book/18](http://www.broadview.com.cn/book/18) --------------------------------------------------------------------------------