├── .gitignore ├── README.md ├── pom.xml ├── src └── main │ └── java │ └── com │ └── example │ ├── codeinterviewguide │ ├── README.md │ ├── cp2_linkedlist │ │ ├── p01_PrintCommonPart.java │ │ ├── p02_RemoveLastKthNode.java │ │ ├── p03_RemoveNodeByRatio.java │ │ ├── p04_ReverseList.java │ │ ├── p05_ReversePartList.java │ │ ├── p06_JosephusProblem.java │ │ ├── p07_IsPalindromeList.java │ │ ├── p08_SmallerEqualBigger.java │ │ ├── p09_CopyListWithRandom.java │ │ ├── p10_AddTwoLinkedList.java │ │ ├── p11_FindFirstIntersectNode.java │ │ ├── p12_ConvertEveryKNodesInList.java │ │ ├── p13_RemoveRepetition.java │ │ ├── p14_RemoveGivenValue.java │ │ ├── p15_BSTtoDoubleLinkedList.java │ │ ├── p16_ListSelectionSort.java │ │ ├── p17_RemoveNodeWeird.java │ │ ├── p18_InsertNumToCircularList.java │ │ ├── p19_MergeTwoLinkedLists.java │ │ └── p20_RelocateLinkedList.java │ ├── cp3_binarytree │ │ ├── BiggestSubBSTInTree.java │ │ ├── CompleteTreeNodeNumber.java │ │ ├── Node.java │ │ ├── p01_PreInPosTraversal.java │ │ └── p04_SerializeAndReconstructTree.java │ └── cp8_array │ │ └── partition.java │ ├── leetcode │ ├── array │ │ ├── LeetCode036_ValidSuduku.java │ │ ├── LeetCode15_3Sum.java │ │ ├── LeetCode16_3SumClosest.java │ │ ├── LeetCode18_4Sum.java │ │ ├── LeetCode1_TwoSum.java │ │ ├── LeetCode31_NextPermutation.java │ │ ├── LeetCode33_SearchInRotatedSortedArray.java │ │ └── LeetCode4_MedianOfTwoSortedArrays.java │ ├── backtrack │ │ ├── LeetCode017_LetterCombinationsPhoneNumber.java │ │ ├── LeetCode022_GenerateParentheses.java │ │ ├── LeetCode039_CombinationSum.java │ │ ├── LeetCode040_CombinationSum2.java │ │ ├── LeetCode046_Permutations.java │ │ ├── LeetCode047_Permutations2.java │ │ ├── LeetCode051_NQueens.java │ │ ├── LeetCode060_KthPermutation.java │ │ ├── LeetCode077_Combinations.java │ │ ├── LeetCode078_Subsets.java │ │ ├── LeetCode079_SearchWord.java │ │ ├── LeetCode090_Subsets2.java │ │ ├── LeetCode093_RestoreIpAddress.java │ │ ├── LeetCode131_PalindromePartitioning.java │ │ ├── LeetCode200_NumberOfIslands.java │ │ └── LeetCode257_binaryAllPaths.java │ ├── binarysearch │ │ ├── LeetCode004_MedianOfTwoSortedArrays.java │ │ ├── LeetCode033_SearchInRotatedSortedArray.java │ │ ├── LeetCode034_SearchFirstAndLastPosition.java │ │ ├── LeetCode035_SearchInsertPosition.java │ │ ├── LeetCode069_Sqrtx.java │ │ ├── LeetCode153_FindMinInRotatedSortedArray.java │ │ ├── LeetCode154_FindMinInRotatedSortedArray2.java │ │ ├── LeetCode209_MinSizeSubArraySum.java │ │ ├── LeetCode367_ValidPerfectSquare.java │ │ ├── LeetCode374_GuessNumberHighLow.java │ │ ├── LeetCode441_ArrangingCoins.java │ │ ├── LeetCode704_BinarySearch.java │ │ └── LeetCode852_PeakIndexInMountainArray.java │ ├── binarytree │ │ ├── LeetCode095_UniqueBST2.java │ │ ├── LeetCode096_UniqueBST.java │ │ ├── LeetCode099_RecoverBST.java │ │ ├── LeetCode111_MinDepth.java │ │ ├── LeetCode112_PathSum.java │ │ ├── LeetCode114_Flatten.java │ │ ├── LeetCode124_BinaryTreeMaxPath.java │ │ ├── LeetCode199_binaryTreeRightView.java │ │ ├── LeetCode236_LowestCommonAncestorOfBinaryTree.java │ │ ├── LeetCode617_MergeTwoBinaryTrees.java │ │ ├── LeetCode965_UnivaluedBinaryTree.java │ │ └── listOfDepth.java │ ├── design │ │ └── Twitter.java │ ├── dp │ │ ├── Knapsack.java │ │ ├── Knapsack_MaxWeight.java │ │ ├── Knapsack_SplitTwoPartSame.java │ │ ├── LeetCode10_RegularExpressionMatching.java │ │ ├── LeetCode1143_LCS.java │ │ ├── LeetCode120_TriangleMinPath.java │ │ ├── LeetCode121_BestTimeToBuyAndSellStock.java │ │ ├── LeetCode122_BestTimeToBuyAndSellStock2.java │ │ ├── LeetCode123_BestTimeToBuyAndSellStock3.java │ │ ├── LeetCode198_HouseRobber.java │ │ ├── LeetCode213_HouseRobber2.java │ │ ├── LeetCode300_LIS.java │ │ ├── LeetCode322_CoinChange.java │ │ ├── LeetCode329_LongestIncreasePathMatrix.java │ │ ├── LeetCode32_LongestValidParantheses.java │ │ ├── LeetCode337_HouseRobber3.java │ │ ├── LeetCode45_JumpGame2.java │ │ ├── LeetCode474_OnesAndZeros.java │ │ ├── LeetCode53_MaximumSubarray.java │ │ ├── LeetCode55_JumpGame.java │ │ ├── LeetCode62_UniquePaths.java │ │ ├── LeetCode63_UniquePaths2.java │ │ ├── LeetCode64_MinimumPathSum.java │ │ ├── LeetCode651_4KeysKeyboard.java │ │ ├── LeetCode673_NumberOfLIS.java │ │ ├── LeetCode70_ClimbingStairs.java │ │ ├── LeetCode72_EditDistance.java │ │ ├── LeetCode84_LargestRectangleInHistogram.java │ │ ├── LeetCode85_MaximalRectangle.java │ │ ├── LeetCode87_ScrambleString.java │ │ ├── README.md │ │ └── palindrome │ │ │ ├── LeetCode009_isPalindrome.java │ │ │ ├── LeetCode05_LongestPalindromicSubstring.java │ │ │ ├── LeetCode131_PalindromePartitioning.java │ │ │ ├── LeetCode516_LongestPalindromicSubsequence.java │ │ │ └── LeetCode647_PalindromicSubstrings.java │ ├── heap │ │ ├── LeetCode703_ktLargestElementIntream.java │ │ └── package-info.java │ ├── linkedlist │ │ ├── LeetCode02_AddTwoNumbers.java │ │ ├── LeetCode109_ConvertSortedListToBinarySearchTree.java │ │ ├── LeetCode138_CopyListWithRandomPointer.java │ │ ├── LeetCode141_LinkedListCycle.java │ │ ├── LeetCode142_LinkedListCycle2.java │ │ ├── LeetCode143_ReorderList.java │ │ ├── LeetCode147_InsertionSortList.java │ │ ├── LeetCode148_SortList.java │ │ ├── LeetCode160_IntersectionOfTwoLists.java │ │ ├── LeetCode19_RemoveNthNodeFromEnd.java │ │ ├── LeetCode203_RemoveLinkedListElements.java │ │ ├── LeetCode206_ReverseLinkedList.java │ │ ├── LeetCode21_MergeTwoSortedLists.java │ │ ├── LeetCode234_PalindromeLinkedList.java │ │ ├── LeetCode237_DeleteNodeInLinkedList.java │ │ ├── LeetCode23_MergeKSortedLists.java │ │ ├── LeetCode24_SwapNodesInPairs.java │ │ ├── LeetCode328_OddEvenLinkedList.java │ │ ├── LeetCode445_AddTwoNumbers2.java │ │ ├── LeetCode61_RotateList.java │ │ ├── LeetCode725_SplitLinkedListInParts.java │ │ ├── LeetCode82_RemoveDuplicatesFromSortedList2.java │ │ ├── LeetCode83_RemoveDuplicatesFromSortedList.java │ │ ├── LeetCode86_PartitionList.java │ │ ├── LeetCode876_MiddleOfTheLinkedList.java │ │ ├── LeetCode92_ReverseLinkedList2.java │ │ ├── README.md │ │ └── pojo │ │ │ ├── ListNode.java │ │ │ ├── RandomListNode.java │ │ │ └── TreeNode.java │ ├── other │ │ ├── LeetCode006_ZigZagConversion.java │ │ ├── LeetCode007_ReverseInteger.java │ │ ├── LeetCode014_LongestCommonPrefix.java │ │ ├── LeetCode038_CountAndSay.java │ │ ├── LeetCode041_FirstMissingPositive.java │ │ ├── LeetCode042_RainWater.java │ │ ├── LeetCode043_MultiplyStrings.java │ │ ├── LeetCode049_GroupAnagrams.java │ │ ├── LeetCode050_Powx.java │ │ ├── LeetCode054_SpiralMatrix.java │ │ ├── LeetCode059_SpiralMatrix2.java │ │ ├── LeetCode11_ContainerWithMostWater.java │ │ ├── LeetCode202_HappyNumber.java │ │ ├── LeetCode419_LongestPalindrome.java │ │ ├── LeetCode703_KthLargestElementStream.java │ │ └── exchangeNumber.java │ ├── slidingwindow │ │ ├── LeetCode003_LongestSubstringWithouRepeat.java │ │ ├── LeetCode030_SubWithConcatenationWords.java │ │ ├── LeetCode076_MinWindowSubStr.java │ │ ├── LeetCode438_FindAllAnagrams.java │ │ ├── LeetCode480_SlidingWindowMedian.java │ │ └── LeetCode567_PermutationInString.java │ └── sort │ │ ├── Interval.java │ │ ├── LeetCode147_InsertionSortList.java │ │ ├── LeetCode148_SortList.java │ │ ├── LeetCode164_MaximumGap.java │ │ ├── LeetCode179_LargestNumber.java │ │ ├── LeetCode215_KthLargestElementInAnArray.java │ │ ├── LeetCode274_HIndex.java │ │ ├── LeetCode324_WiggleSort2.java │ │ ├── LeetCode349_IntersectionOfTwoArrays.java │ │ ├── LeetCode435_NoOverLapIntervals.java │ │ ├── LeetCode524_LongestWordInDictionaryThroughDeleting.java │ │ ├── LeetCode56_MergeIntervals.java │ │ ├── LeetCode57_InsertInterval.java │ │ ├── LeetCode710_RandomPickWithBlackList.java │ │ ├── LeetCode75_SortColors.java │ │ ├── LeetCode767_ReorganizeString.java │ │ ├── LeetCode922_sortArrayByParity2.java │ │ ├── LeetCode969_PancakeSorting.java │ │ ├── LeetCode973_KClosestPointsToOrigin.java │ │ ├── LeetCode976_LargestTriangle.java │ │ ├── LeetCode986_IntervalIntersections.java │ │ ├── README.md │ │ ├── SortStackByStack.java │ │ └── package-info.java │ ├── summary │ ├── BST.java │ ├── BinaraySearch2.java │ ├── BinarySearch.java │ ├── BinaryTreeTraversal.java │ ├── DP.java │ ├── MonotoneStack.java │ ├── Palindrome.java │ ├── SlidingWindow.java │ ├── linkedlist │ │ ├── ReverseSummary.java │ │ └── SortSummary.java │ ├── lru │ │ ├── LRUCache.java │ │ ├── LRUCacheBeta.java │ │ └── LRULinkedHashMap.java │ └── sortalgorithm │ │ ├── BubbleSort.java │ │ ├── HeapSort.java │ │ ├── HeapSort2.java │ │ ├── InsertSort.java │ │ ├── MergeSort.java │ │ ├── QuickSort.java │ │ ├── SelectSort.java │ │ ├── ShellSort.java │ │ └── 排序算法.md │ ├── swordoffer │ ├── README.md │ ├── Sword01_FindInArray.java │ ├── Sword02_ReplaceSpace.java │ ├── Sword03_printLinkedList.java │ ├── Sword04_RebuildBinaryTree.java │ ├── Sword05_QueuingWithTwoStacks.java │ ├── Sword06_MinNumberInRotateArray.java │ ├── Sword07_Fibonacci.java │ ├── Sword08_JumpFloor.java │ ├── Sword09_JumpFloorII.java │ ├── Sword10_RectCover.java │ ├── Sword11_NumberOf1.java │ ├── Sword12_Power.java │ ├── Sword13_ReOrderArray.java │ ├── Sword14_FindKthToTail.java │ ├── Sword15_ReverseList.java │ ├── Sword16_MergeSortedLinkedList.java │ ├── Sword17_HasSubtree.java │ ├── Sword18_Mirror.java │ ├── Sword19_PrintMatrix.java │ ├── Sword20_StackWithMin.java │ ├── Sword21_IsPopOrder.java │ ├── Sword22_PrintFromTopToBottom.java │ ├── Sword23_VerifySquenceOfBST.java │ ├── Sword24_FindPath.java │ ├── Sword25_Clone.java │ ├── Sword26_BSTToDoubleLinkedList.java │ ├── Sword27_Permutation.java │ ├── Sword28_MoreThanHalfNum.java │ ├── Sword29_LeastKNumber.java │ ├── Sword30_FindGreatestSumOfSubArray.java │ ├── Sword31_NumberOf1.java │ ├── Sword32_PrintMinNumber.java │ ├── Sword33_UglyNumber.java │ ├── Sword34_FirstNotRepeatChar.java │ ├── Sword35_InversePairs.java │ ├── Sword36_FindFirstCommonNode.java │ ├── Sword37_GetNumberOfK.java │ ├── Sword38_TreeDepth.java │ ├── Sword39_IsBalancedTree.java │ ├── Sword40_FindNumberAppearOnce.java │ ├── Sword41_ConitunuousSequence.java │ ├── Sword42_FindNumbersWithSum.java │ ├── Sword43_LeftRotateString.java │ ├── Sword44_ReverseSentence.java │ ├── Sword45_isContinuous.java │ ├── Sword46_LastRemaining.java │ ├── Sword47_Sum.java │ ├── Sword48_Add.java │ ├── Sword49_StrToInt.java │ ├── Sword50_Duplicate.java │ ├── Sword51_Multiply.java │ ├── Sword52_Match.java │ ├── Sword53_IsNumberic.java │ ├── Sword54_FirstAppearingOnce.java │ ├── Sword55_EntryNodeOfLoop.java │ ├── Sword56_DeleteDuplication.java │ ├── Sword57_GetNext.java │ ├── Sword58_isSymmetrical.java │ ├── Sword59_PrintZigZag.java │ ├── Sword60_PrintMultiLines.java │ ├── Sword61_SerializeTreeNode.java │ ├── Sword62_KthNode.java │ ├── Sword63_StreamMid.java │ ├── Sword64_MaxInWindow.java │ ├── Sword65_MatrixPath.java │ ├── Sword66_MovingCount.java │ ├── Sword67_CutRope.java │ └── Sword68_MaxGift.java │ └── topinterview │ ├── README.md │ └── easy │ ├── README.md │ ├── array │ ├── array21_removeDuplicates.java │ ├── array22_maxProfit2.java │ ├── array23_reverse.java │ ├── array24_containsDuplicate.java │ ├── array25_singleNumber.java │ ├── array26_intersect.java │ ├── array27_plusOne.java │ ├── array28_moveZeroes.java │ ├── array29_twoSum.java │ ├── array30_isValidSudoku.java │ └── array31_rotate.java │ ├── design │ ├── array58_shufflearray.java │ └── array59_minstack.java │ ├── dp │ ├── array54_climbStairs.java │ ├── array55_maxProfit.java │ ├── array56_maxSubArray.java │ └── array57_rob.java │ ├── linkedlist │ ├── array41_deleteNode.java │ ├── array42_removeNthFromEnd.java │ ├── array43_reverseList.java │ ├── array44_mergeTwoLists.java │ ├── array45_isPalindrome.java │ └── array46_hasCycle.java │ ├── math │ ├── array60_fizzBuzz.java │ ├── array61_countPrimes.java │ ├── array62_isPowerOfThree.java │ └── array63_romanToInt.java │ ├── other │ ├── array64_hammingWeight.java │ ├── array65_hammingDistance.java │ ├── array66_reverseBits.java │ ├── array67_pascalTriangle.java │ ├── array68_isValid.java │ └── array69_missingNumber.java │ ├── sort │ ├── array52_merge.java │ └── array53_firstBadVersion.java │ ├── string │ ├── array32_reverseString.java │ ├── array33_reverse.java │ ├── array34_firstUniqChar.java │ ├── array35_isAnagram.java │ ├── array36_isPalindrome.java │ ├── array37_myAtoi.java │ ├── array38_strStr.java │ ├── array39_countAndSay.java │ └── array40_longestCommonPrefix.java │ └── tree │ ├── array47_maxDepth.java │ ├── array48_isValidBST.java │ ├── array49_isSymmetic.java │ ├── array50_levelOrder.java │ └── array51_sortedArrayToBST.java └── wechat_logo.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | # maven ignore 2 | target/ 3 | 4 | # idea ignore 5 | .idea/ 6 | *.ipr 7 | *.iml 8 | *.iws 9 | 10 | .gitignore -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.example 8 | leetcode 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | org.apache.maven.plugins 14 | maven-compiler-plugin 15 | 16 | 8 17 | 8 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | junit 27 | junit 28 | 4.12 29 | 30 | 31 | com.google.guava 32 | guava 33 | 20.0 34 | 35 | 36 | com.alibaba 37 | fastjson 38 | 1.2.68 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/main/java/com/example/codeinterviewguide/README.md: -------------------------------------------------------------------------------- 1 | ## 程序员代码面试指南 : 2 | 3 | ### chapter2 : 链表部分题目: 4 | > 01.打印两个有续链表公共部分 5 | 02.在单链表和双链表中删除倒数第K个节点 6 | 03.删除链表中间节点和a/b节点 7 | 04.反转链表 8 | 05.反转部分链表 9 | 06.约瑟夫环问题-链表解法 10 | 07.判断链表是否回文结构 11 | 08.将单向链表按某值划分成左边小、中间相等、右边大的形式 12 | 09.复制含有随机指针节点的链表 13 | 10.两个单链表生成相加链表 14 | 11.两个链表相交的第一个节点 15 | 12.将单链表每K个节点之间逆序 16 | 13.删除无序单链表中值重复出现的节点 17 | 14.在单链表中删除指定值的节点 18 | 15.将搜索二叉树转换成双向链表 19 | 16.单链表的选择排序 20 | 17.怪异的删除方式 21 | 18.向有序的环形单链表中插入新节点 22 | 19.合并两个有序的单链表 23 | 20.按照左右半区的方式重新组合单链表 24 | 25 | ### 分类: 26 | - #### 链表反转: 27 | 04.反转链表 28 | 05.反转部分链表 29 | 07.判断链表是否回文结构 30 | 10.两个单链表生成相加链表(链表代表数字,通过反转实现空间复杂度O(1)) 31 | 32 | - #### 删除链表: 33 | 02.在单链表和双链表中删除倒数第K个节点 34 | 03.删除链表中间节点和a/b节点 35 | 13.删除无序单链表中值重复出现的节点 36 | 14.在单链表中删除指定值的节点 37 | 17.怪异的删除方式 38 | 39 | - #### 环形链表、相交链表: 40 | 11.两个链表相交的第一个节点(需要考虑是否有环) 41 | 18.向有序的环形单链表中插入新节点 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/main/java/com/example/codeinterviewguide/cp2_linkedlist/p01_PrintCommonPart.java: -------------------------------------------------------------------------------- 1 | package com.example.codeinterviewguide.cp2_linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 打印两个有续链表公共部分 7 | * @author: icecrea 8 | * @create: 2019-09-30 9 | **/ 10 | public class p01_PrintCommonPart { 11 | 12 | /** 13 | * 较小值链表指针后移,直到链表大小相等 14 | * 15 | * @param head1 16 | * @param head2 17 | */ 18 | public static void printCommonPart(ListNode head1, ListNode head2) { 19 | System.out.print("Common Part: "); 20 | while (head1 != null && head2 != null) { 21 | if (head1.val < head2.val) { 22 | head1 = head1.next; 23 | } else if (head1.val > head2.val) { 24 | head2 = head2.next; 25 | } else { 26 | System.out.print(head1.val + " "); 27 | head1 = head1.next; 28 | head2 = head2.next; 29 | } 30 | } 31 | System.out.println(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/example/codeinterviewguide/cp2_linkedlist/p02_RemoveLastKthNode.java: -------------------------------------------------------------------------------- 1 | package com.example.codeinterviewguide.cp2_linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 在单链表和双链表中删除倒数第K个节点 7 | * @author: icecrea 8 | * @create: 2019-09-30 9 | **/ 10 | public class p02_RemoveLastKthNode { 11 | 12 | /** 13 | * 单链表 14 | * 15 | * @param head 16 | * @param lastKth 17 | * @return 18 | */ 19 | public static ListNode removeLastKthNode(ListNode head, int lastKth) { 20 | if (head == null || lastKth < 1) { 21 | return head; 22 | } 23 | ListNode cur = head; 24 | while (cur != null) { 25 | lastKth--; 26 | cur = cur.next; 27 | } 28 | if (lastKth == 0) { 29 | head = head.next; 30 | } 31 | if (lastKth < 0) { 32 | cur = head; 33 | while (++lastKth != 0) { 34 | cur = cur.next; 35 | } 36 | cur.next = cur.next.next; 37 | } 38 | return head; 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/example/codeinterviewguide/cp2_linkedlist/p03_RemoveNodeByRatio.java: -------------------------------------------------------------------------------- 1 | package com.example.codeinterviewguide.cp2_linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 删除链表中间节点和a/b节点 7 | * @author: icecrea 8 | * @create: 2019-09-30 9 | **/ 10 | public class p03_RemoveNodeByRatio { 11 | 12 | /** 13 | * 删除中间节点 14 | * 15 | * @param head 16 | * @return 17 | */ 18 | public static ListNode removeMidListNode(ListNode head) { 19 | if (head == null || head.next == null) { 20 | return head; 21 | } 22 | if (head.next.next == null) { 23 | return head.next; 24 | } 25 | ListNode pre = head; 26 | ListNode cur = head.next.next; 27 | while (cur.next != null && cur.next.next != null) { 28 | pre = pre.next; 29 | cur = cur.next.next; 30 | } 31 | pre.next = pre.next.next; 32 | return head; 33 | } 34 | 35 | /** 36 | * 删除a/b节点 37 | * @param head 38 | * @param a 39 | * @param b 40 | * @return 41 | */ 42 | public static ListNode removeByRatio(ListNode head, int a, int b) { 43 | if (a < 1 || a > b) { 44 | return head; 45 | } 46 | int n = 0; 47 | ListNode cur = head; 48 | while (cur != null) { 49 | n++; 50 | cur = cur.next; 51 | } 52 | n = (int) Math.ceil(((double) (a * n)) / (double) b); 53 | if (n == 1) { 54 | head = head.next; 55 | } 56 | if (n > 1) { 57 | cur = head; 58 | while (--n != 1) { 59 | cur = cur.next; 60 | } 61 | cur.next = cur.next.next; 62 | } 63 | return head; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/example/codeinterviewguide/cp2_linkedlist/p04_ReverseList.java: -------------------------------------------------------------------------------- 1 | package com.example.codeinterviewguide.cp2_linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 反转链表 7 | * @author: icecrea 8 | * @create: 2019-09-30 9 | **/ 10 | public class p04_ReverseList { 11 | 12 | /** 13 | * 反转链表简洁版 14 | * 15 | * @param head 16 | * @return 17 | */ 18 | public static ListNode reverseList(ListNode head) { 19 | ListNode pre = null; 20 | ListNode next = null; 21 | while (head != null) { 22 | next = head.next; 23 | head.next = pre; 24 | pre = head; 25 | head = next; 26 | } 27 | return pre; 28 | } 29 | 30 | /** 31 | * reverse(head) 定义: 32 | * 输入一个节点 head,将「以 head 为起点」的链表反转,并返回反转之后的头结点。 33 | * 34 | */ 35 | public static ListNode reverse(ListNode head) { 36 | //递归终止条件: 找到链表最后一个节点 37 | if (head == null || head.next == null) { 38 | return head; 39 | } 40 | ListNode last = reverse(head.next); 41 | //反转头节点的下一个节点的next指针 head.next对应的是 反转后链表的尾指针,而node.next是反转后的头指针的下一个节点,此处注意区分 42 | head.next.next = head; 43 | //反转头节点的next指针,将头节点作为尾节点 44 | head.next = null; 45 | return last; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/example/codeinterviewguide/cp2_linkedlist/p05_ReversePartList.java: -------------------------------------------------------------------------------- 1 | package com.example.codeinterviewguide.cp2_linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 反转部分链表 将从from到to部分节点进行反转 7 | * @author: icecrea 8 | * @create: 2019-09-30 9 | **/ 10 | public class p05_ReversePartList { 11 | 12 | public static ListNode reversePart(ListNode head, int from, int to) { 13 | int len = 0; 14 | ListNode node1 = head; 15 | ListNode fPre = null; 16 | ListNode tPos = null; 17 | while (node1 != null) { 18 | len++; 19 | fPre = len == from - 1 ? node1 : fPre; 20 | tPos = len == to + 1 ? node1 : tPos; 21 | node1 = node1.next; 22 | } 23 | if (from > to || from < 1 || to > len) { 24 | return head; 25 | } 26 | node1 = fPre == null ? head : fPre.next; 27 | ListNode node2 = node1.next; 28 | node1.next = tPos; 29 | ListNode next = null; 30 | while (node2 != tPos) { 31 | next = node2.next; 32 | node2.next = node1; 33 | node1 = node2; 34 | node2 = next; 35 | } 36 | if (fPre != null) { 37 | fPre.next = node1; 38 | return head; 39 | } 40 | return node1; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/example/codeinterviewguide/cp2_linkedlist/p13_RemoveRepetition.java: -------------------------------------------------------------------------------- 1 | package com.example.codeinterviewguide.cp2_linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | import java.util.HashSet; 6 | 7 | /** 8 | * @description: 删除无序单链表中值重复出现的节点 9 | * 如 1-2-3-3-4-4-2-1-1-null 删除重复之后为 1-2-3-4-null 10 | * 要求两种方法 1.时间复杂O(N) 方法二2.额外空间复杂度O(1) 11 | * @author: icecrea 12 | * @create: 2019-09-30 13 | **/ 14 | public class p13_RemoveRepetition { 15 | /** 16 | * 哈希表 时间复杂度O1 空间复杂度On 17 | * @param head 18 | */ 19 | public static void removeRep1(ListNode head) { 20 | if (head == null) { 21 | return; 22 | } 23 | HashSet set = new HashSet<>(); 24 | ListNode pre = head; 25 | ListNode cur = head.next; 26 | set.add(head.val); 27 | while (cur != null) { 28 | if (set.contains(cur.val)) { 29 | pre.next = cur.next; 30 | } else { 31 | set.add(cur.val); 32 | pre = cur; 33 | } 34 | cur = cur.next; 35 | } 36 | } 37 | 38 | /** 39 | * 时间复杂度On^2 空间复杂度O1 40 | * @param head 41 | */ 42 | public static void removeRep2(ListNode head) { 43 | ListNode cur = head; 44 | ListNode pre; 45 | ListNode next; 46 | while (cur != null) { 47 | pre = cur; 48 | next = cur.next; 49 | while (next != null) { 50 | if (cur.val == next.val) { 51 | pre.next = next.next; 52 | } else { 53 | pre = next; 54 | } 55 | next = next.next; 56 | } 57 | cur = cur.next; 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/example/codeinterviewguide/cp2_linkedlist/p14_RemoveGivenValue.java: -------------------------------------------------------------------------------- 1 | package com.example.codeinterviewguide.cp2_linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | import java.util.Stack; 6 | 7 | /** 8 | * @description: 在单链表中删除指定值的节点 9 | * @author: icecrea 10 | * @create: 2019-09-30 11 | **/ 12 | public class p14_RemoveGivenValue { 13 | 14 | public static ListNode removeValue1(ListNode head, int num) { 15 | Stack stack = new Stack(); 16 | while (head != null) { 17 | if (head.val != num) { 18 | stack.push(head); 19 | } 20 | head = head.next; 21 | } 22 | while (!stack.isEmpty()) { 23 | stack.peek().next = head; 24 | head = stack.pop(); 25 | } 26 | return head; 27 | } 28 | 29 | public static ListNode removeValue2(ListNode head, int num) { 30 | while (head != null) { 31 | if (head.val != num) { 32 | break; 33 | } 34 | head = head.next; 35 | } 36 | ListNode pre = head; 37 | ListNode cur = head; 38 | while (cur != null) { 39 | if (cur.val == num) { 40 | pre.next = cur.next; 41 | } else { 42 | pre = cur; 43 | } 44 | cur = cur.next; 45 | } 46 | return head; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/example/codeinterviewguide/cp2_linkedlist/p15_BSTtoDoubleLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.example.codeinterviewguide.cp2_linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.TreeNode; 4 | 5 | import java.util.LinkedList; 6 | import java.util.Queue; 7 | 8 | /** 9 | * @description: 将搜索二叉树转换成双向链表 10 | * @author: icecrea 11 | * @create: 2019-09-30 12 | **/ 13 | public class p15_BSTtoDoubleLinkedList { 14 | 15 | 16 | public static TreeNode convert(TreeNode head) { 17 | Queue queue = new LinkedList(); 18 | inOrderToQueue(head, queue); 19 | if (queue.isEmpty()) { 20 | return head; 21 | } 22 | head = queue.poll(); 23 | TreeNode pre = head; 24 | pre.left = null; 25 | TreeNode cur; 26 | while (!queue.isEmpty()) { 27 | cur = queue.poll(); 28 | pre.right = cur; 29 | cur.left = pre; 30 | pre = cur; 31 | } 32 | pre.right = null; 33 | return head; 34 | } 35 | 36 | public static void inOrderToQueue(TreeNode head, Queue queue) { 37 | if (head == null) { 38 | return; 39 | } 40 | inOrderToQueue(head.left, queue); 41 | queue.offer(head); 42 | inOrderToQueue(head.right, queue); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/example/codeinterviewguide/cp2_linkedlist/p17_RemoveNodeWeird.java: -------------------------------------------------------------------------------- 1 | package com.example.codeinterviewguide.cp2_linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 怪异的删除方式 7 | * 给定一个链表中节点node,但是不给整个链表头节点 如何删除node 8 | * @author: icecrea 9 | * @create: 2019-09-30 10 | **/ 11 | public class p17_RemoveNodeWeird { 12 | 13 | 14 | /** 15 | * 删除某个节点需要得到前一个节点的指针,因为我们没有头节点指针,只能另辟蹊径 16 | * 将node下一个节点的值赋值给node节点,然后删除node的下一个节点。达到“删除node节点"效果。注意对node下一个节点判空 17 | * 18 | * @param node 19 | */ 20 | public static void removeNodeWired(ListNode node) { 21 | if (node == null) { 22 | return; 23 | } 24 | ListNode next = node.next; 25 | if (next == null) { 26 | throw new RuntimeException("can not remove last node."); 27 | } 28 | node.val = next.val; 29 | node.next = next.next; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/example/codeinterviewguide/cp2_linkedlist/p18_InsertNumToCircularList.java: -------------------------------------------------------------------------------- 1 | package com.example.codeinterviewguide.cp2_linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 向有序的环形单链表中插入新节点 7 | * 时间复杂度O(N),空间复杂度O(1) 8 | * @author: icecrea 9 | * @create: 2019-09-30 10 | **/ 11 | public class p18_InsertNumToCircularList { 12 | 13 | public static ListNode insertNum(ListNode head, int num) { 14 | ListNode node = new ListNode(num); 15 | if (head == null) { 16 | node.next = node; 17 | return node; 18 | } 19 | ListNode pre = head; 20 | ListNode cur = head.next; 21 | //循环一圈 22 | while (cur != head) { 23 | //找到对应的位置 24 | if (pre.val <= num && cur.val >= num) { 25 | break; 26 | } 27 | pre = cur; 28 | cur = cur.next; 29 | } 30 | //如果是转了一圈都没满足情况,说明应该插入到头节点前面 如1-3-4-1 num=5 将5插入节点1前 num-0 也应把0插入节点1前 下面条件同样满足 31 | pre.next = node; 32 | node.next = cur; 33 | //如果node节点值比链表头节点值大,返回原来头节点。如果node节点值比头节点小(即比最小节点小),把NODE作为链表新头节点返回 34 | return head.val < num ? head : node; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/example/codeinterviewguide/cp2_linkedlist/p19_MergeTwoLinkedLists.java: -------------------------------------------------------------------------------- 1 | package com.example.codeinterviewguide.cp2_linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 合并两个有序的单链表 7 | * @author: icecrea 8 | * @create: 2019-09-30 9 | **/ 10 | public class p19_MergeTwoLinkedLists { 11 | public static ListNode merge(ListNode head1, ListNode head2) { 12 | if (head1 == null || head2 == null) { 13 | return head1 != null ? head1 : head2; 14 | } 15 | ListNode head = head1.val < head2.val ? head1 : head2; 16 | //cur1和head指针指向同一个节点 17 | ListNode cur1 = head == head1 ? head1 : head2; 18 | ListNode cur2 = head == head1 ? head2 : head1; 19 | ListNode pre = null; 20 | ListNode next; 21 | while (cur1 != null && cur2 != null) { 22 | if (cur1.val <= cur2.val) { 23 | pre = cur1; 24 | cur1 = cur1.next; 25 | } else { 26 | next = cur2.next; 27 | pre.next = cur2; 28 | cur2.next = cur1; 29 | pre = cur2; 30 | cur2 = next; 31 | } 32 | } 33 | //连接剩下的节点 34 | pre.next = cur1 == null ? cur2 : cur1; 35 | return head; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/example/codeinterviewguide/cp2_linkedlist/p20_RelocateLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.example.codeinterviewguide.cp2_linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 按照左右半区的方式重新组合单链表 7 | * 如果N为奇数,前N/2个节点是左半区,后N/2+1个节点是右半区 8 | * 将链表调整成L1-R1-L2-R2的形式 9 | * 如: 1-2-3-4-null 调整后 1-3-2-4-null 10 | * 如: 1-2-3-4-5-null 调整后 1-3-2-4-5-null 11 | * 如: 1-2-3-4-5-6-null 调整后 1-4-2-5-3-6-null 12 | * @author: icecrea 13 | * @create: 2019-09-30 14 | **/ 15 | public class p20_RelocateLinkedList { 16 | public static void relocate(ListNode head) { 17 | if (head == null || head.next == null) { 18 | return; 19 | } 20 | //mid 代表下标为第n/2-1个节点 慢指针从第一个节点开始,步长为1, 快指针从第二个节点开始步长2,走的距离是慢指针两倍 21 | ListNode mid = head; 22 | ListNode right = head.next; 23 | while (right.next != null && right.next.next != null) { 24 | mid = mid.next; 25 | right = right.next.next; 26 | } 27 | right = mid.next; 28 | mid.next = null; 29 | mergeLR(head, right); 30 | } 31 | 32 | public static void mergeLR(ListNode left, ListNode right) { 33 | ListNode next; 34 | while (left.next != null) { 35 | next = right.next; 36 | right.next = left.next; 37 | left.next = right; 38 | 39 | left = right.next; 40 | right = next; 41 | } 42 | left.next = right; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/example/codeinterviewguide/cp3_binarytree/CompleteTreeNodeNumber.java: -------------------------------------------------------------------------------- 1 | package com.example.codeinterviewguide.cp3_binarytree; 2 | 3 | import com.example.leetcode.linkedlist.pojo.TreeNode; 4 | 5 | /** 6 | * @description: 统计完全二叉树节点数 7 | * @author: icecrea 8 | * @create: 2019-10-20 9 | **/ 10 | public class CompleteTreeNodeNumber { 11 | 12 | public int countNodes(TreeNode root) { 13 | TreeNode l = root, r = root; 14 | // 记录左、右子树的高度 15 | int hl = 0, hr = 0; 16 | while (l != null) { 17 | l = l.left; 18 | hl++; 19 | } 20 | while (r != null) { 21 | r = r.right; 22 | hr++; 23 | } 24 | // 如果左右子树的高度相同,则是一棵满二叉树 25 | if (hl == hr) { 26 | return (int) Math.pow(2, hl) - 1; 27 | } 28 | // 如果左右高度不同,则按照普通二叉树的逻辑计算 29 | return 1 + countNodes(root.left) + countNodes(root.right); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/example/codeinterviewguide/cp3_binarytree/Node.java: -------------------------------------------------------------------------------- 1 | package com.example.codeinterviewguide.cp3_binarytree; 2 | 3 | /** 4 | * @description: 5 | * @author: icecrea 6 | * @create: 2019-10-02 7 | **/ 8 | public class Node { 9 | public int value; 10 | public Node left; 11 | public Node right; 12 | 13 | public Node(int data) { 14 | this.value = data; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/array/LeetCode16_3SumClosest.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.array; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 最接近的三数之和 7 | * 给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。 8 | *

9 | * 例如,给定数组 nums = [-1,2,1,-4], 和 target = 1. 10 | *

11 | * 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2). 12 | * 13 | * @author icecrea 14 | */ 15 | public class LeetCode16_3SumClosest { 16 | /** 17 | * 3个数 问题是最接近target 最接近可以通过变量绝对值比较来判断 18 | */ 19 | public int threeSumClosest(int[] nums, int target) { 20 | // 排序 21 | Arrays.sort(nums); 22 | int closestNum = nums[0] + nums[1] + nums[2]; 23 | for (int i = 0; i < nums.length - 2; i++) { 24 | int l = i + 1, r = nums.length - 1; 25 | while (l < r){ 26 | int threeSum = nums[l] + nums[r] + nums[i]; 27 | if (Math.abs(threeSum - target) < Math.abs(closestNum - target)) { 28 | closestNum = threeSum; 29 | } 30 | if (threeSum > target) { 31 | r--; 32 | } else if (threeSum < target) { 33 | l++; 34 | } else { 35 | // 如果已经等于target的话, 肯定是最接近的 36 | return target; 37 | } 38 | 39 | } 40 | 41 | } 42 | 43 | return closestNum; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/array/LeetCode33_SearchInRotatedSortedArray.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.array; 2 | 3 | /** 4 | * @description: 循环有序数组二分查找 5 | * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 6 | * ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 7 | * 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 8 | * 你可以假设数组中不存在重复的元素。 9 | * 你的算法时间复杂度必须是 O(log n) 级别。 10 | * 示例 1: 11 | * 输入: arr = [4,5,6,7,0,1,2], target = 0 12 | * 输出: 4 13 | * 示例 2: 14 | * 输入: arr = [4,5,6,7,0,1,2], target = 3 15 | * 输出: -1 16 | * @author: icecrea 17 | * @create: 2019-10-24 18 | **/ 19 | public class LeetCode33_SearchInRotatedSortedArray { 20 | /** 21 | * 中间节点小于最右节点,说明右半部分有序 22 | * 中间节点大于最右节点,说明左半部分有序 23 | */ 24 | public int search(int[] arr, int target) { 25 | int low = 0, high = arr.length - 1; 26 | while (low <= high) { 27 | int mid = low + ((high - low) >> 1); 28 | if (arr[mid] == target) { 29 | return mid; 30 | } else if (arr[mid] < arr[high]) { //右侧是有序的 31 | //判断查找的数是否在右区间中 32 | if (arr[mid] < target && arr[high] >= target) { 33 | low = mid + 1; 34 | } else { 35 | high = mid - 1; 36 | } 37 | } else { //左侧是有序的 38 | //判断查找的数是否在左区间中 39 | if (arr[mid] > target && arr[low] <= target) { 40 | high = mid - 1; 41 | } else { 42 | low = mid + 1; 43 | } 44 | } 45 | } 46 | return -1; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/backtrack/LeetCode077_Combinations.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.backtrack; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * @description: 组合 10 | * 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 11 | * 示例: 12 | * 输入: n = 4, k = 2 13 | * 输出: 14 | * [ 15 | * [2,4], 16 | * [3,4], 17 | * [2,3], 18 | * [1,2], 19 | * [1,3], 20 | * [1,4], 21 | * ] 22 | * 来源:力扣(LeetCode) 23 | * 链接:https://leetcode-cn.com/problems/combinations 24 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 25 | * @auther: icecrea 26 | * @date: 2020/4/20 27 | */ 28 | public class LeetCode077_Combinations { 29 | List> res = new ArrayList<>(); 30 | 31 | public List> combine(int n, int k) { 32 | List backtrack = new ArrayList<>(); 33 | backtrack(backtrack, k, n, 1); 34 | return res; 35 | } 36 | 37 | void backtrack(List track, int k, int n, int start) { 38 | if (track.size() == k) { 39 | res.add(new ArrayList<>(track)); 40 | return; 41 | } 42 | for (int i = start; i <= n; i++) { 43 | track.add(i); 44 | backtrack(track, k, n, i + 1); 45 | track.remove(track.size() - 1); 46 | } 47 | } 48 | 49 | @Test 50 | public void test() { 51 | combine(4, 2); 52 | System.out.println(res); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/backtrack/LeetCode200_NumberOfIslands.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.backtrack; 2 | 3 | /** 4 | * @description: 岛屿的个数 5 | * 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 6 | * 示例 1: 7 | * 输入: 8 | * 11110 9 | * 11010 10 | * 11000 11 | * 00000 12 | * 输出: 1 13 | * 示例 2: 14 | * 输入: 15 | * 11000 16 | * 11000 17 | * 00100 18 | * 00011 19 | * 输出: 3 20 | * @author: icecrea 21 | * @create: 2020-01-04 22 | **/ 23 | public class LeetCode200_NumberOfIslands { 24 | 25 | public int numIslands(char[][] grid) { 26 | if (grid == null || grid.length == 0) { 27 | return 0; 28 | } 29 | int rows = grid.length; 30 | int cols = grid[0].length; 31 | int num_islands = 0; 32 | for (int r = 0; r < rows; ++r) { 33 | for (int c = 0; c < cols; ++c) { 34 | if (grid[r][c] == '1') { 35 | ++num_islands; 36 | dfs(grid, r, c); 37 | } 38 | } 39 | } 40 | return num_islands; 41 | } 42 | 43 | 44 | /** 45 | * 染色法:深度优先遍历,访问到某个节点,将该节点置为0,并且将其周围关联的为1的节点也置为0 46 | * 从grid[i][j]出发,将能遍历到的岛屿1置为0 47 | */ 48 | void dfs(char[][] grid, int i, int j) { 49 | int rows = grid.length; 50 | int cols = grid[0].length; 51 | 52 | if (i < 0 || j < 0 || i >= rows || j >= cols || grid[i][j] == '0') { 53 | return; 54 | } 55 | grid[i][j] = '0'; 56 | dfs(grid, i - 1, j); 57 | dfs(grid, i + 1, j); 58 | dfs(grid, i, j - 1); 59 | dfs(grid, i, j + 1); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarysearch/LeetCode033_SearchInRotatedSortedArray.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarysearch; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 搜索旋转排序数组 7 | * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 8 | * ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 9 | * 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 10 | * 你可以假设数组中不存在重复的元素。 11 | * 你的算法时间复杂度必须是 O(log n) 级别。 12 | * 示例 1: 13 | * 输入: nums = [4,5,6,7,0,1,2], target = 0 14 | * 输出: 4 15 | * 示例 2: 16 | * 输入: nums = [4,5,6,7,0,1,2], target = 3 17 | * 输出: -1 18 | * @auther: icecrea 19 | * @date: 2019/12/18 20 | */ 21 | public class LeetCode033_SearchInRotatedSortedArray { 22 | public int search(int[] nums, int target) { 23 | if (nums == null || nums.length == 0) { 24 | return -1; 25 | } 26 | int start = 0, end = nums.length - 1; 27 | int mid; 28 | while (start <= end) { 29 | mid = start + (end - start) / 2; 30 | if (nums[mid] == target) { 31 | return mid; 32 | } 33 | //前半部分有序 34 | if (nums[start] <= nums[mid]) { 35 | //target在前半部分 36 | if (target >= nums[start] && target < nums[mid]) { 37 | end = mid - 1; 38 | } else { 39 | start = mid + 1; 40 | } 41 | } else { 42 | //后半部分有序 43 | if (target <= nums[end] && target > nums[mid]) { 44 | start = mid + 1; 45 | } else { 46 | end = mid - 1; 47 | } 48 | } 49 | } 50 | return -1; 51 | } 52 | 53 | @Test 54 | public void test() { 55 | System.out.println(search(new int[]{4, 5, 6, 7, 0, 1, 2}, 0)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarysearch/LeetCode035_SearchInsertPosition.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarysearch; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 搜索插入位置 7 | * 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 8 | * 你可以假设数组中无重复元素。 9 | * 示例 1: 10 | * 输入: [1,3,5,6], 5 11 | * 输出: 2 12 | * 示例 2: 13 | * 输入: [1,3,5,6], 2 14 | * 输出: 1 15 | * 示例 3: 16 | * 输入: [1,3,5,6], 7 17 | * 输出: 4 18 | * 示例 4: 19 | * 输入: [1,3,5,6], 0 20 | * 输出: 0 21 | * @auther: icecrea 22 | * @date: 2019/12/18 23 | */ 24 | public class LeetCode035_SearchInsertPosition { 25 | /** 26 | * 二分查找模板 27 | * 其实这道题可以转换成,大于或者等于目标值的第 1 个数的索引 28 | * 因为:如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 所以不用再单独判断left right 29 | */ 30 | public int searchInsert(int[] nums, int target) { 31 | //特殊情况考虑 32 | if (target > nums[nums.length - 1]) { 33 | return nums.length; 34 | } 35 | int left = 0, right = nums.length - 1; 36 | while (left < right) { 37 | int mid = (left + right) >>> 1; 38 | //排除中位数的逻辑 目标至少是中位数但不包括中位数 39 | if (nums[mid] < target) { 40 | left = mid + 1; 41 | } else { 42 | right = mid; 43 | } 44 | } 45 | return left; 46 | } 47 | 48 | @Test 49 | public void test() { 50 | System.out.println(searchInsert(new int[]{1, 3, 5, 6}, 5)); 51 | System.out.println(searchInsert(new int[]{1, 3, 5, 6}, 2)); 52 | System.out.println(searchInsert(new int[]{1, 3, 5, 6}, 4)); 53 | System.out.println(searchInsert(new int[]{1, 3, 5, 6}, 6)); 54 | 55 | System.out.println(Integer.MAX_VALUE); 56 | System.out.println((Integer.MAX_VALUE + Integer.MAX_VALUE) >>> 1); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarysearch/LeetCode153_FindMinInRotatedSortedArray.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarysearch; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 寻找旋转排序数组中的最小值 7 | * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 8 | * ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 9 | * 请找出其中最小的元素。 10 | * 你可以假设数组中不存在重复元素。 11 | * 示例 1: 12 | * 输入: [3,4,5,1,2] 13 | * 输出: 1 14 | * 示例 2: 15 | * 输入: [4,5,6,7,0,1,2] 16 | * 输出: 0 17 | * @auther: icecrea 18 | * @date: 2019/12/19 19 | */ 20 | public class LeetCode153_FindMinInRotatedSortedArray { 21 | public int findMin(int[] nums) { 22 | int left = 0, right = nums.length - 1, mid; 23 | while (left < right) { 24 | mid = (left + right) >>> 1; 25 | //中大于右, 最小值必然在右侧 26 | if (nums[mid] > nums[right]) { 27 | left = mid + 1; 28 | } else { 29 | right = mid; 30 | } 31 | } 32 | return nums[left]; 33 | } 34 | 35 | @Test 36 | public void test() { 37 | System.out.println(findMin(new int[]{1, 2, 3, 4, 5})); 38 | System.out.println(findMin(new int[]{2, 3, 4, 5, 1})); 39 | System.out.println(findMin(new int[]{3, 4, 5, 1, 2})); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarysearch/LeetCode154_FindMinInRotatedSortedArray2.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarysearch; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 寻找旋转排序数组中的最小值2 7 | * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 8 | * ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 9 | * 请找出其中最小的元素。 10 | * 注意数组中可能存在重复的元素。 11 | * 示例 1: 12 | * 输入: [1,3,5] 13 | * 输出: 1 14 | * 示例 2: 15 | * 输入: [2,2,2,0,1] 16 | * 输出: 0 17 | * 说明: 18 | * 这道题是 寻找旋转排序数组中的最小值 的延伸题目。 19 | * 允许重复会影响算法的时间复杂度吗?会如何影响,为什么? 20 | * @auther: icecrea 21 | * @date: 2019/12/19 22 | */ 23 | public class LeetCode154_FindMinInRotatedSortedArray2 { 24 | /** 25 | * 有了重复元素,主要问题在于相等情况取哪个区间 如 1,3,3 、 3,3,1,3 两种情况 26 | * 当nums[mid] == nums[right]时,可以把right舍弃,因为两者相等,所以必然不会影响结果 27 | */ 28 | public int findMin(int[] nums) { 29 | int left = 0, right = nums.length - 1, mid; 30 | while (left < right) { 31 | mid = (left + right) >>> 1; 32 | //中大于右, 最小值必然在右侧 33 | if (nums[mid] > nums[right]) { 34 | left = mid + 1; 35 | }else if(nums[mid] < nums[right]){ 36 | right = mid; 37 | }else { 38 | right--; 39 | } 40 | } 41 | return nums[left]; 42 | } 43 | 44 | @Test 45 | public void test() { 46 | System.out.println(findMin(new int[]{1, 2, 3, 4, 5})); 47 | System.out.println(findMin(new int[]{2, 3, 4, 5, 1})); 48 | System.out.println(findMin(new int[]{3, 4, 5, 1, 2})); 49 | System.out.println(findMin(new int[]{1, 3, 3})); 50 | System.out.println(findMin(new int[]{3, 3, 1})); 51 | System.out.println(findMin(new int[]{3, 3, 1, 3})); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarysearch/LeetCode209_MinSizeSubArraySum.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarysearch; 2 | 3 | /** 4 | * @description: 长度最小的子数组 5 | * 给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。 6 | * 示例:  7 | * 输入: s = 7, nums = [2,3,1,2,4,3] 8 | * 输出: 2 9 | * 解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。 10 | * 进阶: 11 | * 如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。 12 | * @auther: icecrea 13 | * @date: 2019/12/20 14 | */ 15 | public class LeetCode209_MinSizeSubArraySum { 16 | public int minSubArrayLen1(int s, int[] nums) { 17 | int n = nums.length; 18 | int ans = Integer.MAX_VALUE; 19 | int left = 0; 20 | int sum = 0; 21 | for (int i = 0; i < n; i++) { 22 | sum += nums[i]; 23 | while (sum >= s) { 24 | ans = Math.min(ans, i - left + 1); 25 | sum -= nums[left++]; 26 | } 27 | } 28 | return (ans != Integer.MAX_VALUE) ? ans : 0; 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarysearch/LeetCode367_ValidPerfectSquare.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarysearch; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 有效的完全平方数 7 | * 给定一个正整数 num,编写一个函数,如果 num 是一个完全平方数,则返回 True,否则返回 False。 8 | * 说明:不要使用任何内置的库函数,如  sqrt。 9 | * 示例 1: 10 | * 输入:16 11 | * 输出:True 12 | * 示例 2: 13 | * 输入:14 14 | * 输出:False 15 | * @auther: icecrea 16 | * @date: 2019/12/19 17 | */ 18 | public class LeetCode367_ValidPerfectSquare { 19 | public boolean isPerfectSquare(int num) { 20 | long left = 1, right = num, mid; 21 | while (left < right) { 22 | mid = (left + right) >>> 1; 23 | if (mid * mid < num) { 24 | left = mid + 1; 25 | } else { 26 | right = mid; 27 | } 28 | } 29 | return (left * left) == num ? true : false; 30 | } 31 | 32 | @Test 33 | public void test() { 34 | int a = 111111111; 35 | int b = 111111111; 36 | double c = a * b; 37 | System.out.println((double) a * b); 38 | System.out.println((double) c); 39 | System.out.println(isPerfectSquare(2147483647)); 40 | System.out.println(isPerfectSquare(2147483647)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarysearch/LeetCode374_GuessNumberHighLow.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarysearch; 2 | 3 | /** 4 | * @description: 猜数字大小 5 | * 我们正在玩一个猜数字游戏。 游戏规则如下: 6 | * 我从 1 到 n 选择一个数字。 你需要猜我选择了哪个数字。 7 | * 每次你猜错了,我会告诉你这个数字是大了还是小了。 8 | * 你调用一个预先定义好的接口 guess(int num),它会返回 3 个可能的结果(-1,1 或 0): 9 | * -1 : 我的数字比较小 10 | * 1 : 我的数字比较大 11 | * 0 : 恭喜!你猜对了! 12 | * 示例 : 13 | * 输入: n = 10, pick = 6 14 | * 输出: 6 15 | * @auther: icecrea 16 | * @date: 2019/12/19 17 | */ 18 | public class LeetCode374_GuessNumberHighLow { 19 | int guess(int num) { 20 | return 1; 21 | } 22 | 23 | public int guessNumber(int n) { 24 | int left = 0, right = n, mid; 25 | while (left <= right) { 26 | mid = (left + right) >>> 1; 27 | if (guess(mid) == 0) { 28 | return mid; 29 | } else if (guess(mid) == -1) { 30 | right = mid - 1; 31 | } else { 32 | left = mid + 1; 33 | } 34 | } 35 | return -1; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarysearch/LeetCode441_ArrangingCoins.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarysearch; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 排列硬币 7 | * 你总共有 n 枚硬币,你需要将它们摆成一个阶梯形状,第 k 行就必须正好有 k 枚硬币。 8 | * 给定一个数字 n,找出可形成完整阶梯行的总行数。 9 | * n 是一个非负整数,并且在32位有符号整型的范围内。 10 | * 示例 1: 11 | * n = 5 12 | * 硬币可排列成以下几行: 13 | * ¤ 14 | * ¤ ¤ 15 | * ¤ ¤ 16 | * 因为第三行不完整,所以返回2. 17 | * 示例 2: 18 | * n = 8 19 | * 硬币可排列成以下几行: 20 | * ¤ 21 | * ¤ ¤ 22 | * ¤ ¤ ¤ 23 | * ¤ ¤ 24 | * 因为第四行不完整,所以返回3. 25 | * @auther: icecrea 26 | * @date: 2019/12/19 27 | */ 28 | public class LeetCode441_ArrangingCoins { 29 | public int arrangeCoins(int n) { 30 | long left = 0, right = n, mid; 31 | while (left < right) { 32 | mid = (left + right + 1) >>> 1; 33 | long t = (1 + mid) * (mid - 1 + 1) / 2; 34 | if (t > n) { 35 | right = mid - 1; 36 | } else { 37 | left = mid; 38 | } 39 | } 40 | return (int) left; 41 | } 42 | 43 | @Test 44 | public void test() { 45 | System.out.println(arrangeCoins(8)); 46 | System.out.println(arrangeCoins(0)); 47 | System.out.println(arrangeCoins(1804289383)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarysearch/LeetCode704_BinarySearch.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarysearch; 2 | 3 | /** 4 | * @description: 二分查找 5 | * 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 6 | * 示例 1: 7 | * 输入: nums = [-1,0,3,5,9,12], target = 9 8 | * 输出: 4 9 | * 解释: 9 出现在 nums 中并且下标为 4 10 | * 示例 2: 11 | * 输入: nums = [-1,0,3,5,9,12], target = 2 12 | * 输出: -1 13 | * 解释: 2 不存在 nums 中因此返回 -1 14 | *   15 | * 提示: 16 | * 你可以假设 nums 中的所有元素是不重复的。 17 | * n 将在 [1, 10000]之间。 18 | * nums 的每个元素都将在 [-9999, 9999]之间。 19 | * @auther: icecrea 20 | * @date: 2019/12/19 21 | */ 22 | public class LeetCode704_BinarySearch { 23 | public int search(int[] nums, int target) { 24 | int left = 0, right = nums.length - 1; 25 | int mid; 26 | while (left < right) { 27 | mid = (left + right) >>> 1; 28 | if (nums[mid] < target) { 29 | left = mid + 1; 30 | } else { 31 | right = mid; 32 | } 33 | } 34 | return nums[left] == target ? left : -1; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarysearch/LeetCode852_PeakIndexInMountainArray.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarysearch; 2 | 3 | /** 4 | * @description: 山脉数组的峰顶索引 5 | * 我们把符合下列属性的数组 A 称作山脉: 6 | * A.length >= 3 7 | * 存在 0 < i < A.length - 1 使得A[0] < A[1] < ... A[i-1] < A[i] > A[i+1] > ... > A[A.length - 1] 8 | * 给定一个确定为山脉的数组,返回任何满足 A[0] < A[1] < ... A[i-1] < A[i] > A[i+1] > ... > A[A.length - 1] 的 i 的值。 9 | *   10 | * 示例 1: 11 | * 输入:[0,1,0] 12 | * 输出:1 13 | * 示例 2: 14 | * 输入:[0,2,1,0] 15 | * 输出:1 16 | *   17 | * 提示: 18 | * 3 <= A.length <= 10000 19 | * 0 <= A[i] <= 10^6 20 | * A 是如上定义的山脉 21 | * @auther: icecrea 22 | * @date: 2019/12/19 23 | */ 24 | public class LeetCode852_PeakIndexInMountainArray { 25 | /** 26 | * 利用该数组先增后减的特性,二分查找 27 | * 数组左部分满足 A[mid] < A[mid + 1] 右部分不满足。 28 | * 当A[mid] < A[mid + 1]时, mid肯定不是最大值索引,在右半区查找 29 | */ 30 | public int peakIndexInMountainArray(int[] A) { 31 | int left = 0, right = A.length, mid; 32 | while (left < right) { 33 | mid = (left + right) >>> 1; 34 | if (A[mid] < A[mid + 1]) { 35 | left = mid + 1; 36 | } else { 37 | right = mid; 38 | } 39 | } 40 | return left; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarytree/LeetCode111_MinDepth.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarytree; 2 | 3 | import com.example.leetcode.linkedlist.pojo.TreeNode; 4 | 5 | /** 6 | * @description: 二叉树最小深度 7 | * 给定一个二叉树,找出其最小深度。 8 | * 9 | * 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 10 | * 11 | * 说明: 叶子节点是指没有子节点的节点。 12 | * 13 | * 示例: 14 | * 15 | * 给定二叉树 [3,9,20,null,null,15,7], 16 | * 17 | * 3 18 | * / \ 19 | * 9 20 20 | * / \ 21 | * 15 7 22 | * 返回它的最小深度  2. 23 | * 24 | * 来源:力扣(LeetCode) 25 | * 链接:https://leetcode-cn.com/problems/minimum-depth-of-binary-tree 26 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 27 | * @author: icecrea 28 | * @create: 2020-05-03 29 | **/ 30 | public class LeetCode111_MinDepth { 31 | 32 | /** 33 | * 注意是到叶子节点的最小深度 34 | * 35 | * @param root 36 | * @return 37 | */ 38 | public int minDepth(TreeNode root) { 39 | if (root == null) { 40 | return 0; 41 | } 42 | int left = minDepth(root.left); 43 | int right = minDepth(root.right); 44 | 45 | if (left == 0 || right == 0) { 46 | return left + right + 1; 47 | } 48 | //注意是要到叶子节点 49 | return Math.min(left, right) + 1; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarytree/LeetCode112_PathSum.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarytree; 2 | 3 | import com.example.leetcode.linkedlist.pojo.TreeNode; 4 | 5 | /** 6 | * @description: 路径总和 7 | * 8 | * 给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。 9 | * 10 | * 说明: 叶子节点是指没有子节点的节点。 11 | * 12 | * 示例: 13 | * 给定如下二叉树,以及目标和 sum = 22, 14 | * 15 | * 5 16 | * / \ 17 | * 4 8 18 | * / / \ 19 | * 11 13 4 20 | * / \ \ 21 | * 7 2 1 22 | * 返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。 23 | * @author: icecrea 24 | * @create: 2020-05-03 25 | **/ 26 | public class LeetCode112_PathSum { 27 | boolean flag = false; 28 | 29 | /** 30 | * 注意是到叶子节点的最小深度 31 | */ 32 | public boolean hasPathSum(TreeNode root, int sum) { 33 | if (root == null) { 34 | return false; 35 | } 36 | dfs(root, root.val, sum); 37 | return flag; 38 | } 39 | 40 | void dfs(TreeNode root, int cur, int sum) { 41 | if (root == null) { 42 | return; 43 | } 44 | if (cur == sum && root.left == null && root.right == null) { 45 | flag = true; 46 | return; 47 | } 48 | if (root.left != null) { 49 | dfs(root.left, cur + root.left.val, sum); 50 | } 51 | if (root.right != null) { 52 | dfs(root.right, cur + root.right.val, sum); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarytree/LeetCode114_Flatten.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarytree; 2 | 3 | import com.example.leetcode.linkedlist.pojo.TreeNode; 4 | 5 | /** 6 | * @description: 二叉树展开为链表 7 | * 给定一个二叉树,原地将它展开为链表。 8 | * 9 | * 例如,给定二叉树 10 | * 11 | * 1 12 | * / \ 13 | * 2 5 14 | * / \ \ 15 | * 3 4 6 16 | * 将其展开为: 17 | * 18 | * 1 19 | * \ 20 | * 2 21 | * \ 22 | * 3 23 | * \ 24 | * 4 25 | * \ 26 | * 5 27 | * \ 28 | * 6 29 | * 30 | * 来源:力扣(LeetCode) 31 | * 链接:https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list 32 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 33 | * @author: icecrea 34 | * @create: 2020-05-03 35 | **/ 36 | public class LeetCode114_Flatten { 37 | 38 | /** 39 | * 将左子树插入到右子树的地方 40 | * 将原来的右子树接到左子树的最右边节点 41 | * 考虑新的右子树的根节点,一直重复上边的过程,直到新的右子树为 null 42 | */ 43 | public void flatten(TreeNode root) { 44 | while (root != null) { 45 | //左子树为 null,直接考虑下一个节点 46 | if (root.left == null) { 47 | root = root.right; 48 | } else { 49 | // 找左子树最右边的节点 50 | TreeNode pre = root.left; 51 | while (pre.right != null) { 52 | pre = pre.right; 53 | } 54 | //将原来的右子树接到左子树的最右边节点 55 | pre.right = root.right; 56 | // 将左子树插入到右子树的地方 57 | root.right = root.left; 58 | root.left = null; 59 | // 考虑下一个节点 60 | root = root.right; 61 | } 62 | } 63 | } 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarytree/LeetCode124_BinaryTreeMaxPath.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarytree; 2 | 3 | import com.example.leetcode.linkedlist.pojo.TreeNode; 4 | 5 | /** 6 | * @description: 二叉树最大路径和 7 | * 给定一个非空二叉树,返回其最大路径和。 8 | * 9 | * 本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。 10 | * 11 | * 示例 1: 12 | * 13 | * 输入: [1,2,3] 14 | * 15 | * 1 16 | * / \ 17 | * 2 3 18 | * 19 | * 输出: 6 20 | * 示例 2: 21 | * 22 | * 输入: [-10,9,20,null,null,15,7] 23 | * 24 | *   -10 25 | *    / \ 26 | *   9  20 27 | *     /  \ 28 | *    15   7 29 | * 30 | * 输出: 42 31 | * 32 | * 来源:力扣(LeetCode) 33 | * 链接:https://leetcode-cn.com/problems/binary-tree-maximum-path-sum 34 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 35 | * @author: icecrea 36 | * @create: 2020-05-03 37 | **/ 38 | public class LeetCode124_BinaryTreeMaxPath { 39 | 40 | 41 | public int max = Integer.MIN_VALUE; 42 | 43 | public int maxPathSum(TreeNode root) { 44 | findMax(root); 45 | return max; 46 | } 47 | 48 | /** 49 | * 以root为根节点的树的单边路径最大值 50 | */ 51 | public int findMax(TreeNode root) { 52 | if (root == null) { 53 | return 0; 54 | } 55 | int left = Math.max(0, findMax(root.left)); 56 | int right = Math.max(0, findMax(root.right)); 57 | max = Math.max(max, root.val + left + right); 58 | return Math.max(left, right) + root.val; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarytree/LeetCode199_binaryTreeRightView.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarytree; 2 | 3 | import com.example.leetcode.linkedlist.pojo.TreeNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.LinkedList; 7 | import java.util.List; 8 | import java.util.Queue; 9 | 10 | /** 11 | * @description: 二叉树右视图 12 | * 给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。 13 | * 示例: 14 | * 输入: [1,2,3,null,5,null,4] 15 | * 输出: [1, 3, 4] 16 | * 解释: 17 | * 1 <--- 18 | * / \ 19 | * 2 3 <--- 20 | * \ \ 21 | * 5 4 <--- 22 | * 来源:力扣(LeetCode) 23 | * 链接:https://leetcode-cn.com/problems/binary-tree-right-side-view 24 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 25 | * @auther: icecrea 26 | * @date: 2020/4/21 27 | */ 28 | public class LeetCode199_binaryTreeRightView { 29 | 30 | public List rightSideView(TreeNode root) { 31 | Queue q = new LinkedList<>(); 32 | List res = new ArrayList<>(); 33 | if (root == null) { 34 | return new ArrayList<>(); 35 | } 36 | q.offer(root); 37 | while (!q.isEmpty()) { 38 | int size = q.size(); 39 | for (int i = 0; i < size; i++) { 40 | TreeNode poll = q.poll(); 41 | if (poll.left != null) { 42 | q.offer(poll.left); 43 | } 44 | if (poll.right != null) { 45 | q.offer(poll.right); 46 | } 47 | if (i == size - 1) { 48 | res.add(poll.val); 49 | } 50 | } 51 | } 52 | return res; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarytree/LeetCode236_LowestCommonAncestorOfBinaryTree.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarytree; 2 | 3 | import com.example.leetcode.linkedlist.pojo.TreeNode; 4 | import org.junit.Test; 5 | 6 | /** 7 | * 二叉树最近公共父节点 8 | * 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 9 | * 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” 10 | * 例如,给定如下二叉树:  root = [3,5,1,6,2,0,8,null,null,7,4] 11 | * 示例 1: 12 | * 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 13 | * 输出: 3 14 | * 解释: 节点 5 和节点 1 的最近公共祖先是节点 3。 15 | * 示例 2: 16 | * 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 17 | * 输出: 5 18 | * 解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。 19 | * 说明: 20 | * 所有节点的值都是唯一的。 21 | * p、q 为不同节点且均存在于给定的二叉树中。 22 | */ 23 | public class LeetCode236_LowestCommonAncestorOfBinaryTree { 24 | 25 | /** 26 | * 1。如果其中一个节点是根节点,返回根节点为最近公共父节点 27 | * 2。都不是根节点,分别递归左子树,右子树,看哪个子树存在pq的最近公共父节点 28 | * 3。如果都不存在,说明pq分别在两个子树上,一边一个,返回根节点 29 | * 4。如果其中一个存在,返回结果 30 | */ 31 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { 32 | if (root == null) { 33 | return null; 34 | } 35 | if (p == root || q == root) { 36 | return root; 37 | } 38 | TreeNode left = lowestCommonAncestor(root.left, p, q); 39 | TreeNode right = lowestCommonAncestor(root.right, p, q); 40 | //两个节点分别在root的左右分支,返回根节点为最近公共节点 41 | if (left != null && right != null) { 42 | return root; 43 | } 44 | return right == null ? left : right; 45 | } 46 | 47 | @Test 48 | public void test() { 49 | TreeNode root = new TreeNode(0); 50 | TreeNode right = new TreeNode(1); 51 | root.left = null; 52 | root.right = right; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/binarytree/LeetCode965_UnivaluedBinaryTree.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.binarytree; 2 | 3 | import com.example.leetcode.linkedlist.pojo.TreeNode; 4 | 5 | /** 6 | * @description: 单值二叉树 7 | * 如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。 8 | * 只有给定的树是单值二叉树时,才返回 true;否则返回 false。 9 | * 10 | * 输入:[1,1,1,1,1,null,1] 11 | * 输出:true 12 | * 13 | * 输入:[2,2,2,5,2] 14 | * 输出:false 15 | * 16 | * 提示: 17 | * 18 | * 给定树的节点数范围是 [1, 100]。 19 | * 每个节点的值都是整数,范围为 [0, 99] 。 20 | * @author: icecrea 21 | * @create: 2020-01-10 22 | **/ 23 | public class LeetCode965_UnivaluedBinaryTree { 24 | 25 | public boolean isUnivalTree(TreeNode root) { 26 | return same(root, root.val); 27 | } 28 | 29 | public boolean same(TreeNode root, int val) { 30 | if (root == null) { 31 | return true; 32 | } 33 | return root.val == val && same(root.left, val) && same(root.right, val); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/dp/LeetCode120_TriangleMinPath.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.dp; 2 | 3 | import com.google.common.collect.Lists; 4 | import org.junit.Test; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * 三角形最小路径和 11 | * 给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 12 | * 13 | * 例如,给定三角形: 14 | * 15 | * [ 16 | * [2], 17 | * [3,4], 18 | * [6,5,7], 19 | * [4,1,8,3] 20 | * ] 21 | * 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 22 | * 23 | * 说明: 24 | * 25 | * 如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。 26 | */ 27 | public class LeetCode120_TriangleMinPath { 28 | /** 29 | * 2 30 | * 3 4 31 | * 6 5 7 32 | * 4 1 8 3 33 | * 34 | * 自顶向下和自底向上的最短路径是相同的 35 | * 如果从顶向下,需要考虑很多判空条件,所以自底向上计算 36 | * 转移方程如下 37 | * num[i][j] = min(num[i+1][j],num[i+1][j+1]) + num[i][j] 38 | */ 39 | public int minimumTotal(List> triangle) { 40 | int row = triangle.size(); 41 | List res = new ArrayList<>(triangle.get(row - 1)); 42 | for (int i = row - 2; i >= 0; i--) { 43 | List rowList = triangle.get(i); 44 | for (int j = 0; j < rowList.size(); j++) { 45 | res.set(j, Math.min(res.get(j), res.get(j + 1)) + rowList.get(j)); 46 | } 47 | } 48 | return res.get(0); 49 | } 50 | 51 | @Test 52 | public void test() { 53 | List> list = new ArrayList(); 54 | list.add(Lists.newArrayList(2)); 55 | list.add(Lists.newArrayList(3, 4)); 56 | list.add(Lists.newArrayList(6, 5, 7)); 57 | list.add(Lists.newArrayList(4, 1, 8, 3)); 58 | int i = minimumTotal(list); 59 | System.out.println(i); 60 | 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/dp/LeetCode300_LIS.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.dp; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | import java.util.Stack; 9 | 10 | /** 11 | * 最长上升子序列 12 | * LIS问题 LongestIncreasingSubsequence 13 | * 给定一个无序的整数数组,找到其中最长上升子序列的长度。 14 | * 示例: 15 | * 输入: [10,9,2,5,3,7,101,18] 16 | * 输出: 4 17 | * 解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。 18 | * 说明: 19 | * 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。 20 | * 你算法的时间复杂度应该为 O(n2) 。 21 | * 进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗? 22 | */ 23 | public class LeetCode300_LIS { 24 | 25 | /** 26 | * dp[i]: 以i结尾的最长递增子序列长度 O(N^2) 27 | * 问题在于如何根据已知的dp[0]...dp[i-1],来推导dp[i] 28 | * 10,9,2,5,3,7,101,18 29 | * 1 ,1,1,2,2,3,4, 4 30 | */ 31 | public int lengthOfLIS(int[] a) { 32 | if (a == null || a.length == 0) { 33 | return 0; 34 | } 35 | //dp[i] 以i结尾的最长递增子序列长度 36 | int dp[] = new int[a.length]; 37 | Arrays.fill(dp, 1); 38 | int max = Integer.MIN_VALUE; 39 | for (int j = 1; j < a.length; j++) { 40 | for (int i = 0; i < j; i++) { 41 | if (a[j] > a[i]) { 42 | dp[j] = Math.max(dp[j], dp[i] + 1); 43 | } 44 | } 45 | max = Math.max(max, dp[j]); 46 | } 47 | return max; 48 | } 49 | 50 | @Test 51 | public void test() { 52 | System.out.println(lengthOfLIS(new int[]{10, 9, 2, 5, 3, 7, 101, 18})); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/dp/LeetCode53_MaximumSubarray.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.dp; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 最大连续子序列和 7 | * 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 8 | * 9 | * 示例: 10 | * 11 | * 输入: [-2,1,-3,4,-1,2,1,-5,4], 12 | * 输出: 6 13 | * 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 14 | * 进阶: 15 | * 16 | * 如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 17 | */ 18 | public class LeetCode53_MaximumSubarray { 19 | 20 | /** 21 | * -2,1,-3,4,-1,2,1,-5,4 22 | * -2,1,-2,4,3,5,6,1,5 23 | * -2,1, 1,4,4,5,6,6,6 24 | * 25 | * @param nums 26 | * @return 27 | */ 28 | public int maxSubArray(int[] nums) { 29 | int maxToCur = Integer.MIN_VALUE; 30 | int max = Integer.MIN_VALUE; 31 | for (int i = 0; i < nums.length; i++) { 32 | if (maxToCur >= 0) { 33 | maxToCur += nums[i]; 34 | } else { 35 | maxToCur = nums[i]; 36 | } 37 | max = Math.max(maxToCur, max); 38 | } 39 | return max; 40 | } 41 | 42 | @Test 43 | public void test() { 44 | // int max = maxSubArray(new int[]{-2, 1, -3, 4, -1, 2, 1, -5, 4}); 45 | int max = maxSubArray(new int[]{-1}); 46 | System.out.println(max); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/dp/LeetCode55_JumpGame.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.dp; 2 | 3 | /** 4 | * @description: 跳跃游戏 5 | * 给定一个非负整数数组,你最初位于数组的第一个位置。 6 | * 数组中的每个元素代表你在该位置可以跳跃的最大长度。 7 | * 判断你是否能够到达最后一个位置。 8 | * 示例 1: 9 | * 输入: [2,3,1,1,4] 10 | * 输出: true 11 | * 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 12 | * 示例 2: 13 | * 输入: [3,2,1,0,4] 14 | * 输出: false 15 | * 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 16 | * 来源:力扣(LeetCode) 17 | * 链接:https://leetcode-cn.com/problems/jump-game 18 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 19 | * @auther: icecrea 20 | * @date: 2020/4/22 21 | */ 22 | public class LeetCode55_JumpGame { 23 | 24 | /** 25 | * 2 3 1 1 4 26 | * 2 4 4 4 27 | * 3 2 1 0 4 28 | * 3 3 3 3 29 | * 30 | * @param nums 31 | * @return 32 | */ 33 | public boolean canJump(int[] nums) { 34 | int max = 0; 35 | for (int i = 0; i < nums.length - 1; i++) { 36 | // 计算从0到i为止能跳到的最远距离 37 | max = Math.max(max, i + nums[i]); 38 | if (max <= i) { 39 | return false; 40 | } 41 | } 42 | return true; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/dp/LeetCode70_ClimbingStairs.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.dp; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 爬楼梯 7 | * 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 8 | * 9 | * 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 10 | * 11 | * 注意:给定 n 是一个正整数。 12 | * 13 | * 示例 1: 14 | * 15 | * 输入: 2 16 | * 输出: 2 17 | * 解释: 有两种方法可以爬到楼顶。 18 | * 1. 1 阶 + 1 阶 19 | * 2. 2 阶 20 | * 示例 2: 21 | * 22 | * 输入: 3 23 | * 输出: 3 24 | * 解释: 有三种方法可以爬到楼顶。 25 | * 1. 1 阶 + 1 阶 + 1 阶 26 | * 2. 1 阶 + 2 阶 27 | * 3. 2 阶 + 1 阶 28 | */ 29 | public class LeetCode70_ClimbingStairs { 30 | 31 | /** 32 | * f(n) = f(n-1) + f(n-2) 33 | * 11 22 33 45 58 34 | * @param n 35 | * @return 36 | */ 37 | public int climbStairs(int n) { 38 | if (n == 1) { 39 | return 1; 40 | } 41 | if (n == 2) { 42 | return 2; 43 | } 44 | int l = 1; 45 | int r = 2; 46 | int res = 0; 47 | for (int i = 3; i <= n; i++) { 48 | res = l + r; 49 | l = r; 50 | r = res; 51 | } 52 | return res; 53 | } 54 | 55 | @Test 56 | public void test(){ 57 | System.out.println(climbStairs(3)); 58 | System.out.println(climbStairs(4)); 59 | System.out.println(climbStairs(5)); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/dp/LeetCode87_ScrambleString.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.dp; 2 | 3 | /** 4 | * 扰乱字符串 5 | * 给定一个字符串 s1,我们可以把它递归地分割成两个非空子字符串,从而将其表示为二叉树。 6 | * 7 | * 下图是字符串 s1 = "great" 的一种可能的表示形式。 8 | * 9 | * great 10 | * / \ 11 | * gr eat 12 | * / \ / \ 13 | * g r e at 14 | * / \ 15 | * a t 16 | * 在扰乱这个字符串的过程中,我们可以挑选任何一个非叶节点,然后交换它的两个子节点。 17 | * 18 | * 例如,如果我们挑选非叶节点 "gr" ,交换它的两个子节点,将会产生扰乱字符串 "rgeat" 。 19 | * 20 | * rgeat 21 | * / \ 22 | * rg eat 23 | * / \ / \ 24 | * r g e at 25 | * / \ 26 | * a t 27 | * 我们将 "rgeat” 称作 "great" 的一个扰乱字符串。 28 | * 29 | * 同样地,如果我们继续交换节点 "eat" 和 "at" 的子节点,将会产生另一个新的扰乱字符串 "rgtae" 。 30 | * 31 | * rgtae 32 | * / \ 33 | * rg tae 34 | * / \ / \ 35 | * r g ta e 36 | * / \ 37 | * t a 38 | * 我们将 "rgtae” 称作 "great" 的一个扰乱字符串。 39 | * 40 | * 给出两个长度相等的字符串 s1 和 s2,判断 s2 是否是 s1 的扰乱字符串。 41 | * 42 | * 示例 1: 43 | * 44 | * 输入: s1 = "great", s2 = "rgeat" 45 | * 输出: true 46 | * 示例 2: 47 | * 48 | * 输入: s1 = "abcde", s2 = "caebd" 49 | * 输出: false 50 | * 51 | */ 52 | public class LeetCode87_ScrambleString { 53 | 54 | // public boolean isScramble(String s1, String s2) { 55 | // 56 | // } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/dp/README.md: -------------------------------------------------------------------------------- 1 | ## 动态规划专题 Leetcode 2 | - [05.最长回文子串](./LeetCode05_LongestPalindromicSubstring.java) 3 | - [10.正则表达式匹配](./LeetCode10_RegularExpressionMatching.java) 4 | - [32.最长有效括号](./LeetCode32_LongestValidParantheses.java) 5 | - [53.最大连续子序列和](./LeetCode53_MaximumSubarray.java) 6 | - [62.不同路径](./LeetCode62_UniquePaths.java) 7 | - [63.不同路径2](./LeetCode63_UniquePaths2.java) 8 | - [64.最小路径和](./LeetCode64_MinimumPathSum.java) 9 | - [70.爬楼梯](./LeetCode70_ClimbingStairs.java) 10 | - [72.编辑距离](./LeetCode72_EditDistance.java) 11 | - [79.单词搜索](./LeetCode79_SearchWord.java) 12 | - [84.柱状图中最大的矩形](./LeetCode84_LargestRectangleInHistogram.java) 13 | - [85.最大矩形](./LeetCode85_MaximalRectangle.java) 14 | - [87.扰乱字符串](./LeetCode87_ScrambleString.java) 15 | - [95.不同的二叉搜索树2](./LeetCode95_UniqueBST2.java) 16 | - [96.不同的二叉搜索树](./LeetCode96_UniqueBST.java) 17 | - [120.三角形最小路径和](./LeetCode120_TriangleMinPath.java) 18 | - [121.买卖股票的最佳时机](./LeetCode121_BestTimeToBuyAndSellStock.java) 19 | - [122.买卖股票的最佳时机2](./LeetCode122_BestTimeToBuyAndSellStock2.java) 20 | - [123.买卖股票的最佳时机3](./LeetCode123_BestTimeToBuyAndSellStock3.java) 21 | - [198.打家劫舍](./LeetCode198_HouseRobber.java) 22 | - [213.打家劫舍2](./LeetCode213_HouseRobber2.java) 23 | - [300.最长上升子序列LIS](./LeetCode300_LIS.java) 24 | - [322.零钱兑换](./LeetCode322_CoinChange.java) 25 | - [474.一和零](./LeetCode474_OnesAndZeros.java) 26 | - [516.最长回文子序列](./LeetCode516_LongestPalindromicSubsequence.java) 27 | - [651.四键键盘](./LeetCode651_4KeysKeyboard.java) 28 | - [673.最长递增子序列的个数](./LeetCode673_NumberOfLIS.java) 29 | - [1143.最长公共子序列LCS](./LeetCode1143_LCS.java) -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/dp/palindrome/LeetCode516_LongestPalindromicSubsequence.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.dp.palindrome; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 最长回文子序列 7 | * 给定一个字符串s,找到其中最长的回文子序列。可以假设s的最大长度为1000。 8 | * 9 | * 示例 1: 10 | * 输入: 11 | * "bbbab" 12 | * 输出: 13 | * 4 14 | * 一个可能的最长回文子序列为 "bbbb"。 15 | * 16 | * 示例 2: 17 | * 输入: 18 | * "cbbd" 19 | * 输出: 20 | * 21 | * 2 22 | * 一个可能的最长回文子序列为 "bb"。 23 | */ 24 | public class LeetCode516_LongestPalindromicSubsequence { 25 | 26 | /** 27 | * dp[i][j] : 在子串 s[i..j] 中,最长回文子序列的长度 28 | * 我们需要的是 dp[0][n - 1] 29 | * 注意遍历顺序,i 从最后一个字符开始往前遍历,j 从 i + 1 开始往后遍历,这样可以保证每个子问题都已经算好了。 30 | */ 31 | public int longestPalindromeSubseq(String s) { 32 | int n = s.length(); 33 | int[][] dp = new int[s.length()][s.length()]; 34 | for (int i = n - 1; i >= 0; i--) { 35 | //单个字符初始化 回文为1 36 | dp[i][i] = 1; 37 | for (int j = i + 1; j < n; j++) { 38 | if (s.charAt(i) == s.charAt(j)) { 39 | dp[i][j] = dp[i + 1][j - 1] + 2; 40 | } else { 41 | dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]); 42 | } 43 | } 44 | } 45 | return dp[0][n - 1]; 46 | } 47 | 48 | @Test 49 | public void test(){ 50 | 51 | /** 52 | * 53 | * b b b a b 54 | * b 1 55 | * b 1 56 | * b 1 57 | * a 1 58 | * b 1 59 | */ 60 | 61 | System.out.println(longestPalindromeSubseq("bbbab")); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/dp/palindrome/LeetCode647_PalindromicSubstrings.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.dp.palindrome; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 回文子串个数 7 | * 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。 8 | * 具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。 9 | * 示例 1: 10 | * 输入: "abc" 11 | * 输出: 3 12 | * 解释: 三个回文子串: "a", "b", "c". 13 | * 示例 2: 14 | * 输入: "aaa" 15 | * 输出: 6 16 | * 说明: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa". 17 | * 注意: 18 | * 输入的字符串长度不会超过1000。 19 | * @auther: icecrea 20 | * @date: 2019/12/16 21 | */ 22 | public class LeetCode647_PalindromicSubstrings { 23 | /** 24 | * 动态规划 25 | * dp[i][j] 代表str[i] - str[j]是否是回文子串 26 | * 考虑单字符和双字符的特殊情况 27 | * 状态转移方程:dp[i][j] = dp[i+1][j-1] && str[i]==str[j] 28 | * 可以类比 29 | * @see LeetCode05_LongestPalindromicSubstring 30 | */ 31 | public int countSubstrings(String s) { 32 | int res = 0; 33 | boolean dp[][] = new boolean[s.length()][s.length()]; 34 | for (int j = 0; j < s.length(); j++) { 35 | for (int i = j; i >= 0; i--) { 36 | if (s.charAt(i) == s.charAt(j) && ((j - i < 2) || dp[i + 1][j - 1])) { 37 | dp[i][j] = true; 38 | res++; 39 | } 40 | } 41 | } 42 | return res; 43 | } 44 | 45 | @Test 46 | public void test() { 47 | System.out.println(countSubstrings("aaa")); 48 | System.out.println(countSubstrings("abc")); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/heap/LeetCode703_ktLargestElementIntream.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.heap; 2 | 3 | import java.util.PriorityQueue; 4 | 5 | /** 6 | * @description: 数据流中的第K大元素 7 | * 设计一个找到数据流中第K大元素的类(class)。注意是排序后的第K大元素,不是第K个不同的元素。 8 | *

9 | * 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中的初始元素。每次调用 KthLargest.add,返回当前数据流中第K大的元素。 10 | *

11 | * 示例: 12 | *

13 | * int k = 3; 14 | * int[] arr = [4,5,8,2]; 15 | * KthLargest kthLargest = new KthLargest(3, arr); 16 | * kthLargest.add(3); // returns 4 17 | * kthLargest.add(5); // returns 5 18 | * kthLargest.add(10); // returns 5 19 | * kthLargest.add(9); // returns 8 20 | * kthLargest.add(4); // returns 8 21 | * 说明: 22 | * 你可以假设 nums 的长度≥ k-1 且k ≥ 1。 23 | * @author: icecrea 24 | * @create: 2019-04-15 13:09 25 | **/ 26 | public class LeetCode703_ktLargestElementIntream { 27 | 28 | // public PriorityQueue priorityQueue = new PriorityQueue(); 29 | // 30 | // public KthLargest(int k, int[] nums) { 31 | // 32 | // } 33 | // 34 | // public int add(int val) { 35 | // 36 | // } 37 | } 38 | 39 | /** 40 | * Your KthLargest object will be instantiated and called as such: 41 | * KthLargest obj = new KthLargest(k, nums); 42 | * int param_1 = obj.add(val); 43 | */ 44 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/heap/package-info.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.heap; 2 | 3 | // https://leetcode-cn.com/tag/heap/ 4 | // 堆 列表 -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/LeetCode02_AddTwoNumbers.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 两数相加 7 | * 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的, 8 | * 并且它们的每个节点只能存储 一位 数字。 9 | * 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 10 | * 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 11 | * 示例: 12 | * 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 13 | * 输出:7 -> 0 -> 8 14 | * 原因:342 + 465 = 807 15 | * @author: icecrea 16 | * @create: 2018-12-24 19:12 17 | **/ 18 | public class LeetCode02_AddTwoNumbers { 19 | 20 | public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 21 | ListNode dummyHead = new ListNode(0); 22 | ListNode p = l1, q = l2, curr = dummyHead; 23 | int carry = 0; 24 | while (p != null || q != null) { 25 | int x = (p != null) ? p.val : 0; 26 | int y = (q != null) ? q.val : 0; 27 | int sum = carry + x + y; 28 | carry = sum / 10; 29 | curr.next = new ListNode(sum % 10); 30 | curr = curr.next; 31 | if (p != null) { 32 | p = p.next; 33 | } 34 | if (q != null) { 35 | q = q.next; 36 | } 37 | } 38 | if (carry > 0) { 39 | curr.next = new ListNode(carry); 40 | } 41 | return dummyHead.next; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/LeetCode109_ConvertSortedListToBinarySearchTree.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | import com.example.leetcode.linkedlist.pojo.TreeNode; 5 | 6 | /** 7 | * @description: 有序链表转换二叉搜索树 TODO 8 | * 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。 9 | * 10 | * 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。 11 | * 12 | * 示例: 13 | * 14 | * 给定的有序链表: [-10, -3, 0, 5, 9], 15 | * 16 | * 一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树: 17 | * 18 | * 0 19 | * / \ 20 | * -3 9 21 | * / / 22 | * -10 5 23 | * @author: icecrea 24 | * @create: 2019-01-08 20:28 25 | **/ 26 | public class LeetCode109_ConvertSortedListToBinarySearchTree { 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/LeetCode147_InsertionSortList.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 对链表进行插入排序 7 | * 插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。 8 | * 每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。 9 | *

10 | *

11 | *

12 | * 插入排序算法: 13 | *

14 | * 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。 15 | * 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。 16 | * 重复直到所有输入数据插入完为止。 17 | *

18 | *

19 | * 示例 1: 20 | *

21 | * 输入: 4->2->1->3 22 | * 输出: 1->2->3->4 23 | * 示例 2: 24 | *

25 | * 输入: -1->5->3->4->0 26 | * 输出: -1->0->3->4->5 27 | * @author: icecrea 28 | * @create: 2019-01-03 20:57 29 | **/ 30 | public class LeetCode147_InsertionSortList { 31 | public ListNode insertionSortList(ListNode head) { 32 | if (head == null) { 33 | return head; 34 | } 35 | //通过dummy节点构造链表 36 | ListNode dummy = new ListNode(0); 37 | ListNode cur = head; 38 | ListNode pre = dummy; 39 | ListNode next; 40 | while (cur != null) { 41 | next = cur.next; 42 | pre = dummy; 43 | //找到插入的位置的前一个节点pre 44 | while (pre.next != null && pre.next.val < cur.val) { 45 | pre = pre.next; 46 | } 47 | //在pre与pre.next之间插入cur 48 | cur.next = pre.next; 49 | pre.next = cur; 50 | cur = next; 51 | } 52 | 53 | //不能返回head head节点可能会被移动 54 | return dummy.next; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/LeetCode160_IntersectionOfTwoLists.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 相交链表 7 | * 找到两个单链表相交的起始节点。 8 | *

9 | * 输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3 10 | * 输出:Reference of the node with value = 8 11 | * 输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。 12 | * 从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。 13 | *

14 | * 注意: 15 | * 如果两个链表没有交点,返回 null. 16 | * 在返回结果后,两个链表仍须保持原有的结构。 17 | * 可假定整个链表结构中没有循环。 18 | * 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。 19 | * @author: icecrea 20 | * @create: 2018-12-27 11:31 21 | **/ 22 | public class LeetCode160_IntersectionOfTwoLists { 23 | /** 24 | * 这个思路就是 ListA + ListB = A + intersection + Bb + intersection 25 | * ListB + ListA = Bb + intersection + A + intersection 26 | * 用大A表示ListA里面非共有 Bb表示listB里面非共有的,可以看到在第二个intersection的开头两个链表长度是一样的,必然相等 27 | * 所以我们可以遍历A再遍历B,另一个遍历B再遍历A,两个指针必定在第二个交集处相遇,没有交集就是空指针 28 | * 29 | * @param headA 30 | * @param headB 31 | * @return 32 | */ 33 | public ListNode getIntersectionNode(ListNode headA, ListNode headB) { 34 | /** 35 | 定义两个指针, 第一轮让两个到达末尾的节点指向另一个链表的头部, 最后如果相遇则为交点(在第一轮移动中恰好抹除了长度差) 36 | 两个指针等于移动了相同的距离, 有交点就返回, 无交点就是各走了两条指针的长度 37 | **/ 38 | if (headA == null || headB == null) { 39 | return null; 40 | } 41 | ListNode pA = headA, pB = headB; 42 | // 在这里第一轮体现在pA和pB第一次到达尾部会移向另一链表的表头, 而第二轮体现在如果pA或pB相交就返回交点, 不相交最后就是null==null 43 | while (pA != pB) { 44 | pA = pA == null ? headB : pA.next; 45 | pB = pB == null ? headA : pB.next; 46 | } 47 | return pA; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/LeetCode19_RemoveNthNodeFromEnd.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 删除链表的倒数第N个节点 7 | * 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。 8 | *

9 | * 示例: 10 | *

11 | * 给定一个链表: 1->2->3->4->5, 和 n = 2. 12 | *

13 | * 当删除了倒数第二个节点后,链表变为 1->2->3->5. 14 | * 说明: 15 | *

16 | * 给定的 n 保证是有效的。 17 | *

18 | * 进阶: 19 | *

20 | * 你能尝试使用一趟扫描实现吗? 21 | * @author: icecrea 22 | * @create: 2018-12-24 20:39 23 | **/ 24 | public class LeetCode19_RemoveNthNodeFromEnd { 25 | 26 | public ListNode removeNthFromEnd(ListNode head, int n) { 27 | ListNode d = new ListNode(0); 28 | d.next = head; 29 | ListNode fast = d, slow = d; 30 | for (int i = 0; i < n; i++) { 31 | fast = fast.next; 32 | } 33 | while (fast != null && fast.next != null) { 34 | slow = slow.next; 35 | fast = fast.next; 36 | } 37 | slow.next = slow.next.next; 38 | return d.next; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/LeetCode203_RemoveLinkedListElements.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 移除链表元素 7 | *

8 | * 删除链表中等于给定值 val 的所有节点。 9 | *

10 | * 示例: 11 | *

12 | * 输入: 1->2->6->3->4->5->6, val = 6 13 | * 输出: 1->2->3->4->5 14 | * @author: icecrea 15 | * @create: 2018-12-27 17:02 16 | **/ 17 | public class LeetCode203_RemoveLinkedListElements { 18 | /** 19 | * 设置哑节点,next连到头节点, 20 | * 然后遍历当前节点的next值与val是否相等,便于删除 21 | * @param head 22 | * @param val 23 | * @return 24 | */ 25 | public ListNode removeElements(ListNode head, int val) { 26 | if (head == null) { 27 | return null; 28 | } 29 | ListNode newHead = new ListNode(Integer.MIN_VALUE); 30 | newHead.next = head; 31 | 32 | ListNode cur = newHead; 33 | while (cur.next != null) { 34 | if (cur.next.val == val) { 35 | cur.next = cur.next.next; 36 | } else { 37 | cur = cur.next; 38 | } 39 | } 40 | return newHead.next; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/LeetCode206_ReverseLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 反转链表 7 | *

8 | * 反转一个单链表。 9 | *

10 | * 示例: 11 | *

12 | * 输入: 1->2->3->4->5->NULL 13 | * 输出: 5->4->3->2->1->NULL 14 | * 进阶: 15 | * 你可以迭代或递归地反转链表。你能否用两种方法解决这道题? 16 | * @author: icecrea 17 | * @create: 2018-12-27 11:42 18 | **/ 19 | public class LeetCode206_ReverseLinkedList { 20 | /** 21 | * 非递归 22 | * @param head 23 | * @return 24 | */ 25 | public ListNode reverseList(ListNode head) { 26 | if (head == null || head.next == null) { 27 | return head; 28 | } 29 | 30 | ListNode p = head; 31 | ListNode q = p.next; 32 | head.next = null; 33 | ListNode next; 34 | 35 | while (q != null) { 36 | //因为有指针反转,所以需要提前保留下一个step要处理的指针 37 | next = q.next; 38 | //指针反转 39 | q.next = p; 40 | //后移一位 41 | p = q; 42 | q = next; 43 | } 44 | return p; 45 | } 46 | 47 | 48 | /** 49 | * 递归方法 50 | * @param head 51 | * @return 52 | */ 53 | public ListNode reverseListRecur(ListNode head) { 54 | //递归终止条件: 找到链表最后一个节点 55 | if (head == null || head.next == null) { 56 | return head; 57 | } 58 | ListNode newNode = reverseListRecur(head.next); 59 | //反转头节点的下一个节点的next指针 head.next对应的是 反转后链表的尾指针,而node.next是反转后的头指针的下一个节点,此处注意区分 60 | head.next.next = head; 61 | //反转头节点的next指针,将头节点作为尾节点 62 | head.next = null; 63 | return newNode; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/LeetCode21_MergeTwoSortedLists.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 合并两个有序链表 7 | * 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 8 | * 示例: 9 | * 输入:1->2->4, 1->3->4 10 | * 输出:1->1->2->3->4->4 11 | * @author: icecrea 12 | * @create: 2018-12-24 18:58 13 | **/ 14 | public class LeetCode21_MergeTwoSortedLists { 15 | /** 16 | * 合并两个有序链表 17 | * 18 | * @param l1 19 | * @param l2 20 | * @return 21 | */ 22 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 23 | ListNode dummy = new ListNode(Integer.MIN_VALUE); 24 | ListNode cur = dummy; 25 | while (l1 != null && l2 != null) { 26 | if (l1.val < l2.val) { 27 | cur.next = l1; 28 | l1 = l1.next; 29 | } else { 30 | cur.next = l2; 31 | l2 = l2.next; 32 | } 33 | cur = cur.next; 34 | } 35 | cur.next = l1 == null ? l2 : l1; 36 | return dummy.next; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/LeetCode234_PalindromeLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 回文链表 7 | *

8 | * 请判断一个链表是否为回文链表。 9 | *

10 | * 示例 1: 11 | *

12 | * 输入: 1->2 13 | * 输出: false 14 | * 示例 2: 15 | *

16 | * 输入: 1->2->2->1 17 | * 输出: true 18 | * 进阶: 19 | * 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题? 20 | * @author: icecrea 21 | * @create: 2018-12-27 18:02 22 | **/ 23 | public class LeetCode234_PalindromeLinkedList { 24 | 25 | public boolean isPalindrome(ListNode head) { 26 | // 要实现 O(n) 的时间复杂度和 O(1) 的空间复杂度,需要翻转后半部分 27 | if (head == null || head.next == null) { 28 | return true; 29 | } 30 | ListNode fast = head; 31 | ListNode slow = head; 32 | // 根据快慢指针,找到链表的中点 33 | while(fast.next != null && fast.next.next != null) { 34 | fast = fast.next.next; 35 | slow = slow.next; 36 | } 37 | slow = reverse(slow.next); 38 | while(slow != null) { 39 | if (head.val != slow.val) { 40 | return false; 41 | } 42 | head = head.next; 43 | slow = slow.next; 44 | } 45 | return true; 46 | } 47 | 48 | 49 | private ListNode reverse(ListNode head) { 50 | if (head == null || head.next == null) { 51 | return head; 52 | } 53 | ListNode newNode = reverse(head.next); 54 | head.next.next = head; 55 | head.next = null; 56 | return newNode; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/LeetCode237_DeleteNodeInLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 删除链表中的节点 7 | * 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。 8 | *

9 | * 现有一个链表 -- head = [4,5,1,9],它可以表示为: 10 | *

11 | * 4 -> 5 -> 1 -> 9 12 | * 示例 1: 13 | *

14 | * 输入: head = [4,5,1,9], node = 5 15 | * 输出: [4,1,9] 16 | * 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9. 17 | * 示例 2: 18 | *

19 | * 输入: head = [4,5,1,9], node = 1 20 | * 输出: [4,5,9] 21 | * 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9. 22 | * 说明: 23 | *

24 | * 链表至少包含两个节点。 25 | * 链表中所有节点的值都是唯一的。 26 | * 给定的节点为非末尾节点并且一定是链表中的一个有效节点。 27 | * 不要从你的函数中返回任何结果。 28 | * @author: icecrea 29 | * @create: 2018-12-29 00:25 30 | **/ 31 | public class LeetCode237_DeleteNodeInLinkedList { 32 | 33 | /** 34 | * 我们无法访问我们想要删除的节点之前的节点,我们始终不能修改该节点的 next 指针。 35 | * 相反,我们必须将想要删除的节点的值替换为它后面节点中的值,然后删除它之后的节点。 36 | * 因为我们知道要删除的节点不是列表的末尾,所以我们可以保证这种方法是可行的。 37 | * 38 | * @param node 39 | */ 40 | public void deleteNode(ListNode node) { 41 | node.val = node.next.val; 42 | node.next = node.next.next; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/LeetCode24_SwapNodesInPairs.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 两两交换链表中的节点 7 | * 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 8 | *

9 | * 示例: 10 | *

11 | * 给定 1->2->3->4, 你应该返回 2->1->4->3. 12 | * 说明: 13 | *

14 | * 你的算法只能使用常数的额外空间。 15 | * 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 16 | * @author: icecrea 17 | * @create: 2019-01-08 22:06 18 | **/ 19 | public class LeetCode24_SwapNodesInPairs { 20 | 21 | /** 22 | * 23 | * 1->2->3->4 24 | * 2->1->4->3 25 | * 26 | * @param head 27 | * @return 28 | */ 29 | public ListNode swapPairs(ListNode head) { 30 | ListNode dummy = new ListNode(0); 31 | dummy.next = head; 32 | ListNode point = dummy; 33 | while (point.next != null && point.next.next != null) { 34 | ListNode swap1 = point.next; 35 | ListNode swap2 = point.next.next; 36 | // 注意语句顺序不要变动 37 | point.next = swap2; 38 | swap1.next = swap2.next; 39 | swap2.next = swap1; 40 | point = swap1; 41 | } 42 | return dummy.next; 43 | } 44 | 45 | public ListNode swapPairsRecur(ListNode head) { 46 | if ((head == null) || (head.next == null)) { 47 | return head; 48 | } 49 | ListNode n = head.next; 50 | head.next = swapPairsRecur(head.next.next); 51 | n.next = head; 52 | return n; 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/LeetCode328_OddEvenLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 奇偶链表 7 | * 给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。 8 | * 请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。 9 | * 示例 1: 10 | * 输入: 1->2->3->4->5->NULL 11 | * 输出: 1->3->5->2->4->NULL 12 | * 示例 2: 13 | * 输入: 2->1->3->5->6->4->7->NULL 14 | * 输出: 2->3->6->7->1->5->4->NULL 15 | * 说明: 16 | * 应当保持奇数节点和偶数节点的相对顺序。 17 | * 链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。 18 | * @author: icecrea 19 | * @create: 2019-01-02 18:50 20 | **/ 21 | public class LeetCode328_OddEvenLinkedList { 22 | /** 23 | * 限制了空间复杂度 ,则需要在链表中调整,因为每次调整会改变指针,所以我们需要在循环过程中,同时调整奇偶指针的next 24 | * 25 | * @param head 26 | * @return 27 | */ 28 | public ListNode oddEvenList(ListNode head) { 29 | if (head == null || head.next == null) { 30 | return head; 31 | } 32 | ListNode oddHead = head; 33 | ListNode odd = oddHead; 34 | ListNode evenHead = head.next; 35 | ListNode even = evenHead; 36 | while (odd.next != null && even.next != null) { 37 | odd.next = odd.next.next; 38 | even.next = even.next.next; 39 | 40 | odd = odd.next; 41 | even = even.next; 42 | } 43 | odd.next = evenHead; 44 | return oddHead; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/LeetCode82_RemoveDuplicatesFromSortedList2.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 删除排序链表中的重复元素 II 7 | * 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。 8 | *

9 | * 示例 1: 10 | *

11 | * 输入: 1->2->3->3->4->4->5 12 | * 输出: 1->2->5 13 | * 示例 2: 14 | *

15 | * 输入: 1->1->1->2->3 16 | * 输出: 2->3 17 | * @author: icecrea 18 | * @create: 2019-01-07 19:46 19 | **/ 20 | public class LeetCode82_RemoveDuplicatesFromSortedList2 { 21 | 22 | public ListNode deleteDuplicates(ListNode head) { 23 | ListNode dummy = new ListNode(Integer.MIN_VALUE); 24 | dummy.next = head; 25 | ListNode pre = dummy; 26 | //因为要删除所有重复的元素而并非留一个,所以要考虑头节点删除,留出pre指针,比较后两个大小是否相等 27 | while (pre.next != null && pre.next.next != null) { 28 | if (pre.next.val != pre.next.next.val) { 29 | pre = pre.next; 30 | continue; 31 | } else { 32 | ListNode lastSame = pre.next.next; 33 | while (lastSame.next != null && pre.next.val == lastSame.next.val) { 34 | lastSame = lastSame.next; 35 | } 36 | //移动指针指向,不真正移动指针,指针的移动在不同时候 比如:有可能存在54448889这种情况 37 | pre.next = lastSame.next; 38 | } 39 | } 40 | return dummy.next; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/LeetCode83_RemoveDuplicatesFromSortedList.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 删除排序链表中的重复元素 7 | * 给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。 8 | *

9 | * 示例 1: 10 | *

11 | * 输入: 1->1->2 12 | * 输出: 1->2 13 | * 示例 2: 14 | *

15 | * 输入: 1->1->2->3->3 16 | * 输出: 1->2->3 17 | * @author: icecrea 18 | * @create: 2018-12-25 13:17 19 | **/ 20 | public class LeetCode83_RemoveDuplicatesFromSortedList { 21 | public ListNode deleteDuplicates(ListNode head) { 22 | ListNode cur = head; 23 | while (cur != null && cur.next != null) { 24 | if (cur.val == cur.next.val) { 25 | cur.next = cur.next.next; 26 | } else { 27 | cur = cur.next; 28 | } 29 | } 30 | return head; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/LeetCode876_MiddleOfTheLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 链表中间节点 7 | * 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。 8 | *

9 | * 如果有两个中间结点,则返回第二个中间结点。 10 | *

11 | * 示例 1: 12 | *

13 | * 输入:[1,2,3,4,5] 14 | * 输出:此列表中的结点 3 (序列化形式:[3,4,5]) 15 | * 返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。 16 | * 注意,我们返回了一个 ListNode 类型的对象 ans,这样: 17 | * ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL. 18 | * 示例 2: 19 | *

20 | * 输入:[1,2,3,4,5,6] 21 | * 输出:此列表中的结点 4 (序列化形式:[4,5,6]) 22 | * 由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。 23 | * @author: icecrea 24 | * @create: 2018-12-25 13:06 25 | **/ 26 | public class LeetCode876_MiddleOfTheLinkedList { 27 | 28 | public ListNode middleNode(ListNode head) { 29 | ListNode fast = head; 30 | ListNode low = head; 31 | while (fast != null && fast.next != null) { 32 | fast = fast.next.next; 33 | low = low.next; 34 | } 35 | return low; 36 | } 37 | 38 | public ListNode middleNode2(ListNode head) { 39 | ListNode[] A = new ListNode[100]; 40 | int t = 0; 41 | while (head.next != null) { 42 | A[t++] = head; 43 | head = head.next; 44 | } 45 | return A[t / 2]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/README.md: -------------------------------------------------------------------------------- 1 | ## LeetCode链表类型题目 2 | 3 | - [02.两数相加](./LeetCode02_AddTwoNumbers.java) 4 | - [19.删除链表的倒数第N个节点](./LeetCode19_RemoveNthNodeFromEnd.java) 5 | - [21.合并两个有序链表](./LeetCode21_MergeTwoSortedLists.java) 6 | - [23.合并k个排序链表](./LeetCode23_MergeKSortedLists.java) 7 | - [24.两两交换链表中的节点](./LeetCode24_SwapNodesInPairs.java) 8 | - [61.旋转链表](./LeetCode61_RotateList.java) 9 | - [82.删除排序链表中的重复元素2](./LeetCode82_RemoveDuplicatesFromSortedList2.java) 10 | - [83.删除排序链表中的重复元素](./LeetCode83_RemoveDuplicatesFromSortedList.java) 11 | - [86.分隔链表](./LeetCode86_PartitionList.java) 12 | - [92.反转链表2](./LeetCode92_ReverseLinkedList2.java) 13 | - [109.有序链表转换二叉搜索树](./LeetCode109_ConvertSortedListToBinarySearchTree.java) 14 | - [138.复制带随机指针的链表](./LeetCode138_CopyListWithRandomPointer.java) 15 | - [141.环形链表](./LeetCode141_LinkedListCycle.java) 16 | - [142.环形链表2](./LeetCode142_LinkedListCycle2.java) 17 | - [143.重排链表](./LeetCode143_ReorderList.java) 18 | - [147.对链表进行插入排序](./LeetCode147_InsertionSortList.java) 19 | - [148.排序链表](./LeetCode148_SortList.java) 20 | - [160.相交链表](./LeetCode160_IntersectionOfTwoLists.java) 21 | - [203.移除链表元素](./LeetCode203_RemoveLinkedListElements.java) 22 | - [206.反转链表](./LeetCode206_ReverseLinkedList.java) 23 | - [234.回文链表](./LeetCode234_PalindromeLinkedList.java) 24 | - [237.删除链表中的节点](./LeetCode237_DeleteNodeInLinkedList.java) 25 | - [328.奇偶链表](./LeetCode328_OddEvenLinkedList.java) 26 | - [445.两数相加2](./LeetCode445_AddTwoNumbers2.java) 27 | - [725.分隔链表](./LeetCode725_SplitLinkedListInParts.java) 28 | - [876.链表中间节点](./LeetCode876_MiddleOfTheLinkedList.java) -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/pojo/ListNode.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist.pojo; 2 | 3 | /** 4 | * @description: 方便起见,设置Public 5 | * @author: icecrea 6 | * @create: 2018-12-18 17:44 7 | **/ 8 | public class ListNode { 9 | public int val; 10 | public ListNode next; 11 | 12 | public ListNode(int x) { 13 | val = x; 14 | next = null; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/pojo/RandomListNode.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist.pojo; 2 | 3 | /** 4 | * @description: 5 | * @author: icecrea 6 | * @create: 2019-01-10 11:21 7 | **/ 8 | public class RandomListNode { 9 | public int label; 10 | public RandomListNode next, random; 11 | 12 | public RandomListNode(int x) { 13 | this.label = x; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/linkedlist/pojo/TreeNode.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.linkedlist.pojo; 2 | 3 | /** 4 | * @description: 5 | * @author: icecrea 6 | * @create: 2019-01-08 20:29 7 | **/ 8 | public class TreeNode { 9 | public int val; 10 | public TreeNode left; 11 | public TreeNode right; 12 | 13 | public TreeNode(int x) { 14 | val = x; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/other/LeetCode007_ReverseInteger.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.other; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 整数反转 7 | * 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。 8 | * 9 | * 示例 1: 10 | * 11 | * 输入: 123 12 | * 输出: 321 13 | *  示例 2: 14 | * 15 | * 输入: -123 16 | * 输出: -321 17 | * 示例 3: 18 | * 19 | * 输入: 120 20 | * 输出: 21 21 | * 注意: 22 | * 23 | * 假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231,  231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。 24 | * 25 | * 来源:力扣(LeetCode) 26 | * 链接:https://leetcode-cn.com/problems/reverse-integer 27 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 28 | * @author: icecrea 29 | * @create: 2020-05-01 30 | **/ 31 | public class LeetCode007_ReverseInteger { 32 | 33 | public int reverse(int x) { 34 | int ans = 0; 35 | while (x != 0) { 36 | int pop = x % 10; 37 | if (ans > Integer.MAX_VALUE / 10 || (ans == Integer.MAX_VALUE / 10 && pop > Integer.MAX_VALUE % 10)) { 38 | return 0; 39 | } 40 | if (ans < Integer.MIN_VALUE / 10 || (ans == Integer.MIN_VALUE / 10 && pop < Integer.MIN_VALUE % 10)) { 41 | return 0; 42 | } 43 | ans = ans * 10 + pop; 44 | x /= 10; 45 | } 46 | return ans; 47 | } 48 | 49 | @Test 50 | public void test() { 51 | System.out.println(Integer.MAX_VALUE); 52 | System.out.println(Integer.MIN_VALUE % 10); 53 | System.out.println(reverse(-1234)); 54 | System.out.println(-1 / 10); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/other/LeetCode014_LongestCommonPrefix.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.other; 2 | 3 | /** 4 | * @description: 字符串数组最长公共前缀 5 | * 编写一个函数来查找字符串数组中的最长公共前缀。 6 | * 7 | * 如果不存在公共前缀,返回空字符串 ""。 8 | * 9 | * 示例 1: 10 | * 11 | * 输入: ["flower","flow","flight"] 12 | * 输出: "fl" 13 | * 示例 2: 14 | * 15 | * 输入: ["dog","racecar","car"] 16 | * 输出: "" 17 | * 解释: 输入不存在公共前缀。 18 | * 说明: 19 | * 20 | * 所有输入只包含小写字母 a-z 。 21 | * 22 | * 来源:力扣(LeetCode) 23 | * 链接:https://leetcode-cn.com/problems/longest-common-prefix 24 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 25 | * @author: icecrea 26 | * @create: 2020-05-01 27 | **/ 28 | public class LeetCode014_LongestCommonPrefix { 29 | 30 | public String longestCommonPrefix(String[] strs) { 31 | if (strs.length == 0) { 32 | return ""; 33 | } 34 | String ans = strs[0]; 35 | for (int i = 1; i < strs.length; i++) { 36 | int j = 0; 37 | for (; j < ans.length() && j < strs[i].length(); j++) { 38 | if (ans.charAt(j) != strs[i].charAt(j)) { 39 | break; 40 | } 41 | } 42 | ans = ans.substring(0, j); 43 | if (ans.equals("")) { 44 | return ans; 45 | } 46 | } 47 | return ans; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/other/LeetCode038_CountAndSay.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.other; 2 | 3 | /** 4 | * @description: 外观数列 5 | * 6 | * 「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。前五项如下: 7 | * 8 | * 1. 1 9 | * 2. 11 10 | * 3. 21 11 | * 4. 1211 12 | * 5. 111221 13 | * 1 被读作 "one 1" ("一个一") , 即 11。 14 | * 11 被读作 "two 1s" ("两个一"), 即 21。 15 | * 21 被读作 "one 2", "one 1" ("一个二" , "一个一") , 即 1211。 16 | * 17 | * 给定一个正整数 n(1 ≤ n ≤ 30),输出外观数列的第 n 项。 18 | * 19 | * 注意:整数序列中的每一项将表示为一个字符串。 20 | * 21 | * 22 | * 23 | * 示例 1: 24 | * 25 | * 输入: 1 26 | * 输出: "1" 27 | * 解释:这是一个基本样例。 28 | * 示例 2: 29 | * 30 | * 输入: 4 31 | * 输出: "1211" 32 | * 解释:当 n = 3 时,序列是 "21",其中我们有 "2" 和 "1" 两组,"2" 可以读作 "12",也就是出现频次 = 1 而 值 = 2;类似 "1" 可以读作 "11"。所以答案是 "12" 和 "11" 组合在一起,也就是 "1211"。 33 | * @author: icecrea 34 | * @create: 2020-05-01 35 | **/ 36 | public class LeetCode038_CountAndSay { 37 | 38 | public String countAndSay(int n) { 39 | String s = "1"; 40 | int k; 41 | for (int i = 1; i < n; i++) { 42 | StringBuilder t = new StringBuilder(); 43 | for (int j = 0; j < s.length(); j = k) { 44 | k = j; 45 | //找有几个相同的. 46 | while(k < s.length() && s.charAt(k) == s.charAt(j)) { 47 | k++; 48 | } 49 | t.append(k - j).append(s.charAt(j)); 50 | } 51 | s = t.toString(); 52 | } 53 | return s; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/other/LeetCode050_Powx.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.other; 2 | 3 | import com.example.swordoffer.Sword12_Power; 4 | import org.junit.Test; 5 | 6 | /** 7 | * @description: Pow(x, n) 8 | * 实现 pow(x, n) ,即计算 x 的 n 次幂函数。 9 | * 10 | * 示例 1: 11 | * 12 | * 输入: 2.00000, 10 13 | * 输出: 1024.00000 14 | * 示例 2: 15 | * 16 | * 输入: 2.10000, 3 17 | * 输出: 9.26100 18 | * 示例 3: 19 | * 20 | * 输入: 2.00000, -2 21 | * 输出: 0.25000 22 | * 解释: 2-2 = 1/22 = 1/4 = 0.25 23 | * 说明: 24 | * 25 | * -100.0 < x < 100.0 26 | * n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。 27 | * 28 | * 来源:力扣(LeetCode) 29 | * 链接:https://leetcode-cn.com/problems/powx-n 30 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 31 | * @author: icecrea 32 | * @create: 2020-05-03 33 | **/ 34 | public class LeetCode050_Powx { 35 | 36 | /** 37 | * @see Sword12_Power 38 | * 11的二进制是1011 39 | * 11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1 = 2³+2¹+2º 40 | * a¹¹= a^2³ * a ^2¹ * a^2º 41 | */ 42 | public double myPow(double x, int n) { 43 | int sign = n; 44 | double res = 1; 45 | n = Math.abs(n); 46 | while (n != 0) { 47 | if ((n & 1) == 1) {//和1与取末尾 48 | res *= x; 49 | } 50 | x *= x; 51 | n = n >>> 1;//注意此处>>> 52 | } 53 | return sign >= 0 ? res : 1 / res; 54 | } 55 | 56 | @Test 57 | public void test() { 58 | System.out.println(myPow(2.0, -2)); 59 | System.out.println(Math.abs(-2147483648)); 60 | System.out.println(myPow(1.0, -2147483648)); 61 | 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/other/LeetCode059_SpiralMatrix2.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.other; 2 | 3 | /** 4 | * @description: 螺旋矩阵2 5 | * 给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。 6 | * 示例: 7 | * 输入: 3 8 | * 输出: 9 | * [ 10 | * [ 1, 2, 3 ], 11 | * [ 8, 9, 4 ], 12 | * [ 7, 6, 5 ] 13 | * ] 14 | * 来源:力扣(LeetCode) 15 | * 链接:https://leetcode-cn.com/problems/spiral-matrix-ii 16 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 17 | * @author: icecrea 18 | * @create: 2020-05-01 19 | **/ 20 | public class LeetCode059_SpiralMatrix2 { 21 | 22 | public int[][] generateMatrix(int n) { 23 | int left = 0, right = n - 1, top = 0, bottom = n - 1; 24 | int[][] mat = new int[n][n]; 25 | int num = 1, end = n * n; 26 | while (num <= end) { 27 | for (int i = left; i <= right; i++) { 28 | mat[top][i] = num++; // left to right. 29 | } 30 | top++; 31 | for (int i = top; i <= bottom; i++) { 32 | mat[i][right] = num++; // top to bottom. 33 | } 34 | right--; 35 | for (int i = right; i >= left; i--) { 36 | mat[bottom][i] = num++; // right to left. 37 | } 38 | bottom--; 39 | for (int i = bottom; i >= top; i--) { 40 | mat[i][left] = num++; // bottom to top. 41 | } 42 | left++; 43 | } 44 | return mat; 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/other/LeetCode11_ContainerWithMostWater.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.other; 2 | 3 | /** 4 | * @description: 5 | * @author: icecrea 6 | * @create: 2018-12-24 17:48 7 | **/ 8 | public class LeetCode11_ContainerWithMostWater { 9 | 10 | /** 11 | * leetcode 11 盛水最多的容器 12 | * https://leetcode-cn.com/problems/container-with-most-water/ 13 | * 给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。 14 | * 在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。 15 | * 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 16 | *

17 | * 示例 18 | * 输入: [1,8,6,2,5,4,8,3,7] 19 | * 输出: 49 20 | * 21 | * @return 22 | */ 23 | public int maxArea(int[] height) { 24 | int maxarea = 0; 25 | for (int i = 0; i < height.length; i++) { 26 | for (int j = i + 1; j < height.length; j++) { 27 | maxarea = Math.max(maxarea, Math.min(height[i], height[j]) * (j - i)); 28 | } 29 | } 30 | return maxarea; 31 | } 32 | 33 | /** 34 | * 使用两个指针,一个放在开始,一个置于末尾。 35 | * 此外,我们会使用变量 maxareamaxarea 来持续存储到目前为止所获得的最大面积。 36 | * 在每一步中,我们会找出指针所指向的两条线段形成的区域,更新 maxareamaxarea, 37 | * 并将指向较短线段的指针向较长线段那端移动一步。 38 | * 39 | * @param height 40 | * @return 41 | */ 42 | public int maxArea2(int[] height) { 43 | int i = 0; 44 | int j = height.length - 1; 45 | int maxArea = 0; 46 | while (i < j) { 47 | int area = (j - i) * Math.min(height[i], height[j]); 48 | if (area > maxArea) { 49 | maxArea = area; 50 | } 51 | if (height[i] < height[j]) { 52 | i++; 53 | } else { 54 | j--; 55 | } 56 | } 57 | return maxArea; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/other/LeetCode202_HappyNumber.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.other; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | /** 7 | * @description: 快乐数 8 | * 编写一个算法来判断一个数 n 是不是快乐数。 9 | * 10 | * 「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为  1,那么这个数就是快乐数。 11 | * 12 | * 如果 n 是快乐数就返回 True ;不是,则返回 False 。 13 | * 14 | *   15 | * 16 | * 示例: 17 | * 18 | * 输入:19 19 | * 输出:true 20 | * 解释: 21 | * 12 + 92 = 82 22 | * 82 + 22 = 68 23 | * 62 + 82 = 100 24 | * 12 + 02 + 02 = 1 25 | * 26 | * 来源:力扣(LeetCode) 27 | * 链接:https://leetcode-cn.com/problems/happy-number 28 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 29 | * @author: icecrea 30 | * @create: 2020-04-30 31 | **/ 32 | public class LeetCode202_HappyNumber { 33 | 34 | public boolean isHappy(int n) { 35 | Set seen = new HashSet<>(); 36 | //如果陷入无线循环会重复 通过set判断重复 37 | while (n != 1 && !seen.contains(n)) { 38 | seen.add(n); 39 | n = getNext(n); 40 | } 41 | return n == 1; 42 | } 43 | 44 | private int getNext(int n) { 45 | int sum = 0; 46 | while (n != 0) { 47 | int a = n % 10; 48 | sum += a * a; 49 | n = n / 10; 50 | } 51 | return sum; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/other/LeetCode419_LongestPalindrome.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.other; 2 | 3 | /** 4 | * @description: 最长回文串 5 | * 给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。 6 | * 在构造过程中,请注意区分大小写。比如 "Aa" 不能当做一个回文字符串。 7 | * 注意: 8 | * 假设字符串的长度不会超过 1010。 9 | * 示例 1: 10 | * 输入: 11 | * "abccccdd" 12 | * 输出: 13 | * 7 14 | * 解释: 15 | * 我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。 16 | * @auther: icecrea 17 | * @date: 2019/12/16 18 | */ 19 | public class LeetCode419_LongestPalindrome { 20 | 21 | /** 22 | * 常用ascii码: 23 | * a-z:97-122 24 | * A-Z:65-90 25 | * 0-9:48-57 26 | */ 27 | public int longestPalindrome(String s) { 28 | int[] count = new int[128]; 29 | for (char c : s.toCharArray()) { 30 | count[c]++; 31 | } 32 | 33 | int ans = 0; 34 | for (int i : count) { 35 | ans += i / 2 * 2; 36 | //防止重复计算 37 | if (i % 2 == 1 && ans % 2 == 0) { 38 | ans++; 39 | } 40 | } 41 | return ans; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/other/LeetCode703_KthLargestElementStream.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.other; 2 | 3 | import java.util.PriorityQueue; 4 | 5 | /** 6 | * @description: 数据流中的第K大元素 7 | * 设计一个找到数据流中第K大元素的类(class)。注意是排序后的第K大元素,不是第K个不同的元素。 8 | * 9 | * 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中的初始元素。每次调用 KthLargest.add,返回当前数据流中第K大的元素。 10 | * 11 | * 示例: 12 | * 13 | * int k = 3; 14 | * int[] arr = [4,5,8,2]; 15 | * KthLargest kthLargest = new KthLargest(3, arr); 16 | * kthLargest.add(3);   // returns 4 17 | * kthLargest.add(5);   // returns 5 18 | * kthLargest.add(10);  // returns 5 19 | * kthLargest.add(9);   // returns 8 20 | * kthLargest.add(4);   // returns 8 21 | * 说明: 22 | * 你可以假设 nums 的长度≥ k-1 且k ≥ 1。 23 | * @author: icecrea 24 | * @create: 2020-01-03 25 | **/ 26 | public class LeetCode703_KthLargestElementStream { 27 | 28 | int size; 29 | private PriorityQueue q; 30 | 31 | public LeetCode703_KthLargestElementStream(int k, int[] nums) { 32 | size = k; 33 | q = new PriorityQueue(k); 34 | for (int num : nums) { 35 | add(num); 36 | } 37 | } 38 | 39 | public int add(int val) { 40 | if (q.size() < size) { 41 | q.add(val); 42 | } else if (q.peek() < val) { 43 | q.poll(); 44 | q.add(val); 45 | } 46 | return q.peek(); 47 | } 48 | 49 | public static void main(String[] args) { 50 | LeetCode703_KthLargestElementStream main = new LeetCode703_KthLargestElementStream(3, new int[]{4, 5, 8, 2}); 51 | main.add(-1); 52 | main.add(1); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/other/exchangeNumber.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.other; 2 | 3 | /** 4 | * @description: 交换两数 亦或方法 5 | * @auther: icecrea 6 | * @date: 2020/4/23 7 | */ 8 | public class exchangeNumber { 9 | 10 | public static void main(String[] args) { 11 | int a = 3; 12 | int b = 5; 13 | System.out.println("a和b交换前a=" + a + "\tb=" + b); 14 | a = a ^ b; // 此时a的值为a ^ b; 15 | b = a ^ b; // 此时b的值为a ^ b ^ b = a; 16 | a = a ^ b; // 此时a的值为a ^ b ^ a = b; 17 | System.out.println("a和b交换后a=" + a + "\tb=" + b); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/sort/Interval.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.sort; 2 | 3 | /** 4 | * @description: 5 | * @author: icecrea 6 | * @create: 2019-03-25 09:09 7 | **/ 8 | public class Interval { 9 | int start; 10 | int end; 11 | Interval() { start = 0; end = 0; } 12 | Interval(int s, int e) { start = s; end = e; } 13 | 14 | @Override 15 | public String 16 | toString() { 17 | return "Interval{" + 18 | "start=" + start + 19 | ", end=" + end + 20 | '}'; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/sort/LeetCode179_LargestNumber.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.sort; 2 | 3 | import java.util.Arrays; 4 | import java.util.Comparator; 5 | 6 | /** 7 | * @description: 最大数 8 | * 给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。 9 | *

10 | * 示例 1: 11 | *

12 | * 输入: [10,2] 13 | * 输出: 210 14 | * 示例 2: 15 | *

16 | * 输入: [3,30,34,5,9] 17 | * 输出: 9534330 18 | * 说明: 输出结果可能非常大,所以你需要返回一个字符串而不是整数。 19 | * @author: icecrea 20 | * @create: 2019-03-27 10:21 21 | **/ 22 | public class LeetCode179_LargestNumber { 23 | 24 | public String largestNumber(int[] num) { 25 | 26 | if (num == null || num.length == 0) { 27 | return ""; 28 | } 29 | 30 | String[] numStr = new String[num.length]; 31 | for (int i = 0; i < num.length; i++) { 32 | numStr[i] = String.valueOf(num[i]); 33 | } 34 | 35 | Comparator comp = new Comparator() { 36 | @Override 37 | public int compare(String str1, String str2) { 38 | String s1 = str1 + str2; 39 | String s2 = str2 + str1; 40 | return s2.compareTo(s1); 41 | } 42 | }; 43 | 44 | Arrays.sort(numStr, comp); 45 | if (numStr[0].charAt(0) == '0') { 46 | return "0"; 47 | } 48 | 49 | StringBuilder sb = new StringBuilder(); 50 | for (String s : numStr) { 51 | sb.append(s); 52 | } 53 | 54 | return sb.toString(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/sort/LeetCode349_IntersectionOfTwoArrays.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.sort; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashSet; 5 | 6 | /** 7 | * @description: 两个数组交集 8 | * 给定两个数组,编写一个函数来计算它们的交集。 9 | *

10 | * 示例 1: 11 | *

12 | * 输入: nums1 = [1,2,2,1], nums2 = [2,2] 13 | * 输出: [2] 14 | * 示例 2: 15 | *

16 | * 输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4] 17 | * 输出: [9,4] 18 | * 说明: 19 | *

20 | * 输出结果中的每个元素一定是唯一的。 21 | * 我们可以不考虑输出结果的顺序。 22 | * @author: icecrea 23 | * @create: 2019-03-28 09:54 24 | **/ 25 | public class LeetCode349_IntersectionOfTwoArrays { 26 | 27 | public int[] intersection(int[] nums1, int[] nums2) { 28 | HashSet set = new HashSet(); 29 | ArrayList res = new ArrayList(); 30 | for (int i = 0; i < nums1.length; i++) { 31 | set.add(nums1[i]); 32 | } 33 | for (int j = 0; j < nums2.length; j++) { 34 | if (set.contains(nums2[j])) { 35 | res.add(nums2[j]); 36 | set.remove(nums2[j]); 37 | } 38 | } 39 | int[] arr = new int[res.size()]; 40 | for (int i = 0; i < res.size(); i++) { 41 | arr[i] = res.get(i); 42 | } 43 | return arr; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/sort/LeetCode435_NoOverLapIntervals.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.sort; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @description: 无重叠区间 7 | * 给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。 8 | * 注意: 9 | * 可以认为区间的终点总是大于它的起点。 10 | * 区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。 11 | * 示例 1: 12 | * 输入: [ [1,2], [2,3], [3,4], [1,3] ] 13 | * 输出: 1 14 | * 解释: 移除 [1,3] 后,剩下的区间没有重叠。 15 | * 示例 2: 16 | * 输入: [ [1,2], [1,2], [1,2] ] 17 | * 输出: 2 18 | * 解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。 19 | * 示例 3: 20 | * 输入: [ [1,2], [2,3] ] 21 | * 输出: 0 22 | * 解释: 你不需要移除任何区间,因为它们已经是无重叠的了。 23 | * @auther: icecrea 24 | * @date: 2020/4/22 25 | */ 26 | public class LeetCode435_NoOverLapIntervals { 27 | public int eraseOverlapIntervals(List intervals) { 28 | return intervals.size() - intervalSchedule(intervals); 29 | } 30 | 31 | /** 32 | * 求不重叠的区间个数 33 | */ 34 | public int intervalSchedule(List intervals) { 35 | if (intervals.size() == 0) { 36 | return 0; 37 | } 38 | // 按 end 升序排序 39 | intervals.sort((i1, i2) -> Integer.compare(i1.end, i2.end)); 40 | // 至少有一个区间不相交 41 | int count = 1; 42 | // 排序后,第一个区间就是 x 43 | int xEnd = intervals.get(0).end; 44 | for (Interval interval : intervals) { 45 | int start = interval.start; 46 | if (start >= xEnd) { 47 | // 找到下一个选择的区间了 48 | count++; 49 | xEnd = interval.end; 50 | } 51 | } 52 | return count; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/sort/LeetCode976_LargestTriangle.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.sort; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * @description: 三角形最大周长 7 | * 给定由一些正数(代表长度)组成的数组 A,返回由其中三个长度组成的、面积不为零的三角形的最大周长。 8 | *

9 | * 如果不能形成任何面积不为零的三角形,返回 0。 10 | *

11 | *

12 | *

13 | * 示例 1: 14 | *

15 | * 输入:[2,1,2] 16 | * 输出:5 17 | * 示例 2: 18 | *

19 | * 输入:[1,2,1] 20 | * 输出:0 21 | * 示例 3: 22 | *

23 | * 输入:[3,2,3,4] 24 | * 输出:10 25 | * 示例 4: 26 | *

27 | * 输入:[3,6,2,3] 28 | * 输出:8 29 | *

30 | *

31 | * 提示: 32 | *

33 | * 3 <= A.length <= 10000 34 | * 1 <= A[i] <= 10^6 35 | * @author: icecrea 36 | * @create: 2019-04-02 10:08 37 | **/ 38 | public class LeetCode976_LargestTriangle { 39 | 40 | /** 41 | * 排序之后从后往前 尽量找最大 42 | * @param A 43 | * @return 44 | */ 45 | public int largestPerimeter(int[] A) { 46 | Arrays.sort(A); 47 | for (int i = A.length - 3; i >= 0; --i) { 48 | if (A[i] + A[i + 1] > A[i + 2]) { 49 | return A[i] + A[i + 1] + A[i + 2]; 50 | } 51 | } 52 | return 0; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/sort/README.md: -------------------------------------------------------------------------------- 1 | ## 排序专题 2 | 3 | - [56.合并区间](./LeetCode56_MergeIntervals.java) 4 | - [57.插入区间](./LeetCode57_InsertInterval.java) 5 | - [75.颜色分类](./LeetCode75_SortColors.java) 6 | - [147.链表插入排序](./LeetCode147_InsertionSortList.java) 7 | - [148.排序链表](./LeetCode148_SortList.java) 8 | - [164.最大间距](./LeetCode164_MaximumGap.java) 9 | - [179.最大数](./LeetCode179_LargestNumber.java) 10 | - [215.数组中第K个最大元素](./LeetCode215_KthLargestElementInAnArray.java) 11 | - [274.H指数](./LeetCode274_HIndex.java) 12 | - [324.摆动排序2](./LeetCode324_WiggleSort2.java) 13 | - [349.两个数组交集](./LeetCode349_IntersectionOfTwoArrays.java) 14 | - [524.通过删除字母匹配到字典里最长单词](./LeetCode524_LongestWordInDictionaryThroughDeleting.java) 15 | - [710.黑名单中随机数](./LeetCode710_RandomPickWithBlackList.java) 16 | - [767.重构字符串](./LeetCode767_ReorganizeString.java) 17 | - [922.按奇偶排序数组2](./LeetCode922_sortArrayByParity2.java) 18 | - [969.煎饼排序](./LeetCode969_PancakeSorting.java) 19 | - [973.最接近原点的K个点](./LeetCode973_KClosestPointsToOrigin.java) 20 | - [976.三角形最大周长](./LeetCode976_LargestTriangle.java) -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/sort/SortStackByStack.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.sort; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Stack; 6 | 7 | /** 8 | * @description: 用一个栈排序另一个栈 9 | * @auther: icecrea 10 | * @date: 2020/4/24 11 | */ 12 | public class SortStackByStack { 13 | public static void sortStackByStack(Stack stack) { 14 | //辅助数组 15 | Stack help = new Stack<>(); 16 | while (!stack.isEmpty()) { 17 | int cur = stack.pop(); 18 | //如果数据栈顶的元素比help栈顶元素小,那么直接压入,否则,选择合适的位置压入 19 | while (!help.isEmpty() && cur > help.peek()) { 20 | stack.push(help.pop()); 21 | } 22 | help.push(cur); 23 | } 24 | //此时数据栈为空,辅助栈是逆序的,将辅助栈依次弹出,压入到数据栈中 25 | while (!help.isEmpty()) { 26 | stack.push(help.pop()); 27 | } 28 | } 29 | 30 | @Test 31 | public void test() { 32 | // 3 7 33 | // 34 22 7 3 34 | // 3 7 22 34 35 | Stack stack = new Stack<>(); 36 | stack.push(3); 37 | stack.push(7); 38 | stack.push(34); 39 | stack.push(22); 40 | sortStackByStack(stack); 41 | while (!stack.isEmpty()){ 42 | System.out.println(stack.pop()); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/example/leetcode/sort/package-info.java: -------------------------------------------------------------------------------- 1 | package com.example.leetcode.sort; 2 | 3 | /** 4 | * https://leetcode-cn.com/tag/sort/ 5 | * leetcode 题库 排序类型题 6 | */ 7 | -------------------------------------------------------------------------------- /src/main/java/com/example/summary/DP.java: -------------------------------------------------------------------------------- 1 | package com.example.summary; 2 | 3 | import com.example.leetcode.dp.*; 4 | 5 | /** 6 | * @description: dp问题总结 7 | * @auther: icecrea 8 | * @date: 2020/4/29 9 | */ 10 | public class DP { 11 | 12 | /** 13 | * @see Knapsack 01背包问题 14 | * @see LeetCode10_RegularExpressionMatching 正则表达式匹配 15 | * @see LeetCode72_EditDistance 编辑距离 16 | * @see LeetCode300_LIS 最长上升子序列 17 | * @see LeetCode1143_LCS 最长公共子序列 18 | * @see LeetCode322_CoinChange 零钱兑换 19 | * @see LeetCode32_LongestValidParantheses 最长有效括号 20 | * @see LeetCode85_MaximalRectangle 最大矩形 TODO 难 21 | * @see LeetCode45_JumpGame2 跳跃游戏1,2 22 | * @see LeetCode53_MaximumSubarray 最大连续子序列和 23 | * 24 | * 25 | * 系列: 26 | * 打家劫舍 27 | * 股票问题 28 | * 29 | */ 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/example/summary/SlidingWindow.java: -------------------------------------------------------------------------------- 1 | package com.example.summary; 2 | 3 | import com.example.leetcode.slidingwindow.*; 4 | import com.example.swordoffer.Sword64_MaxInWindow; 5 | 6 | /** 7 | * @description: 滑动窗口总结 8 | * @auther: icecrea 9 | * @date: 2020/4/29 10 | */ 11 | public class SlidingWindow { 12 | 13 | /** 14 | * @see LeetCode438_FindAllAnagrams 找所有的字母异位词 15 | * @see LeetCode480_SlidingWindowMedian 滑动窗口中位数 16 | * @see Sword64_MaxInWindow 滑动窗口最大值 17 | * @see LeetCode567_PermutationInString 字符串a是否包含字符串b的排列 18 | * @see LeetCode003_LongestSubstringWithouRepeat 最长无重复子串 19 | * @see LeetCode076_MinWindowSubStr 最小覆盖子串 20 | * 21 | */ 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/example/summary/sortalgorithm/BubbleSort.java: -------------------------------------------------------------------------------- 1 | package com.example.summary.sortalgorithm; 2 | 3 | /** 4 | * @description: 冒泡排序 5 | * @author: icecrea 6 | * @create: 2018-12-18 17:42 7 | **/ 8 | public class BubbleSort { 9 | /** 10 | * 核心思路: 11 | * 每一轮依次进行两两比较,将最大的数沉底 12 | * 外圈:因为只剩下一个数时不用再比较,所以共须循环n-1次; 13 | * 内圈:第一圈比较n个数,需要n-1次,最大数沉底,第二圈比较n-1个数,需要n-2次。在第i次排序中,比较次数n-i;总移动次数n(n-1)/2; 14 | * 稳定的排序算法 15 | */ 16 | public static void bubbleSort(int[] a) { 17 | if (a.length <= 1) { 18 | return; 19 | } 20 | 21 | boolean flag = true; 22 | for (int i = 0; i < a.length - 1; i++) { 23 | if (flag == false) { 24 | break; 25 | } 26 | flag = false; 27 | for (int j = 1; j < a.length - i; j++) { 28 | if (a[j] < a[j - 1]) { 29 | int temp = a[j - 1]; 30 | a[j - 1] = a[j]; 31 | a[j] = temp; 32 | flag = true; 33 | } 34 | } 35 | } 36 | } 37 | 38 | 39 | public void bubbleSort(int[] a, int n) { 40 | if (n <= 1) { 41 | return; 42 | } 43 | 44 | for (int i = 0; i < n; ++i) { 45 | // 提前退出冒泡循环的标志位 46 | boolean flag = false; 47 | for (int j = 0; j < n - i - 1; ++j) { 48 | if (a[j] > a[j + 1]) { 49 | int tmp = a[j]; 50 | a[j] = a[j + 1]; 51 | a[j + 1] = tmp; 52 | // 表示有数据交换 53 | flag = true; 54 | } 55 | } 56 | // 没有数据交换,提前退出 57 | if (!flag) { 58 | break; 59 | } 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/example/summary/sortalgorithm/InsertSort.java: -------------------------------------------------------------------------------- 1 | package com.example.summary.sortalgorithm; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 直接插入排序 7 | * @author: icecrea 8 | * @create: 2018-12-18 17:41 9 | **/ 10 | public class InsertSort { 11 | /** 12 | * 核心思路:每次将一条数据插入到有序序列中,将大于该数字的数据统一后移一位,形成新的有序序列。重复到全部有序。(顾名思义) 13 | * 监视哨:无需重复判断数组下标是否越界,将每个a[i]赋给a[0],当比较到0个位置时自动成立退出循环 14 | * 稳定的排序算法 15 | */ 16 | public static void insertionSort(int[] a, int n) { 17 | if (n <= 1) { 18 | return; 19 | } 20 | 21 | for (int i = 1; i < n; ++i) { 22 | int value = a[i]; 23 | int j = i - 1; 24 | // 查找插入的位置 25 | for (; j >= 0; --j) { 26 | if (a[j] > value) { 27 | // 数据移动 28 | a[j + 1] = a[j]; 29 | } else { 30 | break; 31 | } 32 | } 33 | // 插入数据 34 | a[j + 1] = value; 35 | } 36 | } 37 | 38 | 39 | @Test 40 | public void test() { 41 | int a[] = new int[]{5, 1}; 42 | insertionSort(a, a.length); 43 | for (int i : a) { 44 | System.out.println(i); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/example/summary/sortalgorithm/MergeSort.java: -------------------------------------------------------------------------------- 1 | package com.example.summary.sortalgorithm; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 归并排序 7 | * @author: icecrea 8 | * @create: 2018-12-18 17:29 9 | **/ 10 | public class MergeSort { 11 | public static void mergeArray(int[] a, int first, int mid, int last) { 12 | int[] temp = new int[last - first + 1]; 13 | int i = first, j = mid + 1; 14 | int k = 0; 15 | while (i <= mid && j <= last) { 16 | if (a[i] < a[j]) { 17 | temp[k++] = a[i++]; 18 | } else { 19 | temp[k++] = a[j++]; 20 | } 21 | } 22 | while (i <= mid) { 23 | temp[k++] = a[i++]; 24 | } 25 | while (j <= last) { 26 | temp[k++] = a[j++]; 27 | } 28 | for (i = 0; i < k; i++) { 29 | a[first + i] = temp[i]; 30 | } 31 | } 32 | 33 | public static void mergeSort(int[] a, int first, int last) { 34 | if (first >= last) { 35 | return; 36 | } 37 | int mid = first + ((last - first) >> 1); 38 | //左边有序 39 | mergeSort(a, first, mid); 40 | //右边有序 41 | mergeSort(a, mid + 1, last); 42 | //合并两个有序数列 43 | mergeArray(a, first, mid, last); 44 | } 45 | 46 | @Test 47 | public void test() { 48 | int a[] = new int[]{5, 1, 7, 88, 4}; 49 | mergeSort(a, 0, 4); 50 | for (int i : a) { 51 | System.out.println(i); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/example/summary/sortalgorithm/SelectSort.java: -------------------------------------------------------------------------------- 1 | package com.example.summary.sortalgorithm; 2 | 3 | /** 4 | * @description: 直接选择排序 5 | * @author: icecrea 6 | * @create: 2018-12-18 17:38 7 | **/ 8 | public class SelectSort { 9 | /** 10 | * 思路:每一圈比较获得最小值的下标,并付给当前数组的第一位。 11 | * 时间复杂度:外循环n-1次,内圈循环n-1-i次 O(n^2) 12 | * 不稳定的排序算法 13 | */ 14 | public static void selectSort(int[] a) { 15 | for (int i = 0; i < a.length - 1; i++) { 16 | int min = i; 17 | for (int j = i + 1; j < a.length; j++) { 18 | if (a[j] < a[min]) { 19 | //找到最小值的下标 20 | min = j; 21 | } 22 | } 23 | if (min != i) { 24 | int temp = a[i]; 25 | a[i] = a[min]; 26 | a[min] = temp; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/example/summary/sortalgorithm/ShellSort.java: -------------------------------------------------------------------------------- 1 | package com.example.summary.sortalgorithm; 2 | 3 | /** 4 | * @description: 希尔排序 5 | * @author: icecrea 6 | * @create: 2018-12-18 17:39 7 | **/ 8 | public class ShellSort { 9 | /** 10 | * 又称缩小增量排序。 11 | * 直接插入排序的优化,利用直接插入排序N较小时效率高与N基本有序时效率高的特点,将数据分组进行直接插入排序。\ 12 | * 不稳定的排序算法 13 | * @param a 14 | */ 15 | public static void shellSort(int[] a) { 16 | int step = a.length / 2; 17 | int i, j; 18 | while (step > 0) { 19 | for (i = step; i < a.length; i++) { 20 | int temp = a[i]; 21 | for (j = i - step; j >= 0 && a[j] > temp; j -= step) { 22 | a[j + step] = a[j]; 23 | } 24 | a[j + step] = temp; 25 | } 26 | step = step / 2; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/example/summary/sortalgorithm/排序算法.md: -------------------------------------------------------------------------------- 1 | ## 分析排序算法: 2 | 3 | #### - 排序算法执行效率 4 | 1. 最好,最坏,平均时间复杂度 5 | 2. 时间复杂度的系数,常数,低阶 6 | 3. 比较和交换(或移动)次数 7 | 8 | #### - 排序算法内存消耗 9 | #### - 排序算法稳定性 10 | 举例: 一批订单要按金额排序,同时相同金额按时间排序。 11 | 可以通过先按时间排序,再用稳定排序算法对金额排序,此时时间依然是有序的。 12 | 13 | TODO 平均时间复杂度分析方法 14 | TODO 归并排序时间复杂度分析 15 | 16 |

  • 冒泡排序: 原地排序,稳定排序(相邻元素大小相等时不交换),最好O(N),最坏O(N^2),平均O(N^2) 17 |
  • 插入排序: 原地排序,稳定排序(可以将后面出现的元素,插入到前面出现元素的后面),最好O(N),最坏O(N^2),平均O(N^2) 18 |
  • 选择排序: 原地排序,不稳定排序(每次查找剩余未排序元素最小值和前面元素交换位置,破坏稳定性),最好、最坏、平均O(N^2) 19 |
  • 归并排序: 非原地排序(空间O(N)),稳定排序(子数组合并时候,将p~q的放前面,q+1~r放后面),最好、最坏、平均O(NLog(N)) 20 |
  • 快速排序: 原地排序,稳定排序(子数组合并时候,将p~q的放前面,q+1~r放后面),最好O(NLog(N))、最坏O(N^2、平均O(NLog(N)) 21 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword02_ReplaceSpace.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | /** 4 | * @description: 替换空格 5 | * 请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy. 6 | * 则经过替换之后的字符串为We%20Are%20Happy。 7 | * @author: icecrea 8 | * @create: 2019-04-17 11:34 9 | **/ 10 | public class Sword02_ReplaceSpace { 11 | 12 | 13 | /** 14 | * 从后往前替换,减少移动次数 15 | * @param str 16 | * @return 17 | */ 18 | public String replaceSpace(StringBuffer str) { 19 | int spacenum = 0; 20 | for (int i = 0; i < str.length(); i++) { 21 | if (str.charAt(i) == ' ') { 22 | spacenum++; 23 | } 24 | } 25 | int indexold = str.length() - 1; 26 | int newlength = str.length() + spacenum * 2; 27 | int indexnew = newlength - 1; 28 | str.setLength(newlength); 29 | for (; indexold >= 0 ; --indexold) { 30 | if (str.charAt(indexold) == ' ') { 31 | str.setCharAt(indexnew--, '0'); 32 | str.setCharAt(indexnew--, '2'); 33 | str.setCharAt(indexnew--, '%'); 34 | } else { 35 | str.setCharAt(indexnew--, str.charAt(indexold)); 36 | } 37 | } 38 | return str.toString(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword03_printLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Stack; 7 | 8 | /** 9 | * @description: 打印链表 10 | * 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。 11 | * @author: icecrea 12 | * @create: 2019-04-17 11:46 13 | **/ 14 | public class Sword03_printLinkedList { 15 | 16 | public ArrayList printListFromTailToHead(ListNode listNode) { 17 | Stack stack = new Stack<>(); 18 | while (listNode!=null){ 19 | stack.push(listNode.val); 20 | listNode= listNode.next; 21 | } 22 | ArrayList list = new ArrayList(); 23 | while (!stack.empty()){ 24 | list.add(stack.pop()); 25 | } 26 | return list; 27 | } 28 | 29 | /** 30 | * 递归 31 | * @param listNode 32 | * @return 33 | */ 34 | public ArrayList printListFromTailToHeadRecur(ListNode listNode) { 35 | return recur(listNode); 36 | } 37 | 38 | public ArrayList recur(ListNode node){ 39 | if(node == null){ 40 | return new ArrayList(); 41 | } 42 | ArrayList recur = recur(node.next); 43 | recur.add(node.val); 44 | return recur; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword05_QueuingWithTwoStacks.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * @description: 用两个栈实现队列 7 | * 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。 8 | * @author: icecrea 9 | * @create: 2019-04-17 13:09 10 | **/ 11 | public class Sword05_QueuingWithTwoStacks { 12 | 13 | Stack stack1 = new Stack(); 14 | Stack stack2 = new Stack(); 15 | 16 | /** 17 | * 用例: 18 | * ["PSH1","PSH2","PSH3","POP","POP","PSH4","POP","PSH5","POP","POP"] 19 | *

    20 | * 对应输出应该为: 21 | *

    22 | * 1,2,3,4,5 23 | * 24 | * 25 | * 26 | * @param node 27 | */ 28 | public void push(int node) { 29 | stack1.push(node); 30 | } 31 | 32 | public int pop() { 33 | //当stack2为空时,一次压入stack1中全部全元素。 即栈1每次出栈时,弹出所有元素 34 | if (stack2.empty()) { 35 | while (!stack1.empty()) { 36 | stack2.push(stack1.pop()); 37 | } 38 | } 39 | //不为空时,弹出栈顶元素 40 | return stack2.pop(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword07_Fibonacci.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | /** 4 | * @description:斐波那契数列 5 | * 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。n<=39 6 | * @author: icecrea 7 | * @create: 2019-04-17 23:54 8 | **/ 9 | public class Sword07_Fibonacci { 10 | 11 | public int Fibonacci(int n) { 12 | if (n == 0) { 13 | return 0; 14 | } 15 | int[] a = new int[n + 1]; 16 | a[0] = 0; 17 | a[1] = 1; 18 | for (int i = 2; i <= n; i++) { 19 | a[i] = a[i - 1] + a[i - 2]; 20 | } 21 | return a[n]; 22 | } 23 | 24 | public int Fibonacci2(int n) { 25 | if (n == 1) { 26 | return 1; 27 | } 28 | int p = 0; 29 | int q = 1; 30 | int ans = 0; 31 | for (int i = 2; i <= n; i++) { 32 | ans = p + q; 33 | p = q; 34 | q = ans; 35 | } 36 | return ans; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword08_JumpFloor.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | /** 4 | * @description: 青蛙跳台阶 5 | * 一只青蛙一次可以跳上1级台阶,也可以跳上2级。 6 | * 求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。 7 | * @author: icecrea 8 | * @create: 2019-04-18 00:10 9 | **/ 10 | public class Sword08_JumpFloor { 11 | public int JumpFloor(int target) { 12 | if (target == 1) { 13 | return 1; 14 | } 15 | if (target == 2) { 16 | return 2; 17 | } 18 | return JumpFloor(target - 1) + JumpFloor(target - 2); 19 | } 20 | 21 | public int JumpFloor2(int target) { 22 | if (target == 1) { 23 | return 1; 24 | } 25 | if (target == 2) { 26 | return 2; 27 | } 28 | int p = 1; 29 | int q = 2; 30 | int sum = 0; 31 | for (int i = 3; i <= target; i++) { 32 | sum = p + q; 33 | p = q; 34 | q = sum; 35 | } 36 | return sum; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword09_JumpFloorII.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | /** 4 | * @description: 变态跳台阶 5 | * 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 6 | * @author: icecrea 7 | * @create: 2019-04-18 00:15 8 | **/ 9 | public class Sword09_JumpFloorII { 10 | /** 11 | * 1 1 1 12 | * 2 2 11/2 13 | * 3 4 111/21/12/3 14 | * 4 8 1111/121/211/112/31/13/4/22 15 | * 5 16 11111/1112/1121/1211/2111/311/131/113/14/41/5/221/122/212/32/23 16 | *

    17 | *

    18 | *

    19 | *

    20 | * 因为n级台阶,第一步有n种跳法:跳1级、跳2级、到跳n级 21 | * 跳1级,剩下n-1级,则剩下跳法是f(n-1) 22 | * 跳2级,剩下n-2级,则剩下跳法是f(n-2) 23 | * 所以f(n)=f(n-1)+f(n-2)+...+f(1) 24 | * 因为f(n-1)=f(n-2)+f(n-3)+...+f(1) 25 | * 所以f(n)=2*f(n-1) 26 | * 27 | * @param target 28 | * @return 29 | */ 30 | public int JumpFloorII(int target) { 31 | return 1 << (target - 1); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword10_RectCover.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | /** 4 | * @description: 矩形覆盖 5 | * 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。 6 | * 请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 7 | * @author: icecrea 8 | * @create: 2019-04-18 00:42 9 | **/ 10 | public class Sword10_RectCover { 11 | 12 | /** 13 | * 1 1 14 | * 2 2 15 | * 3 3 16 | * 4 5 17 | * target = 1大矩形为2*1,只有一种摆放方法,return1; 18 | * target = 2 大矩形为2*2,有两种摆放方法,return2; 19 | * target = n 分为两步考虑: 20 | * 1.第一次摆放一块 2*1 的小矩阵,则摆放方法总共为f(target - 1) 21 | * 2.第一次摆放一块1*2的小矩阵,则摆放方法总共为f(target-2) 22 | * 23 | * @param target 24 | * @return 25 | */ 26 | public int RectCover(int target) { 27 | if (target == 1) { 28 | return 1; 29 | } 30 | if (target == 2) { 31 | return 2; 32 | } 33 | int p = 1; 34 | int q = 2; 35 | int sum = 0; 36 | for (int i = 3; i <= target; i++) { 37 | sum = p + q; 38 | p = q; 39 | q = sum; 40 | } 41 | return sum; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword11_NumberOf1.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | /** 4 | * @description: 二进制中1的个数 5 | * 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。 6 | * @author: icecrea 7 | * @create: 2019-04-18 09:02 8 | **/ 9 | public class Sword11_NumberOf1 { 10 | 11 | public int NumberOf1(int n) { 12 | int size = 0; 13 | while (n != 0) { 14 | size += n & 1; 15 | n = n >>> 1; 16 | } 17 | return size; 18 | } 19 | 20 | 21 | /** 22 | * 如果一个整数不为0,那么这个整数至少有一位是1(二进制)。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0, 23 | * 原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。 24 | * 举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1 25 | * ,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。 26 | * 这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。 27 | * 如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0. 28 | * 那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。 29 | * 30 | * @param n 31 | * @return 32 | */ 33 | public int NumberOf1II(int n) { 34 | int count = 0; 35 | while (n != 0) { 36 | count++; 37 | n = n & (n - 1); 38 | } 39 | return count; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword12_Power.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | /** 4 | * @description: 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 5 | * @author: icecrea 6 | * @create: 2019-04-18 09:03 7 | **/ 8 | public class Sword12_Power { 9 | public double Power(double base, int exponent) { 10 | double result = 1; 11 | for (int i = 0; i < Math.abs(exponent); i++) { 12 | result *= base; 13 | } 14 | if (exponent < 0) { 15 | result = 1 / result; 16 | } 17 | return result; 18 | } 19 | 20 | 21 | /** 22 | * 2^11 = 2^1 * 2^2 * 2^8 23 | * 2^1011 = 2^0001 * 2^0010 * 2^1000 24 | *

    25 | * 写出指数的二进制表达,例如13表达为二进制1101。 26 | * 举例:10^1101 = 10^0001* 10^0100 * 10^1000。 27 | * 通过&1和>>1来逐位读取1101,为1时将该位代表的乘数累乘到最终结果。 28 | */ 29 | public double Power2(double base, int n) { 30 | double res = 1; 31 | int exponent; 32 | if (n > 0) { 33 | exponent = n; 34 | } else if (n < 0) { 35 | exponent = -n; 36 | } else { 37 | // 0次方 38 | return 1; 39 | } 40 | 41 | while (exponent != 0) { 42 | if ((exponent & 1) == 1) { 43 | res *= base; 44 | } 45 | // 翻倍 46 | base *= base; 47 | // 右移一位 48 | exponent >>= 1; 49 | } 50 | return n >= 0 ? res : (1 / res); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword14_FindKthToTail.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 链表中倒数第k个节点 7 | * 输入一个链表,输出该链表中倒数第k个结点。 8 | * @author: icecrea 9 | * @create: 2019-04-18 13:26 10 | **/ 11 | public class Sword14_FindKthToTail { 12 | 13 | /** 14 | * 用例: 15 | * 6,{1,2,3,4,5} 16 | *

    17 | * 对应输出应该为: 18 | *

    19 | * {} 20 | *

    21 | * 你的输出为: 22 | *

    23 | * {1,2,3,4,5} 24 | * 25 | * @param head 26 | * @param k 27 | * @return 28 | */ 29 | public ListNode FindKthToTail(ListNode head, int k) { 30 | int len = 0; 31 | ListNode cur = head; 32 | while (cur != null) { 33 | len++; 34 | cur = cur.next; 35 | } 36 | if (len < k) { 37 | return null; 38 | } 39 | for (int i = 0; i < len - k; i++) { 40 | head = head.next; 41 | } 42 | return head; 43 | } 44 | 45 | /** 46 | * 倒数第k个订单,快指针先走k-1步 47 | * 注意终止条件是 fast.next !=null 48 | * 49 | * @param head 50 | * @param k 51 | * @return 52 | */ 53 | public ListNode FindKthToTail2(ListNode head, int k) { 54 | if (head == null || k <= 0) { 55 | return null; 56 | } 57 | ListNode fast = head; 58 | ListNode slow = head; 59 | for (int i = 0; i < k - 1; i++) { 60 | if (fast.next != null) { 61 | fast = fast.next; 62 | } else { 63 | return null; 64 | } 65 | } 66 | while (fast.next != null) { 67 | fast = fast.next; 68 | slow = slow.next; 69 | } 70 | return slow; 71 | } 72 | 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword15_ReverseList.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 反转链表 7 | * 输入一个链表,反转链表后,输出新链表的表头。 8 | * @author: icecrea 9 | * @create: 2019-04-18 18:39 10 | **/ 11 | public class Sword15_ReverseList { 12 | public ListNode ReverseList(ListNode head) { 13 | ListNode pre = null; 14 | ListNode next; 15 | while (head != null) { 16 | next = head.next; 17 | head.next = pre; 18 | pre = head; 19 | head = next; 20 | } 21 | return pre; 22 | } 23 | 24 | private ListNode reverse(ListNode head) { 25 | //递归终止条件: 找到链表最后一个节点 注意空链表 26 | if (head == null || head.next == null) { 27 | return head; 28 | } 29 | ListNode newNode = reverse(head.next); 30 | head.next.next = head; 31 | //反转头节点的next指针,将头节点作为尾节点 32 | head.next = null; 33 | return newNode; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword16_MergeSortedLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 合并两个排序的链表 7 | * @author: icecrea 8 | * @create: 2019-11-07 9 | **/ 10 | public class Sword16_MergeSortedLinkedList { 11 | 12 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 13 | ListNode dummy = new ListNode(Integer.MIN_VALUE); 14 | ListNode cur = dummy; 15 | while (l1 != null && l2 != null) { 16 | if (l1.val < l2.val) { 17 | cur.next = l1; 18 | l1 = l1.next; 19 | } else { 20 | cur.next = l2; 21 | l2 = l2.next; 22 | } 23 | cur = cur.next; 24 | } 25 | cur.next = l1 == null ? l2 : l1; 26 | return dummy.next; 27 | } 28 | 29 | 30 | /** 31 | * 合并k个排序链表 分治成n个再2个合并 32 | * @param lists 33 | * @return 34 | */ 35 | public ListNode mergeKLists(ListNode[] lists) { 36 | return partion(lists, 0, lists.length - 1); 37 | } 38 | 39 | public ListNode partion(ListNode[] lists, int start, int end) { 40 | //终止条件 41 | if (start == end) { 42 | return lists[start]; 43 | } 44 | int mid = start + ((end - start) >> 1); 45 | ListNode l1 = partion(lists, start, mid); 46 | ListNode l2 = partion(lists, mid + 1, end); 47 | return mergeTwoLists(l1, l2); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword17_HasSubtree.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import com.example.leetcode.linkedlist.pojo.TreeNode; 4 | 5 | 6 | /** 7 | * @description: 树的子结构 8 | * 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构) 9 | * @author: icecrea 10 | * @create: 2019-04-18 19:25 11 | **/ 12 | public class Sword17_HasSubtree { 13 | 14 | public boolean HasSubtree(TreeNode root1, TreeNode root2) { 15 | boolean result = false; 16 | //当Tree1和Tree2都不为零的时候,才进行比较。否则直接返回false 17 | if (root2 == null || root1 == null) { 18 | return false; 19 | } 20 | //如果找到了对应Tree2的根节点的点 21 | if (root1.val == root2.val) { 22 | //以这个根节点为为起点判断是否包含Tree2 23 | result = isSameTree(root1, root2); 24 | } 25 | //如果找不到,那么就再去root的左儿子当作起点,去判断时候包含Tree2 26 | if (!result) { 27 | result = HasSubtree(root1.left, root2); 28 | } 29 | 30 | //如果还找不到,那么就再去root的右儿子当作起点,去判断时候包含Tree2 31 | if (!result) { 32 | result = HasSubtree(root1.right, root2); 33 | } 34 | //返回结果 35 | return result; 36 | } 37 | 38 | /** 39 | * 比较两颗树是否完全相同 40 | */ 41 | public boolean isSameTree(TreeNode root1, TreeNode root2) { 42 | // 都为空的话,显然相同 43 | if (root1 == null && root2 == null) { 44 | return true; 45 | } 46 | // 一个为空,一个非空,显然不同 47 | if (root1 == null || root2 == null) { 48 | return false; 49 | } 50 | // 两个都非空,但 val 不一样也不行 51 | if (root1.val != root2.val) { 52 | return false; 53 | } 54 | // root1 和 root2 该比的都比完了 55 | return isSameTree(root1.left, root2.left) && isSameTree(root1.right, root2.right); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword20_StackWithMin.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * @description: 包含Min的栈 7 | * 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。 8 | * @author: icecrea 9 | * @create: 2019-04-18 23:37 10 | **/ 11 | public class Sword20_StackWithMin { 12 | 13 | /** 14 | * 注意需要初始化 15 | */ 16 | private Stack stack = new Stack<>(); 17 | 18 | private Stack stackMin = new Stack<>(); 19 | 20 | public void push(int node) { 21 | stack.push(node); 22 | if (stackMin.empty()) { 23 | stackMin.push(node); 24 | } else if (stackMin.peek() >= node) { 25 | stackMin.push(node); 26 | } 27 | } 28 | 29 | public void pop() { 30 | if(stackMin.peek().equals(stack.peek())) { 31 | stackMin.pop(); 32 | } 33 | stack.pop(); 34 | } 35 | 36 | public int top() { 37 | return stack.peek(); 38 | } 39 | 40 | public int min() { 41 | return stackMin.peek(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword21_IsPopOrder.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * @description: 栈的压入、弹出序列 7 | * 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。 8 | * 例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列, 9 | * 但4,3,5,1,2 就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的) 10 | * @author: icecrea 11 | * @create: 2019-04-19 12:58 12 | **/ 13 | public class Sword21_IsPopOrder { 14 | 15 | public boolean IsPopOrder(int[] pushA, int[] popA) { 16 | if (pushA.length == 0 || popA.length == 0) { 17 | return false; 18 | } 19 | Stack s = new Stack<>(); 20 | //用于标识弹出序列的位置 21 | int popIndex = 0; 22 | for (int i = 0; i < pushA.length; i++) { 23 | s.push(pushA[i]); 24 | //如果栈不为空,且栈顶元素等于弹出序列 25 | while (!s.empty() && s.peek() == popA[popIndex]) { 26 | //出栈 27 | s.pop(); 28 | //弹出序列向后一位 29 | popIndex++; 30 | } 31 | } 32 | return s.empty(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword25_Clone.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | /** 4 | * @description: 复杂链表的复制 5 | * 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点), 6 | * 返回结果为复制后复杂链表的head。 7 | * (注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空) 8 | * @author: icecrea 9 | * @create: 2019-04-22 08:32 10 | **/ 11 | public class Sword25_Clone { 12 | public RandomListNode Clone(RandomListNode pHead) { 13 | if (pHead == null) { 14 | return null; 15 | } 16 | 17 | RandomListNode cur = pHead; 18 | //1、复制每个结点,如复制结点A得到A1,将结点A1插到结点A后面; 19 | while (cur != null) { 20 | RandomListNode cloneNode = new RandomListNode(cur.label); 21 | RandomListNode nextNode = cur.next; 22 | 23 | cur.next = cloneNode; 24 | cloneNode.next = nextNode; 25 | cur = nextNode; 26 | } 27 | 28 | cur = pHead; 29 | //2、重新遍历链表,复制老结点的随机指针给新结点,如A1.random = A.random.next; (注意是的随机节点=老随机节点下一个) 30 | while (cur != null) { 31 | cur.next.random = cur.random == null ? null : cur.random.next; 32 | cur = cur.next.next; 33 | } 34 | 35 | //3、拆分链表,将链表拆分为原链表和复制后的链表 36 | cur = pHead; 37 | RandomListNode pCloneHead = pHead.next; 38 | while (cur != null) { 39 | RandomListNode cloneNode = cur.next; 40 | cur.next = cloneNode.next; 41 | cloneNode.next = cloneNode.next == null ? null : cloneNode.next.next; 42 | cur = cur.next; 43 | } 44 | 45 | return pCloneHead; 46 | } 47 | } 48 | 49 | class RandomListNode { 50 | int label; 51 | RandomListNode next = null; 52 | RandomListNode random = null; 53 | 54 | RandomListNode(int label) { 55 | this.label = label; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword29_LeastKNumber.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.PriorityQueue; 8 | 9 | /** 10 | * @description: 最小的K个数 11 | * 输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。 12 | * @author: icecrea 13 | * @create: 2019-05-08 14:47 14 | **/ 15 | public class Sword29_LeastKNumber { 16 | 17 | /** 18 | * 维护容量为k的大根堆 19 | * 20 | * @param input 21 | * @param k 22 | * @return 23 | */ 24 | public ArrayList GetLeastNumbers(int[] input, int k) { 25 | ArrayList result = new ArrayList<>(); 26 | int length = input.length; 27 | if (k > length || k == 0) { 28 | return result; 29 | } 30 | PriorityQueue maxHeap = new PriorityQueue<>(k, Collections.reverseOrder()); 31 | for (int i = 0; i < length; i++) { 32 | if (maxHeap.size() != k) { 33 | maxHeap.offer(input[i]); 34 | } else if (maxHeap.peek() > input[i]) { 35 | maxHeap.remove(); 36 | maxHeap.offer(input[i]); 37 | } 38 | } 39 | while (!maxHeap.isEmpty()) { 40 | result.add(maxHeap.remove()); 41 | } 42 | return result; 43 | } 44 | 45 | @Test 46 | public void test() { 47 | ArrayList integers = GetLeastNumbers(new int[]{4, 5, 1, 6, 2, 7, 3, 8}, 4); 48 | System.out.println(integers); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword30_FindGreatestSumOfSubArray.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 连续子数组最大和 7 | * HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中, 8 | * 常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数, 9 | * 并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。 10 | * 给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1) 11 | * @author: icecrea 12 | * @create: 2019-05-08 15:48 13 | **/ 14 | public class Sword30_FindGreatestSumOfSubArray { 15 | 16 | 17 | /** 18 | * arr 6 -3 -2 7 -15 1 2 2 19 | * maxToCur 6 3 1 8 -7 1 3 3 20 | * max 6 6 6 8 8 8 8 8 21 | * maxToCur指的到当前为止的最大数。所以如果上一个最大数小于0,就不用加到当前数的最大值中 22 | * @param array 23 | * @return 24 | */ 25 | public int FindGreatestSumOfSubArray(int[] array) { 26 | //到当前为止的最大数(包括当前数) 27 | int maxToCur = 0; 28 | //最大总数 29 | int max = Integer.MIN_VALUE; 30 | 31 | for (int i = 0; i < array.length; i++) { 32 | if (maxToCur <= 0) { 33 | maxToCur = array[i]; 34 | } else { 35 | maxToCur += array[i]; 36 | } 37 | max = Math.max(max, maxToCur); 38 | } 39 | return max; 40 | } 41 | 42 | @Test 43 | public void test() { 44 | // int i = FindGreatestSumOfSubArray(new int[]{6, -3, -2, 7, -15, 1, 2, 2}); 45 | int i = FindGreatestSumOfSubArray(new int[]{1, -2, 3, 10, -4, 7, 2, -5}); 46 | System.out.println(i); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword32_PrintMinNumber.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.Comparator; 6 | 7 | /** 8 | * @description: 把数组排成最小的数 9 | * 输入一个正整数数组,把数组里所有数字拼接起来排成一个数, 10 | * 打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。 11 | * @author: icecrea 12 | * @create: 2019-05-08 17:24 13 | **/ 14 | public class Sword32_PrintMinNumber { 15 | public String PrintMinNumber(int[] numbers) { 16 | int n; 17 | StringBuilder builder = new StringBuilder(); 18 | ArrayList list = new ArrayList<>(); 19 | n = numbers.length; 20 | for (int i = 0; i < n; i++) { 21 | list.add(numbers[i]); 22 | 23 | } 24 | Collections.sort(list, new Comparator() { 25 | 26 | @Override 27 | public int compare(Integer str1, Integer str2) { 28 | String s1 = str1 + "" + str2; 29 | String s2 = str2 + "" + str1; 30 | return s1.compareTo(s2); 31 | } 32 | }); 33 | 34 | for (int i : list) { 35 | builder.append(i); 36 | } 37 | return builder.toString(); 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword33_UglyNumber.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * @description: 丑数 7 | * 把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数, 8 | * 但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。 9 | * @author: icecrea 10 | * @create: 2019-05-08 17:44 11 | **/ 12 | public class Sword33_UglyNumber { 13 | 14 | int GetUglyNumber_Solution(int n) { 15 | if (n <= 0) { 16 | return 0; 17 | } 18 | ArrayList list = new ArrayList(); 19 | list.add(1); 20 | int i2 = 0, i3 = 0, i5 = 0; 21 | //循环的条件 22 | while (list.size() < n) { 23 | int m2 = list.get(i2) * 2; 24 | int m3 = list.get(i3) * 3; 25 | int m5 = list.get(i5) * 5; 26 | int min = Math.min(m2, Math.min(m3, m5)); 27 | list.add(min); 28 | if (min == m2) { 29 | i2++; 30 | } 31 | if (min == m3) { 32 | i3++; 33 | } 34 | if (min == m5) { 35 | i5++; 36 | } 37 | } 38 | return list.get(list.size() - 1); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword34_FirstNotRepeatChar.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * @description: 第一个只出现一次的字符的位置 7 | * 在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 8 | * 如果没有则返回 -1(需要区分大小写). 9 | * @author: icecrea 10 | * @create: 2019-05-08 17:57 11 | **/ 12 | public class Sword34_FirstNotRepeatChar { 13 | public int FirstNotRepeatingChar(String str) { 14 | HashMap map = new HashMap<>(); 15 | for (int i = 0; i < str.length(); i++) { 16 | if (map.containsKey(str.charAt(i))) { 17 | int time = map.get(str.charAt(i)); 18 | map.put(str.charAt(i), ++time); 19 | } else { 20 | map.put(str.charAt(i), 1); 21 | } 22 | } 23 | int pos = -1; 24 | for (int i = 0; i < str.length(); i++) { 25 | char c = str.charAt(i); 26 | if (map.get(c) == 1) { 27 | return i; 28 | } 29 | } 30 | return pos; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword39_IsBalancedTree.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import com.example.leetcode.linkedlist.pojo.TreeNode; 4 | 5 | /** 6 | * @description: 平衡二叉树 TODO 非递归 7 | * 输入一棵二叉树,判断该二叉树是否是平衡二叉树。 8 | * @author: icecrea 9 | * @create: 2019-05-09 08:54 10 | **/ 11 | public class Sword39_IsBalancedTree { 12 | /** 13 | * 左右子树的高度差绝对值不超过1 14 | * 15 | * @param root 16 | * @return 17 | */ 18 | public boolean IsBalanced_Solution(TreeNode root) { 19 | return getDepth(root) != -1; 20 | } 21 | 22 | private int getDepth(TreeNode root) { 23 | if (root == null) { 24 | return 0; 25 | } 26 | int left = getDepth(root.left); 27 | if (left == -1) { 28 | return -1; 29 | } 30 | int right = getDepth(root.right); 31 | if (right == -1) { 32 | return -1; 33 | } 34 | return Math.abs(left - right) > 1 ? -1 : 1 + Math.max(left, right); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword40_FindNumberAppearOnce.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 数组中只出现一次的数字 7 | * 一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。 8 | * @author: icecrea 9 | * @create: 2019-05-09 09:01 10 | **/ 11 | public class Sword40_FindNumberAppearOnce { 12 | /** 13 | * //num1,num2分别为长度为1的数组。传出参数 14 | * //将num1[0],num2[0]设置为返回结果 15 | *

    16 | * 先全部异或,再按照亦或后某一位不为0,分成两个子数组异或 17 | * [2,4,3,6,3,2,5,5] 18 | * 19 | * @param array 20 | * @param num1 21 | * @param num2 22 | */ 23 | public void FindNumsAppearOnce(int[] array, int num1[], int num2[]) { 24 | int sum = 0; 25 | for (int a : array) { 26 | sum ^= a; 27 | } 28 | int firstBit1 = findFirstBit1(sum); 29 | //按照某一位是不是1来划分成两个数组(保证只出现一次的两个数在两个数组) 30 | for (int i = 0; i < array.length; i++) { 31 | if (isBit1(array[i], firstBit1)) { 32 | num1[0] ^= array[i]; 33 | } else { 34 | num2[0] ^= array[i]; 35 | } 36 | } 37 | } 38 | 39 | public int findFirstBit1(int a) { 40 | int indexBit = 0; 41 | while (((a & 1) == 0) && indexBit < 32) { 42 | a = a >> 1; 43 | ++indexBit; 44 | } 45 | return indexBit; 46 | } 47 | 48 | public boolean isBit1(int num, int indexBit) { 49 | num = num >> indexBit; 50 | return (num & 1) == 1; 51 | } 52 | 53 | @Test 54 | public void test() { 55 | int[] a = new int[]{2, 4, 3, 6, 3, 2, 5, 5}; 56 | int[] num1 = new int[1]; 57 | int[] num2 = new int[1]; 58 | FindNumsAppearOnce(a, num1, num2); 59 | 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword41_ConitunuousSequence.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * @description: 和为S的连续正数序列 7 | * 小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。 8 | * 但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。 9 | * 没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。 10 | * 现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck! 11 | * 输出描述: 12 | * 输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序 13 | * @author: icecrea 14 | * @create: 2019-05-09 13:07 15 | **/ 16 | public class Sword41_ConitunuousSequence { 17 | 18 | public ArrayList> FindContinuousSequence(int sum) { 19 | //存放结果 20 | ArrayList> result = new ArrayList<>(); 21 | //两个起点,相当于动态窗口的两边,根据其窗口内的值的和来确定窗口的位置和大小 22 | int left = 1, right = 2; 23 | //当low指针追上high指针时,退出循环,因为此时永远比Sum大,不可能再找到子序列。如Sum = 15,【[1, 2, 3, 4, 5]、[4, 5, 6]、[7, 8]】 24 | while (right > left) { 25 | //由于是连续的,差为1的一个序列,那么求和公式是(a0+an)*n/2 26 | int cur = (right + left) * (right - left + 1) / 2; 27 | //相等,那么就将窗口范围的所有数添加进结果集 28 | if (cur == sum) { 29 | ArrayList list = new ArrayList<>(); 30 | for (int i = left; i <= right; i++) { 31 | list.add(i); 32 | } 33 | result.add(list); 34 | left++; 35 | //如果当前窗口内的值之和小于sum,那么右边窗口右移一下 36 | } else if (cur < sum) { 37 | right++; 38 | } else { 39 | //如果当前窗口内的值之和大于sum,那么左边窗口右移一下 40 | left++; 41 | } 42 | } 43 | return result; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword42_FindNumbersWithSum.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * @description: 和为S的两个数字 7 | * 输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S, 8 | * 输出两个数的乘积最小的。 9 | * 输出描述: 10 | * 对应每个测试案例,输出两个数,小的先输出。 11 | * @author: icecrea 12 | * @create: 2019-05-09 13:24 13 | **/ 14 | public class Sword42_FindNumbersWithSum { 15 | 16 | public ArrayList FindNumbersWithSum(int[] array, int sum) { 17 | ArrayList list = new ArrayList<>(); 18 | if (array == null || array.length < 2) { 19 | return list; 20 | } 21 | int i = 0, j = array.length - 1; 22 | while (i < j) { 23 | if (array[i] + array[j] == sum) { 24 | list.add(array[i]); 25 | list.add(array[j]); 26 | return list; 27 | } else if (array[i] + array[j] > sum) { 28 | j--; 29 | } else { 30 | i++; 31 | } 32 | 33 | } 34 | return list; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword43_LeftRotateString.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | /** 4 | * @description: 左旋转字符串 5 | * 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。 6 | * 对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。 7 | * 例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它! 8 | * @author: icecrea 9 | * @create: 2019-05-09 23:59 10 | **/ 11 | public class Sword43_LeftRotateString { 12 | 13 | public String LeftRotateString(String str, int n) { 14 | char[] chars = str.toCharArray(); 15 | if (chars.length < n) { 16 | return ""; 17 | } 18 | reverse(chars, 0, n - 1); 19 | reverse(chars, n, chars.length - 1); 20 | reverse(chars, 0, chars.length - 1); 21 | StringBuilder sb = new StringBuilder(); 22 | for (char c : chars) { 23 | sb.append(c); 24 | } 25 | return sb.toString(); 26 | } 27 | 28 | public void reverse(char[] chars, int low, int high) { 29 | char temp; 30 | while (low < high) { 31 | temp = chars[low]; 32 | chars[low] = chars[high]; 33 | chars[high] = temp; 34 | low++; 35 | high--; 36 | } 37 | } 38 | 39 | 40 | public String LeftRotateString2(String str, int n) { 41 | int len = str.length(); 42 | if (len == 0) { 43 | return ""; 44 | } 45 | n = n % len; 46 | str += str; 47 | return str.substring(n, n + len); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword44_ReverseSentence.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | /** 4 | * @description: 反转单词序列 5 | * 牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣, 6 | * 有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到, 7 | * 这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行, 8 | * 你能帮助他么? 9 | * @author: icecrea 10 | * @create: 2019-05-10 00:09 11 | **/ 12 | public class Sword44_ReverseSentence { 13 | 14 | public String ReverseSentence(String str) { 15 | if (str.trim().equals("")) { 16 | return str; 17 | } 18 | String[] a = str.split(" "); 19 | StringBuffer o = new StringBuffer(); 20 | int i; 21 | for (i = a.length; i > 0; i--) { 22 | o.append(a[i - 1]); 23 | if (i > 1) { 24 | o.append(" "); 25 | } 26 | } 27 | return o.toString(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword45_isContinuous.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 扑克牌顺子 7 | * LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。 8 | * @author: icecrea 9 | * @create: 2019-05-21 23:59 10 | **/ 11 | public class Sword45_isContinuous { 12 | 13 | 14 | /** 15 | * 连续满足条件: max -min<5 且 无重复数字 16 | * 17 | * 重复数字可以开辟数组来判断 18 | * 19 | * @param numbers 20 | * @return 21 | */ 22 | public boolean isContinuous(int[] numbers) { 23 | if(numbers == null || numbers.length==0){ 24 | return false; 25 | } 26 | 27 | int[] tmp = new int[14]; 28 | int max = -1; 29 | int min = 14; 30 | //循环找到最大值最小值(0不计入) 31 | for (int number : numbers) { 32 | tmp[number]++; 33 | //忽略0的情况 放在最前面,防止进入判重逻辑 34 | if (number == 0) { 35 | continue; 36 | } 37 | if (tmp[number] > 1) { 38 | return false; 39 | } 40 | if (number > max) { 41 | max = number; 42 | } 43 | if (number < min) { 44 | min = number; 45 | } 46 | } 47 | if (max - min < 5) { 48 | return true; 49 | } 50 | return false; 51 | } 52 | 53 | @Test 54 | public void test(){ 55 | System.out.println(isContinuous(new int[]{1,2,5,0,0})); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword47_Sum.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | /** 4 | * @description: 求1+2+3+...+n 5 | *

    6 | * 求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。 7 | * @author: icecrea 8 | * @create: 2019-09-05 00:11 9 | **/ 10 | public class Sword47_Sum { 11 | 12 | 13 | /** 14 | * 利用短路与的特性,弥补无法使用if else,实现递归的终止条件(n=0的计算) 15 | *

    16 | * 当n=0时候,不执行n += Sum_Solution(n - 1),直接返回0 17 | * 当n>0时,递归执行Sum_Solution 18 | * 19 | * @param n 20 | * @return 21 | */ 22 | int Sum_Solution(int n) { 23 | boolean flag = (n > 0) && ((n += Sum_Solution(n - 1)) > 0); 24 | return n; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword48_Add.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 不用加减乘除做加法 7 | * 写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。 8 | * @author: icecrea 9 | * @create: 2019-11-07 10 | **/ 11 | public class Sword48_Add { 12 | /** 13 | * 1.两个数异或:相当于每一位相加,而不考虑进位; 14 | * 2.两个数相与,并左移一位:相当于求得进位; 15 | * 3.将上述两步的结果相加 16 | */ 17 | public int Add(int num1, int num2) { 18 | while (num2 != 0) { 19 | //求和 20 | int sum = num1 ^ num2; 21 | //求进位 22 | int carray = (num1 & num2) << 1; 23 | num1 = sum; 24 | num2 = carray; 25 | } 26 | return num1; 27 | } 28 | 29 | @Test 30 | public void test() { 31 | int a = 5; 32 | int b = 7; 33 | System.out.println(Add(a, b)); 34 | //circle0: num1 5 num2 7 | 101 111 35 | //circle1: sum 2 carry 10 | 010 1010 36 | //circle2: sum 8 carry 4 | 1000 100 37 | //circle3: sum 12 carry 0 | 1100 0 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword54_FirstAppearingOnce.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | /** 4 | * @description: 字符流中第一个不重复的数字、 5 | *

    6 | * 题目描述 7 | * 请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。 8 | * 输出描述: 9 | * 如果当前字符流没有存在出现一次的字符,返回#字符。 10 | * @author: icecrea 11 | * @create: 2019-09-11 12:57 12 | **/ 13 | public class Sword54_FirstAppearingOnce { 14 | 15 | /** 16 | * 一个字符8位,使用256数组足够 17 | */ 18 | int[] hashtable = new int[256]; 19 | StringBuffer s = new StringBuffer(); 20 | 21 | //Insert one char from stringstream 22 | public void Insert(char ch) { 23 | s.append(ch); 24 | if (hashtable[ch] == 0) { 25 | hashtable[ch] = 1; 26 | } else { 27 | hashtable[ch] += 1; 28 | } 29 | } 30 | 31 | //return the first appearence once char in current stringstream 32 | public char FirstAppearingOnce() { 33 | char[] str = s.toString().toCharArray(); 34 | for (char c : str) { 35 | if (hashtable[c] == 1) { 36 | return c; 37 | } 38 | } 39 | return '#'; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword55_EntryNodeOfLoop.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import com.example.leetcode.linkedlist.LeetCode142_LinkedListCycle2; 4 | import com.example.leetcode.linkedlist.pojo.ListNode; 5 | 6 | /** 7 | * @description: 链表中环的入口结点 8 | * 给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。 9 | * @author: icecrea 10 | * @create: 2019-09-11 12:58 11 | **/ 12 | public class Sword55_EntryNodeOfLoop { 13 | 14 | /** 15 | * 思路参考 LEETCODE142题 16 | * @see LeetCode142_LinkedListCycle2 17 | * @param pHead 18 | * @return 19 | */ 20 | public ListNode EntryNodeOfLoop(ListNode pHead) { 21 | if (pHead == null) { 22 | return null; 23 | } 24 | ListNode fast = pHead; 25 | ListNode slow = pHead; 26 | 27 | boolean isCycle = false; 28 | while (fast.next != null && fast.next.next != null) { 29 | fast = fast.next.next; 30 | slow = slow.next; 31 | if (fast == slow) { 32 | isCycle = true; 33 | break; 34 | } 35 | } 36 | 37 | if (isCycle) { 38 | ListNode p = pHead; 39 | while (p != slow) { 40 | p = p.next; 41 | slow = slow.next; 42 | } 43 | } 44 | 45 | return slow; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword56_DeleteDuplication.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import com.example.leetcode.linkedlist.LeetCode82_RemoveDuplicatesFromSortedList2; 4 | import com.example.leetcode.linkedlist.pojo.ListNode; 5 | 6 | /** 7 | * @description: 删除链表中重复的节点 8 | * 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5 9 | * @author: icecrea 10 | * @create: 2019-09-11 12:58 11 | **/ 12 | public class Sword56_DeleteDuplication { 13 | 14 | /** 15 | * 参考leetcode 82题 16 | * 17 | * @param pHead 18 | * @return 19 | * @see LeetCode82_RemoveDuplicatesFromSortedList2 20 | * 难点在 21 | * 1.多个重复节点的删除 22 | * 2.删除节点前一个指针的保存 23 | *

    24 | * 因为要删除所有重复的元素而并非留一个,所以要考虑头节点删除,留出pre指针,比较后两个大小是否相等 25 | */ 26 | public ListNode deleteDuplication(ListNode pHead) { 27 | ListNode dummy = new ListNode(Integer.MIN_VALUE); 28 | dummy.next = pHead; 29 | ListNode pre = dummy; 30 | //因为要删除所有重复的元素而并非留一个,所以要考虑头节点删除,留出pre指针,比较后两个大小是否相等 31 | while (pre.next != null && pre.next.next != null) { 32 | if (pre.next.val != pre.next.next.val) { 33 | pre = pre.next; 34 | continue; 35 | } else { 36 | ListNode lastSame = pre.next.next; 37 | while (lastSame.next != null && pre.next.val == lastSame.next.val) { 38 | lastSame = lastSame.next; 39 | } 40 | //移动指针指向,不真正移动指针,指针的移动在不同时候 41 | pre.next = lastSame.next; 42 | } 43 | } 44 | return dummy.next; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword57_GetNext.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | /** 4 | * @description: 二叉树中序遍历下一个节点 5 | * 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。 6 | * @author: icecrea 7 | * @create: 2019-09-11 12:59 8 | **/ 9 | public class Sword57_GetNext { 10 | 11 | /** 12 | * A 13 | * B C 14 | * D E F G 15 | * H I 16 | * 思路: 17 | * (1) 若该节点存在右子树:则下一个节点为右子树最左子节点(如图节点 B ) 18 | * (2) 若该节点不存在右子树:这时分两种情况: 19 | * 2.1 该节点为父节点的左子节点,则下一个节点为其父节点(如图节点 D ) 20 | * 2.2 该节点为父节点的右子节点,则沿着父节点向上遍历,直到找到一个节点的父节点的左子节点为该节点,则该节点的父节点下一个节点(如图节点 I ,沿着父节点一直向上查找找到 B ( B 为其父节点的左子节点),则 B 的父节点 A 为下一个节点) 21 | * 22 | * @param node 23 | * @return 24 | */ 25 | public TreeLinkNode GetNext(TreeLinkNode node) { 26 | if (node == null) { 27 | return null; 28 | } 29 | //如果有右子树,则找右子树的最左节点 30 | if (node.right != null) { 31 | node = node.right; 32 | while (node.left != null) { 33 | node = node.left; 34 | } 35 | return node; 36 | } 37 | //没右子树,则找第一个当前节点是父节点左孩子的节点 38 | while (node.next != null) { 39 | if (node.next.left == node) { 40 | return node.next; 41 | } 42 | node = node.next; 43 | } 44 | //退到了根节点仍没找到,则返回null 45 | return null; 46 | } 47 | 48 | public class TreeLinkNode { 49 | int val; 50 | TreeLinkNode left = null; 51 | TreeLinkNode right = null; 52 | TreeLinkNode next = null; 53 | 54 | TreeLinkNode(int val) { 55 | this.val = val; 56 | } 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword61_SerializeTreeNode.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import com.example.leetcode.linkedlist.pojo.TreeNode; 4 | 5 | /** 6 | * @description: 序列化二叉树 7 | * 请实现两个函数,分别用来序列化和反序列化二叉树 8 | * 二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。 9 | * 序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以,表示一个结点值的结束(value,)。 10 | * 二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。 11 | * @author: icecrea 12 | * @create: 2019-09-11 22:47 13 | **/ 14 | public class Sword61_SerializeTreeNode { 15 | public int index = -1; 16 | 17 | String Serialize(TreeNode root) { 18 | StringBuffer sb = new StringBuffer(); 19 | if (root == null) { 20 | sb.append("#,"); 21 | return sb.toString(); 22 | } 23 | sb.append(root.val + ","); 24 | sb.append(Serialize(root.left)); 25 | sb.append(Serialize(root.right)); 26 | return sb.toString(); 27 | } 28 | 29 | TreeNode Deserialize(String str) { 30 | index++; 31 | TreeNode node = null; 32 | String[] strr = str.split(","); 33 | if (!strr[index].equals("#")) { 34 | node = new TreeNode(Integer.valueOf(strr[index])); 35 | node.left = Deserialize(str); 36 | node.right = Deserialize(str); 37 | } 38 | return node; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword66_MovingCount.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 机器人的运动范围 7 | * 地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 8 | * 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子? 9 | * @author: icecrea 10 | * @create: 2019-11-07 11 | **/ 12 | public class Sword66_MovingCount { 13 | public int movingCount(int threshold, int rows, int cols) { 14 | int flag[][] = new int[rows][cols]; 15 | return dfs(0, 0, rows, cols, flag, threshold); 16 | } 17 | 18 | private int dfs(int i, int j, int rows, int cols, int[][] flag, int threshold) { 19 | if (i < 0 || i >= rows || j < 0 || j >= cols || numSum(i) + numSum(j) > threshold || flag[i][j] == 1) { 20 | return 0; 21 | } 22 | flag[i][j] = 1; 23 | return dfs(i - 1, j, rows, cols, flag, threshold) 24 | + dfs(i + 1, j, rows, cols, flag, threshold) 25 | + dfs(i, j - 1, rows, cols, flag, threshold) 26 | + dfs(i, j + 1, rows, cols, flag, threshold) 27 | + 1; 28 | } 29 | 30 | private int numSum(int i) { 31 | int sum = 0; 32 | do { 33 | sum += i % 10; 34 | } while ((i = i / 10) > 0); 35 | return sum; 36 | } 37 | 38 | @Test 39 | public void test() { 40 | System.out.println(movingCount(18, 5, 5)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/example/swordoffer/Sword68_MaxGift.java: -------------------------------------------------------------------------------- 1 | package com.example.swordoffer; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 礼物的最大价值 7 | * (剑指offer题目,牛客网剑指offer在线变成没有该题,手动补充) 8 | * 在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物? 9 | * 10 | * 示例 1: 11 | * 12 | * 输入: 13 | * [ 14 | *   [1,3,1], 15 | *   [1,5,1], 16 | *   [4,2,1] 17 | * ] 18 | * 输出: 12 19 | * 解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物 20 | *   21 | * 22 | * 提示: 23 | * 24 | * 0 < grid.length <= 200 25 | * 0 < grid[0].length <= 200 26 | * 27 | * 来源:力扣(LeetCode) 28 | * 链接:https://leetcode-cn.com/problems/li-wu-de-zui-da-jie-zhi-lcof 29 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 30 | * @author: icecrea 31 | * @create: 2020-04-23 32 | **/ 33 | public class Sword68_MaxGift { 34 | 35 | /** 36 | * dp - 到该位置能拿到的最大价值 37 | */ 38 | public int maxValue(int[][] grid) { 39 | int[][] dp = new int[grid.length][grid[0].length]; 40 | dp[0][0] = grid[0][0]; 41 | for (int i = 1; i < dp.length; i++) { 42 | dp[i][0] = dp[i - 1][0] + grid[i][0]; 43 | } 44 | for (int i = 1; i < dp[0].length; i++) { 45 | dp[0][i] = dp[0][i - 1] + grid[0][i]; 46 | } 47 | for (int i = 1; i < dp.length; i++) { 48 | for (int j = 1; j < dp[0].length; j++) { 49 | dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]; 50 | } 51 | } 52 | return dp[grid.length - 1][grid[0].length - 1]; 53 | } 54 | 55 | @Test 56 | public void test(){ 57 | System.out.println(maxValue(new int[][]{{1,3,1},{1,5,1},{4,2,1}})); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/README.md: -------------------------------------------------------------------------------- 1 | # 高频算法题目清单 2 | 3 | 这是由LeetCode官方推出的的经典面试题目清单,将题目重新整理规划,从而为大家提供更好的练习体验和帮助大家找到理想的工作。 我们将题目分为以下三个部分: 4 | 5 | - 初级算法 - 帮助入门 6 | - 中级算法 - 巩固训练 7 | - 高级算法 - 提升进阶 8 | 9 | - [初级算法原地址](https://leetcode-cn.com/explore/interview/card/top-interview-questions-easy/) 10 | - [中级算法原地址](https://leetcode-cn.com/explore/interview/card/top-interview-questions-medium/) 11 | - [高级算法原地址](https://leetcode-cn.com/explore/interview/card/top-interview-questions-hard/) 12 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/array/array21_removeDuplicates.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.array; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 从排序数组中删除重复项 7 | * 8 | * 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 9 | * 10 | * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 11 | * 12 | * 示例 1: 13 | * 给定数组 nums = [1,1,2], 14 | * 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 15 | * 你不需要考虑数组中超出新长度后面的元素。 16 | * 17 | * 示例 2: 18 | * 给定 nums = [0,0,1,1,1,2,2,3,3,4], 19 | * 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 20 | * 你不需要考虑数组中超出新长度后面的元素。 21 | * 22 | * 说明: 23 | * 为什么返回数值是整数,但输出的答案是数组呢? 24 | * 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 25 | * 26 | * 你可以想象内部操作如下: 27 | * 28 | * // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 29 | * int len = removeDuplicates(nums); 30 | * 31 | * // 在函数里修改输入数组对于调用者是可见的。 32 | * // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 33 | * for (int i = 0; i < len; i++) { 34 | * print(nums[i]); 35 | * } 36 | * @author: icecrea 37 | * @create: 2019-02-19 09:18 38 | **/ 39 | public class array21_removeDuplicates { 40 | public int removeDuplicates(int[] nums) { 41 | //两个指针 一个不断向后遍历,记录值不同的位置。一个记录需要替换的位置 42 | //数组新赋值的下标 43 | int index = 0; 44 | for (int i = index + 1; i < nums.length; i++) { 45 | if (nums[i] != nums[index]) { 46 | nums[++index] = nums[i]; 47 | } 48 | } 49 | return index + 1; 50 | } 51 | 52 | @Test 53 | public void test() { 54 | int[] a = new int[]{0, 0, 1, 1, 1, 2, 2, 3, 3, 4}; 55 | System.out.println(removeDuplicates(a)); 56 | for (int i : a) { 57 | System.out.println(i); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/array/array23_reverse.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.array; 2 | 3 | /** 4 | * @description: 旋转数组 5 | * 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 6 | * 7 | * 示例 1: 8 | * 9 | * 输入: [1,2,3,4,5,6,7] 和 k = 3 10 | * 输出: [5,6,7,1,2,3,4] 11 | * 解释: 12 | * 向右旋转 1 步: [7,1,2,3,4,5,6] 13 | * 向右旋转 2 步: [6,7,1,2,3,4,5] 14 | * 向右旋转 3 步: [5,6,7,1,2,3,4] 15 | * 示例 2: 16 | * 17 | * 输入: [-1,-100,3,99] 和 k = 2 18 | * 输出: [3,99,-1,-100] 19 | * 解释: 20 | * 向右旋转 1 步: [99,-1,-100,3] 21 | * 向右旋转 2 步: [3,99,-1,-100] 22 | * 说明: 23 | * 24 | * 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 25 | * 要求使用空间复杂度为 O(1) 的原地算法。 26 | * @author: icecrea 27 | * @create: 2019-02-20 09:06 28 | **/ 29 | public class array23_reverse { 30 | /** 31 | * 可以先整体反序,然后以k下标处分割,两部分再次反序 32 | * 33 | * @param nums 34 | * @param k 35 | */ 36 | public void rotate(int[] nums, int k) { 37 | k = k % nums.length; 38 | reverse(nums, 0, nums.length - 1); 39 | reverse(nums, 0, k - 1); 40 | reverse(nums, k, nums.length - 1); 41 | } 42 | 43 | /** 44 | * @param nums 45 | * @param p 46 | * @param q 47 | */ 48 | public void reverse(int[] nums, int p, int q) { 49 | while (p <= q) { 50 | int tmp = nums[p]; 51 | nums[p] = nums[q]; 52 | nums[q] = tmp; 53 | p++; 54 | q--; 55 | } 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/array/array24_containsDuplicate.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.array; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.HashMap; 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | /** 10 | * @description: 存在重复 11 | * 给定一个整数数组,判断是否存在重复元素。 12 | * 13 | * 如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。 14 | * 15 | * 示例 1: 16 | * 输入: [1,2,3,1] 17 | * 输出: true 18 | * 19 | * 示例 2: 20 | * 输入: [1,2,3,4] 21 | * 输出: false 22 | * 示例 3: 23 | * 24 | * 输入: [1,1,1,3,3,4,3,2,4,2] 25 | * 输出: true 26 | * @author: icecrea 27 | * @create: 2019-02-20 09:44 28 | **/ 29 | public class array24_containsDuplicate { 30 | 31 | public boolean containsDuplicate(int[] nums) { 32 | Set set = new HashSet<>(nums.length); 33 | for (int x : nums) { 34 | if (set.contains(x)) { 35 | return true; 36 | } 37 | set.add(x); 38 | } 39 | return false; 40 | } 41 | 42 | 43 | @Test 44 | public void test() { 45 | System.out.println(containsDuplicate(new int[]{1, 2, 3, 1})); 46 | System.out.println(containsDuplicate(new int[]{1, 2, 3, 4})); 47 | System.out.println(containsDuplicate(new int[]{1, 1, 1, 3, 3, 4, 3, 2, 4, 2})); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/array/array28_moveZeroes.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.array; 2 | 3 | /** 4 | * @description: 移动零 5 | * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 6 | * 7 | * 示例: 8 | * 9 | * 输入: [0,1,0,3,12] 10 | * 输出: [1,3,12,0,0] 11 | * 说明: 12 | * 13 | * 必须在原数组上操作,不能拷贝额外的数组。 14 | * 尽量减少操作次数。 15 | * @author: icecrea 16 | * @create: 2019-02-26 10:41 17 | **/ 18 | public class array28_moveZeroes { 19 | /** 20 | * 不等于0的依次从0给数组赋值,剩下的数组位置全置为0 21 | * 22 | * @param nums 23 | */ 24 | public void moveZeroes(int[] nums) { 25 | int index = 0; 26 | for (int i = 0; i < nums.length; i++) { 27 | if (nums[i] != 0) { 28 | nums[index++] = nums[i]; 29 | } 30 | } 31 | for (int i = index; i < nums.length; i++) { 32 | nums[i] = 0; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/array/array29_twoSum.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.array; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * @description: 两数之和 8 | * 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 9 | * 10 | * 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 11 | * 12 | * 示例: 13 | * 14 | * 给定 nums = [2, 7, 11, 15], target = 9 15 | * 16 | * 因为 nums[0] + nums[1] = 2 + 7 = 9 17 | * 所以返回 [0, 1] 18 | * @author: icecrea 19 | * @create: 2019-02-26 11:30 20 | **/ 21 | public class array29_twoSum { 22 | public int[] twoSum(int[] nums, int target) { 23 | for (int i = 0; i < nums.length; i++) { 24 | for (int j = i + 1; j < nums.length; j++) { 25 | if (nums[i] + nums[j] == target) { 26 | return new int[]{i, j}; 27 | } 28 | } 29 | } 30 | return null; 31 | } 32 | 33 | public int[] twoSum2(int[] nums, int target) { 34 | int n = nums.length; 35 | Map map = new HashMap<>(); 36 | // 构造一个哈希表:元素映射到相应的索引 key是值 value是索引下标 37 | for (int i = 0; i < n; i++) { 38 | map.put(nums[i], i); 39 | } 40 | 41 | for (int i = 0; i < n; i++) { 42 | int other = target - nums[i]; 43 | // 如果 other 存在且不是 nums[i] 本身 44 | if (map.containsKey(other) && map.get(other) != i) 45 | return new int[]{i, map.get(other)}; 46 | } 47 | 48 | return new int[]{-1, -1}; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/array/array31_rotate.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.array; 2 | 3 | /** 4 | * 旋转图像 5 | * 给定一个 n × n 的二维矩阵表示一个图像。 6 | * 将图像顺时针旋转 90 度。 7 | * 说明: 8 | * 你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。 9 | * 10 | * 示例 1: 11 | * 给定 matrix = 12 | * [ 13 | * [1,2,3], 14 | * [4,5,6], 15 | * [7,8,9] 16 | * ], 17 | * 18 | * 原地旋转输入矩阵,使其变为: 19 | * [ 20 | * [7,4,1], 21 | * [8,5,2], 22 | * [9,6,3] 23 | * ] 24 | * 25 | * 示例 2: 26 | * 给定 matrix = 27 | * [ 28 | * [ 5, 1, 9,11], 29 | * [ 2, 4, 8,10], 30 | * [13, 3, 6, 7], 31 | * [15,14,12,16] 32 | * ], 33 | * 34 | * 原地旋转输入矩阵,使其变为: 35 | * [ 36 | * [15,13, 2, 5], 37 | * [14, 3, 4, 1], 38 | * [12, 6, 8, 9], 39 | * [16, 7,10,11] 40 | * ] 41 | */ 42 | public class array31_rotate { 43 | /** 44 | * 先转置矩阵,然后翻转每一行 45 | * 123 46 | * 456 47 | * 789 48 | * 49 | * 147 50 | * 258 51 | * 369 52 | */ 53 | public void rotate(int[][] matrix) { 54 | int n = matrix.length; 55 | 56 | // 转置矩阵 (注意不要转2次导致不变) 57 | for (int i = 0; i < n; i++) { 58 | for (int j = i; j < n; j++) { 59 | int tmp = matrix[j][i]; 60 | matrix[j][i] = matrix[i][j]; 61 | matrix[i][j] = tmp; 62 | } 63 | } 64 | // 反转每行 65 | for (int i = 0; i < n; i++) { 66 | for (int j = 0; j < n / 2; j++) { 67 | int tmp = matrix[i][j]; 68 | matrix[i][j] = matrix[i][n - j - 1]; 69 | matrix[i][n - j - 1] = tmp; 70 | } 71 | } 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/design/array59_minstack.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.design; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * 最小栈 7 | * 设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。 8 | * 9 | * push(x) -- 将元素 x 推入栈中。 10 | * pop() -- 删除栈顶的元素。 11 | * top() -- 获取栈顶元素。 12 | * getMin() -- 检索栈中的最小元素。 13 | * 示例: 14 | * 15 | * MinStack minStack = new MinStack(); 16 | * minStack.push(-2); 17 | * minStack.push(0); 18 | * minStack.push(-3); 19 | * minStack.getMin(); --> 返回 -3. 20 | * minStack.pop(); 21 | * minStack.top(); --> 返回 0. 22 | * minStack.getMin(); --> 返回 -2. 23 | */ 24 | public class array59_minstack { 25 | 26 | Stack stack; 27 | 28 | Stack minStack; 29 | 30 | /** 31 | * initialize your data structure here. 32 | */ 33 | public array59_minstack() { 34 | stack = new Stack(); 35 | minStack = new Stack(); 36 | } 37 | 38 | public void push(int x) { 39 | stack.push(x); 40 | if (minStack.isEmpty() || minStack.peek() >= x) { 41 | minStack.push(x); 42 | } 43 | } 44 | 45 | /** 46 | * 2 2 3 5 1 47 | * 2 2 1 48 | */ 49 | public void pop() { 50 | if (!stack.isEmpty()) { 51 | int pop = stack.pop(); 52 | if (pop == minStack.peek()) { 53 | minStack.pop(); 54 | } 55 | } 56 | } 57 | 58 | public int top() { 59 | return stack.peek(); 60 | } 61 | 62 | public int getMin() { 63 | return minStack.peek(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/dp/array54_climbStairs.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.dp; 2 | 3 | /** 4 | * @description: 爬楼梯 5 | * 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 6 | * 7 | * 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 8 | * 9 | * 注意:给定 n 是一个正整数。 10 | * 11 | * 示例 1: 12 | * 13 | * 输入: 2 14 | * 输出: 2 15 | * 解释: 有两种方法可以爬到楼顶。 16 | * 1. 1 阶 + 1 阶 17 | * 2. 2 阶 18 | * 示例 2: 19 | * 20 | * 输入: 3 21 | * 输出: 3 22 | * 解释: 有三种方法可以爬到楼顶。 23 | * 1. 1 阶 + 1 阶 + 1 阶 24 | * 2. 1 阶 + 2 阶 25 | * 3. 2 阶 + 1 阶 26 | * @author: icecrea 27 | * @create: 2019-03-18 15:45 28 | **/ 29 | public class array54_climbStairs { 30 | 31 | public int climbStairs(int n) { 32 | if (n == 1) { 33 | return 1; 34 | } 35 | if (n == 2) { 36 | return 2; 37 | } 38 | int l = 1; 39 | int r = 2; 40 | int res = 0; 41 | for (int i = 3; i <= n; i++) { 42 | res = l + r; 43 | l = r; 44 | r = res; 45 | } 46 | return res; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/dp/array55_maxProfit.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.dp; 2 | 3 | import com.example.leetcode.dp.LeetCode121_BestTimeToBuyAndSellStock; 4 | 5 | /** 6 | * @description: 买股票的最佳时机 7 | * 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 8 | * 9 | * 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。 10 | * 11 | * 注意你不能在买入股票前卖出股票。 12 | * 13 | * 示例 1: 14 | * 15 | * 输入: [7,1,5,3,6,4] 16 | * 输出: 5 17 | * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 18 | * 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 19 | * 示例 2: 20 | * 21 | * 输入: [7,6,4,3,1] 22 | * 输出: 0 23 | * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 24 | * @author: icecrea 25 | * @create: 2019-03-18 15:59 26 | **/ 27 | public class array55_maxProfit { 28 | /** 29 | * 找到最小的谷和之后的最大的峰 30 | * @see LeetCode121_BestTimeToBuyAndSellStock 31 | * @param prices 32 | * @return 33 | */ 34 | public int maxProfit(int prices[]) { 35 | int minprice = Integer.MAX_VALUE; 36 | int maxprofit = 0; 37 | for (int i = 0; i < prices.length; i++) { 38 | if (prices[i] < minprice) { 39 | minprice = prices[i]; 40 | } else if (prices[i] - minprice > maxprofit) { 41 | maxprofit = prices[i] - minprice; 42 | } 43 | } 44 | return maxprofit; 45 | } 46 | 47 | 48 | public int maxProfit2(int[] prices) { 49 | if (prices == null || prices.length == 0) { 50 | return 0; 51 | } 52 | int maxprofit = 0; 53 | int curMin = prices[0]; 54 | for (int sell = 1; sell < prices.length; sell++) { 55 | curMin = Math.min(curMin, prices[sell]); 56 | maxprofit = Math.max(maxprofit, prices[sell] - curMin); 57 | } 58 | return maxprofit; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/dp/array56_maxSubArray.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.dp; 2 | 3 | /** 4 | * @description: 最大子序和 5 | * 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 6 | * 7 | * 示例: 8 | * -2 1 -2 4 3 5 6 1 5 9 | * 输入: [-2,1,-3,4,-1,2,1,-5,4], 10 | * 输出: 6 11 | * 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 12 | * 进阶: 13 | * 14 | * 如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 15 | * @author: icecrea 16 | * @create: 2019-03-18 19:36 17 | **/ 18 | public class array56_maxSubArray { 19 | public int maxSubArray(int[] nums) { 20 | int maxToCur = 0; 21 | int max = Integer.MIN_VALUE; 22 | for (int i = 0; i < nums.length; i++) { 23 | if (maxToCur >= 0) { 24 | maxToCur += nums[i]; 25 | } else { 26 | maxToCur = nums[i]; 27 | } 28 | max = Math.max(max, maxToCur); 29 | } 30 | return max; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/dp/array57_rob.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.dp; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 打家劫舍 7 | * 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金 8 | * ,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 9 | *

    10 | * 给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。 11 | *

    12 | * 示例 1: 13 | * 1 2 4 3 14 | * 输入: [1,2,3,1] 15 | * 输出: 4 16 | * 解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 17 | * 偷窃到的最高金额 = 1 + 3 = 4 。 18 | * 示例 2: 19 | * 2 7 11 10 12 20 | * 输入: [2,7,9,3,1] 21 | * 输出: 12 22 | * 解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。 23 | * 偷窃到的最高金额 = 2 + 9 + 1 = 12 。 24 | * @author: icecrea 25 | * @create: 2019-03-18 20:04 26 | **/ 27 | public class array57_rob { 28 | public int rob(int[] nums) { 29 | if (nums == null || nums.length == 0) { 30 | return 0; 31 | } 32 | if (nums.length == 1) { 33 | return nums[0]; 34 | } 35 | int[] dp = new int[nums.length]; 36 | dp[0] = nums[0]; 37 | dp[1] = Math.max(nums[0], nums[1]); 38 | for (int i = 2; i < nums.length; i++) { 39 | dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]); 40 | } 41 | return dp[nums.length - 1]; 42 | } 43 | 44 | @Test 45 | public void test() { 46 | // 1 2 4 4 47 | // int rob = rob(new int[]{1, 2, 3, 1}); 48 | // 2 2 3 4 49 | int rob = rob(new int[]{2, 1, 1, 2}); 50 | System.out.println(rob); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/linkedlist/array41_deleteNode.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 删除链表节点 7 | * 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。 8 | * 9 | * 现有一个链表 -- head = [4,5,1,9],它可以表示为: 10 | * 11 | * 12 | * 示例 1: 13 | * 14 | * 输入: head = [4,5,1,9], node = 5 15 | * 输出: [4,1,9] 16 | * 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9. 17 | * 示例 2: 18 | * 19 | * 输入: head = [4,5,1,9], node = 1 20 | * 输出: [4,5,9] 21 | * 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9. 22 | * 23 | * 24 | * 说明: 25 | * 26 | * 链表至少包含两个节点。 27 | * 链表中所有节点的值都是唯一的。 28 | * 给定的节点为非末尾节点并且一定是链表中的一个有效节点。 29 | * 不要从你的函数中返回任何结果。 30 | * @author: icecrea 31 | * @create: 2019-03-17 23:29 32 | **/ 33 | public class array41_deleteNode { 34 | /** 35 | * 要删除一个节点 通常需要前一个节点 但本体给的是需要删除的节点 36 | * 所以通过值替换,删除下一个节点 移花接木 37 | * @param node 38 | */ 39 | public void deleteNode(ListNode node) { 40 | node.val = node.next.val; 41 | node.next = node.next.next; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/linkedlist/array42_removeNthFromEnd.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | 5 | /** 6 | * @description: 删除链表倒数第n个节点 7 | * 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。 8 | *

    9 | * 示例: 10 | *

    11 | * 给定一个链表: 1->2->3->4->5, 和 n = 2. 12 | *

    13 | * 当删除了倒数第二个节点后,链表变为 1->2->3->5. 14 | * 说明: 15 | *

    16 | * 给定的 n 保证是有效的。 17 | *

    18 | * 进阶: 19 | *

    20 | * 你能尝试使用一趟扫描实现吗? 21 | * @author: icecrea 22 | * @create: 2019-03-06 20:29 23 | **/ 24 | public class array42_removeNthFromEnd { 25 | /** 26 | * 删除从列表开头数起的第 (L - n + 1)个结点,其中 L 是列表的长度 27 | * 28 | * @param head 29 | * @param n 30 | * @return 31 | */ 32 | public ListNode removeNthFromEnd(ListNode head, int n) { 33 | int len = 0; 34 | ListNode dummy = new ListNode(0); 35 | dummy.next = head; 36 | ListNode node = dummy; 37 | while (node.next != null) { 38 | len++; 39 | node = node.next; 40 | } 41 | node = dummy; 42 | len = len - n; 43 | for (int i = 0; i < len; i++) { 44 | node = node.next; 45 | } 46 | node.next = node.next.next; 47 | return dummy.next; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/linkedlist/array43_reverseList.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | import org.junit.Test; 5 | 6 | /** 7 | * @description: 反转链表 8 | * 反转一个单链表。 9 | *

    10 | * 示例: 11 | *

    12 | * 输入: 1->2->3->4->5->NULL 13 | * 输出: 5->4->3->2->1->NULL 14 | * 进阶: 15 | * 你可以迭代或递归地反转链表。你能否用两种方法解决这道题? 16 | * @author: icecrea 17 | * @create: 2019-03-17 22:47 18 | **/ 19 | public class array43_reverseList { 20 | /** 21 | * 非递归 22 | * 23 | * @param head 24 | * @return 25 | */ 26 | public ListNode reverseList(ListNode head) { 27 | ListNode pre = null; 28 | ListNode next; 29 | 30 | while (head != null) { 31 | next = head.next; 32 | head.next = pre; 33 | pre = head; 34 | head = next; 35 | } 36 | return pre; 37 | } 38 | 39 | /** 40 | * 递归方法 41 | * 42 | * @param head 43 | * @return 44 | */ 45 | public ListNode reverseListRecur(ListNode head) { 46 | //递归终止条件: 找到链表最后一个节点 47 | if (head == null || head.next == null) { 48 | return head; 49 | } 50 | ListNode newNode = reverseListRecur(head.next); 51 | //反转头节点的下一个节点的next指针 head.next对应的是 反转后链表的尾指针,而node.next是反转后的头指针的下一个节点,此处注意区分 52 | head.next.next = head; 53 | //反转头节点的next指针,将头节点作为尾节点 54 | head.next = null; 55 | return newNode; 56 | } 57 | 58 | 59 | @Test 60 | public void test() { 61 | ListNode a = new ListNode(1); 62 | ListNode b = new ListNode(2); 63 | ListNode c = new ListNode(3); 64 | a.next = b; 65 | b.next = c; 66 | c.next = null; 67 | reverseListRecur(a); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/linkedlist/array44_mergeTwoLists.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | import org.junit.Test; 5 | 6 | /** 7 | * @description: 合并两个有序链表 8 | * 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 9 | *

    10 | * 示例: 11 | *

    12 | * 输入:1->2->4, 1->3->4 13 | * 输出:1->1->2->3->4->4 14 | * @author: icecrea 15 | * @create: 2019-03-18 09:28 16 | **/ 17 | public class array44_mergeTwoLists { 18 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 19 | ListNode dummy = new ListNode(0); 20 | ListNode cur = dummy; 21 | while (l1 != null && l2 != null) { 22 | if (l1.val <= l2.val) { 23 | cur.next = l1; 24 | l1 = l1.next; 25 | } else { 26 | cur.next = l2; 27 | l2 = l2.next; 28 | } 29 | cur = cur.next; 30 | } 31 | if (l1 != null) { 32 | cur.next = l1; 33 | } 34 | if (l2 != null) { 35 | cur.next = l2; 36 | } 37 | return dummy.next; 38 | } 39 | 40 | @Test 41 | public void test() { 42 | ListNode a = new ListNode(1); 43 | ListNode b = new ListNode(2); 44 | ListNode c = new ListNode(3); 45 | a.next = b; 46 | b.next = c; 47 | c.next = null; 48 | 49 | ListNode a2 = new ListNode(1); 50 | ListNode b2 = new ListNode(2); 51 | ListNode c2 = new ListNode(3); 52 | a2.next = b2; 53 | b2.next = c2; 54 | c2.next = null; 55 | mergeTwoLists(a, a2); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/linkedlist/array45_isPalindrome.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.linkedlist; 2 | 3 | import com.example.leetcode.linkedlist.pojo.ListNode; 4 | import org.junit.Test; 5 | 6 | /** 7 | * @description: 回文链表 8 | * 请判断一个链表是否为回文链表。 9 | *

    10 | * 示例 1: 11 | *

    12 | * 输入: 1->2 13 | * 输出: false 14 | * 示例 2: 15 | *

    16 | * 输入: 1->2->2->1 17 | * 输出: true 18 | * 进阶: 19 | * 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题? 20 | * @author: icecrea 21 | * @create: 2019-03-18 09:37 22 | **/ 23 | public class array45_isPalindrome { 24 | /** 25 | * 对链表后半部分反转 26 | * 27 | * @param head 28 | * @return 29 | */ 30 | public boolean isPalindrome(ListNode head) { 31 | // 要实现 O(n) 的时间复杂度和 O(1) 的空间复杂度,需要翻转后半部分 32 | if (head == null || head.next == null) { 33 | return true; 34 | } 35 | ListNode fast = head; 36 | ListNode slow = head; 37 | // 根据快慢指针,找到链表的中点 快指针的下个和下下个均不能为空 38 | while (fast.next != null && fast.next.next != null) { 39 | fast = fast.next.next; 40 | slow = slow.next; 41 | } 42 | //注意反转后半部分 43 | slow = reverse(slow.next); 44 | while (slow != null) { 45 | if (head.val != slow.val) { 46 | return false; 47 | } 48 | head = head.next; 49 | slow = slow.next; 50 | } 51 | return true; 52 | } 53 | 54 | private ListNode reverse(ListNode head) { 55 | if (head == null || head.next == null) { 56 | return head; 57 | } 58 | ListNode newNode = reverse(head.next); 59 | head.next.next = head; 60 | head.next = null; 61 | return newNode; 62 | } 63 | 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/math/array61_countPrimes.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.math; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * @description: 计数质数 9 | * 统计所有小于非负整数 n 的质数的数量。 10 | * 11 | * 示例: 12 | * 13 | * 输入: 10 14 | * 输出: 4 15 | * 解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。 16 | * @author: icecrea 17 | * @create: 2019-03-19 10:42 18 | **/ 19 | public class array61_countPrimes { 20 | /** 21 | * 从 2 开始,2 是一个素数,那么 2 × 2 = 4, 3 × 2 = 6, 4 × 2 = 8... 不可能是素数。 22 | * 3 也是素数,那么 3 × 2 = 6, 3 × 3 = 9, 3 × 4 = 12... 不可能是素数。 23 | */ 24 | public int countPrimes(int n) { 25 | boolean[] isPrime = new boolean[n]; 26 | Arrays.fill(isPrime, true); 27 | int count = 0; 28 | //对于i 判断素数 只需要遍历到sqrt(i)即可 29 | for (int i = 2; i * i < n; i++) { 30 | if (isPrime[i]) { 31 | for (int j = 2 * i; j < n; j += i) { 32 | isPrime[j] = false; 33 | } 34 | } 35 | } 36 | for (int i = 2; i < n; i++) 37 | if (isPrime[i]) { 38 | count++; 39 | } 40 | return count; 41 | } 42 | 43 | @Test 44 | public void test() { 45 | System.out.println(countPrimes(10)); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/math/array62_isPowerOfThree.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.math; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 3的幂 7 | * 给定一个整数,写一个函数来判断它是否是 3 的幂次方。 8 | * 9 | * 示例 1: 10 | * 11 | * 输入: 27 12 | * 输出: true 13 | * 示例 2: 14 | * 15 | * 输入: 0 16 | * 输出: false 17 | * 示例 3: 18 | * 19 | * 输入: 9 20 | * 输出: true 21 | * 示例 4: 22 | * 23 | * 输入: 45 24 | * 输出: false 25 | * 进阶: 26 | * 你能不使用循环或者递归来完成本题吗? 27 | * @author: icecrea 28 | * @create: 2019-03-19 12:07 29 | **/ 30 | public class array62_isPowerOfThree { 31 | /** 32 | * 超时 33 | * 34 | * @param n 35 | * @return 36 | */ 37 | public boolean isPowerOfThree(int n) { 38 | if (n < 1) { 39 | return false; 40 | } 41 | while (n % 3 == 0) { 42 | n /= 3; 43 | } 44 | return n == 1; 45 | } 46 | 47 | public boolean isPowerOfThree2(int n) { 48 | // 1162261467 is 3^19, 3^20 is bigger than int 49 | return n > 0 && (1162261467 % n == 0); 50 | } 51 | 52 | /** 53 | * @param n 54 | * @return 55 | */ 56 | public boolean isPowerOfThree3(int n) { 57 | return (n > 0) && (Math.log10(n) / Math.log10(3) % 1 == 0); 58 | } 59 | 60 | @Test 61 | public void test() { 62 | System.out.println(isPowerOfThree(1162261468 * 3)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/other/array64_hammingWeight.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.other; 2 | 3 | /** 4 | * @description: 位1的个数 5 | * 6 | * 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 7 | * 8 | * 示例 1: 9 | * 输入:00000000000000000000000000001011 10 | * 输出:3 11 | * 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 12 | * 13 | * 示例 2: 14 | * 输入:00000000000000000000000010000000 15 | * 输出:1 16 | * 解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。 17 | * 18 | * 示例 3: 19 | * 输入:11111111111111111111111111111101 20 | * 输出:31 21 | * 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。 22 | * 23 | * 提示: 24 | * 25 | * 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。 26 | * 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。 27 | * 28 | * 29 | * 进阶: 30 | * 如果多次调用这个函数,你将如何优化你的算法? 31 | * @author: icecrea 32 | * @create: 2019-03-19 16:34 33 | **/ 34 | public class array64_hammingWeight { 35 | /** 36 | * 注意 37 | * 1.使用>>> 而不是>> 38 | * 2.n&1加括号 39 | * 40 | * @param n 41 | * @return 42 | */ 43 | public int hammingWeight(int n) { 44 | int count = 0; 45 | while (n != 0) { 46 | count = count + (n & 1); 47 | n = n >>> 1; 48 | } 49 | return count; 50 | } 51 | 52 | public int hammingWeight2(int n) { 53 | return Integer.bitCount(n); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/other/array65_hammingDistance.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.other; 2 | 3 | /** 4 | * @description: 汉明距离 5 | * 两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。 6 | * 7 | * 给出两个整数 x 和 y,计算它们之间的汉明距离。 8 | * 9 | * 注意: 10 | * 0 ≤ x, y < 231. 11 | * 12 | * 示例: 13 | * 14 | * 输入: x = 1, y = 4 15 | * 16 | * 输出: 2 17 | * 18 | * 解释: 19 | * 1 (0 0 0 1) 20 | * 4 (0 1 0 0) 21 | * ↑ ↑ 22 | * 23 | * 上面的箭头指出了对应二进制位不同的位置。 24 | * @author: icecrea 25 | * @create: 2019-03-19 22:04 26 | **/ 27 | public class array65_hammingDistance { 28 | /** 29 | * 利用亦或 不同为1 相同为0 30 | * @param x 31 | * @param y 32 | * @return 33 | */ 34 | public int hammingDistance(int x, int y) { 35 | int xor = x ^ y, count = 0; 36 | for (int i = 0; i < 32; i++) { 37 | count += (xor >> i) & 1; 38 | } 39 | return count; 40 | } 41 | 42 | public int hammingDistance1(int x, int y) { 43 | return Integer.bitCount(x ^ y); 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/other/array67_pascalTriangle.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.other; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * @description: 帕斯卡三角形 10 | * 定一个非负整数 numRows,生成杨辉三角的前 numRows 行。 11 | * 在杨辉三角中,每个数是它左上方和右上方的数的和。 12 | * 13 | * 示例: 14 | * 输入: 5 15 | * 输出: 16 | * [ 17 | * [1], 18 | * [1,1], 19 | * [1,2,1], 20 | * [1,3,3,1], 21 | * [1,4,6,4,1] 22 | * ] 23 | * @author: icecrea 24 | * @create: 2019-03-22 15:51 25 | **/ 26 | public class array67_pascalTriangle { 27 | public List> generate(int numRows) { 28 | List> allrows = new ArrayList<>(); 29 | ArrayList row = new ArrayList<>(); 30 | for (int i = 0; i < numRows; i++) { 31 | row.add(0, 1); 32 | for (int j = 1; j < row.size() - 1; j++) { 33 | row.set(j, row.get(j) + row.get(j + 1)); 34 | } 35 | allrows.add(new ArrayList<>(row)); 36 | } 37 | return allrows; 38 | } 39 | 40 | @Test 41 | public void test() { 42 | System.out.println(generate(4)); 43 | System.out.println(generate(5)); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/other/array68_isValid.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.other; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * @description: 有效的括号 7 | * 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 8 | * 9 | * 有效字符串需满足: 10 | * 11 | * 左括号必须用相同类型的右括号闭合。 12 | * 左括号必须以正确的顺序闭合。 13 | * 注意空字符串可被认为是有效字符串。 14 | * 15 | * 示例 1: 16 | * 输入: "()" 17 | * 输出: true 18 | * 19 | * 示例 2: 20 | * 输入: "()[]{}" 21 | * 输出: true 22 | * 23 | * 示例 3: 24 | * 输入: "(]" 25 | * 输出: false 26 | * 27 | * 示例 4: 28 | * 输入: "([)]" 29 | * 输出: false 30 | * 31 | * 示例 5: 32 | * 输入: "{[]}" 33 | * 输出: true 34 | * 35 | * @author: icecrea 36 | * @create: 2019-03-21 22:40 37 | **/ 38 | public class array68_isValid { 39 | public boolean isValid(String s) { 40 | Stack stack = new Stack<>(); 41 | for (char c : s.toCharArray()) { 42 | if (c == '(') { 43 | stack.push(')'); 44 | } else if (c == '{') { 45 | stack.push('}'); 46 | } else if (c == '[') { 47 | stack.push(']'); 48 | } else if (stack.isEmpty() || stack.pop() != c) { 49 | return false; 50 | } 51 | } 52 | return stack.isEmpty(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/other/array69_missingNumber.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.other; 2 | 3 | /** 4 | * @description: 缺失数字 5 | * 给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。 6 | * 7 | * 示例 1: 8 | * 输入: [3,0,1] 9 | * 输出: 2 10 | * 11 | * 示例 2: 12 | * 输入: [9,6,4,2,3,5,7,0,1] 13 | * 输出: 8 14 | * 说明: 15 | * 你的算法应具有线性时间复杂度。你能否仅使用额外常数空间来实现? 16 | * @author: icecrea 17 | * @create: 2019-03-22 15:53 18 | **/ 19 | public class array69_missingNumber { 20 | /** 21 | * 1到n的和 - 数组和 22 | * @param nums 23 | * @return 24 | */ 25 | public int missingNumber(int[] nums) { 26 | int sum = 0, n = nums.length; 27 | for (int i : nums) { 28 | sum += i; 29 | } 30 | return n * (n + 1) / 2 - sum; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/sort/array52_merge.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.sort; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @description: 合并两个有序数组 7 | * 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 8 | * 9 | * 说明: 10 | * 11 | * 初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 12 | * 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 13 | * 示例: 14 | * 15 | * 输入: 16 | * nums1 = [1,2,3,0,0,0], m = 3 17 | * nums2 = [2,5,6], n = 3 18 | * 19 | * 输出: [1,2,2,3,5,6] 20 | * @author: icecrea 21 | * @create: 2019-03-18 14:31 22 | **/ 23 | public class array52_merge { 24 | 25 | public void merge(int[] nums1, int m, int[] nums2, int n) { 26 | int i = m - 1; 27 | int j = n - 1; 28 | int k = m + n - 1; 29 | while (i >= 0 && j >= 0) { 30 | if (nums1[i] > nums2[j]) { 31 | nums1[k--] = nums1[i--]; 32 | } else { 33 | nums1[k--] = nums2[j--]; 34 | } 35 | } 36 | while (j >= 0) { 37 | nums1[k--] = nums2[j--]; 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/string/array32_reverseString.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.string; 2 | 3 | /** 4 | * @description: 反转字符串 5 | * 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。 6 | * 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 7 | * 你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。 8 | * 9 | * 示例 1: 10 | * 输入:["h","e","l","l","o"] 11 | * 输出:["o","l","l","e","h"] 12 | * 13 | * 示例 2: 14 | * 输入:["H","a","n","n","a","h"] 15 | * 输出:["h","a","n","n","a","H"] 16 | * @author: icecrea 17 | * @create: 2019-03-11 19:22 18 | **/ 19 | public class array32_reverseString { 20 | public void reverseString(char[] s) { 21 | for (int i = 0; i < s.length / 2; i++) { 22 | char tmp = s[i]; 23 | s[i] = s[s.length - i - 1]; 24 | s[s.length - i - 1] = tmp; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/string/array33_reverse.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.string; 2 | 3 | /** 4 | * @description: 整数反转 5 | * 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。 6 | * 示例 1: 7 | * 输入: 123 8 | * 输出: 321 9 | * 10 | * 示例 2: 11 | * 输入: -123 12 | * 输出: -321 13 | * 14 | * 示例 3: 15 | * 输入: 120 16 | * 输出: 21 17 | * 注意: 18 | * 19 | * 假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−2^31, 2^31 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。 20 | * @author: icecrea 21 | * @create: 2019-03-11 19:26 22 | **/ 23 | public class array33_reverse { 24 | 25 | /** 26 | * 使用long 偏取巧 27 | * 循环 28 | * 每次取最后一位数字*10 (从0开始)+ 原数字删除最后一位数字 29 | * new : 3, 32 , 321 30 | * old : 32, 2 , 0 31 | * 32 | * @param x 33 | * @return 34 | */ 35 | public int reverse1(int x) { 36 | long ans = 0; 37 | while (x != 0) { 38 | ans = ans * 10 + (x % 10); 39 | x /= 10; 40 | } 41 | if (ans < Integer.MIN_VALUE || ans > Integer.MAX_VALUE) { 42 | ans = 0; 43 | } 44 | return (int) ans; 45 | } 46 | 47 | /** 48 | * 大神解法 : 如果溢出,溢出的Int值变成负值,则新值和旧值是不同的 49 | * 50 | * @param x 51 | * @return 52 | */ 53 | public int reverse2(int x) { 54 | int result = 0; 55 | 56 | while (x != 0) { 57 | int tail = x % 10; 58 | int newResult = result * 10 + tail; 59 | if ((newResult - tail) / 10 != result) { 60 | return 0; 61 | } 62 | result = newResult; 63 | x = x / 10; 64 | } 65 | 66 | return result; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/string/array34_firstUniqChar.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.string; 2 | 3 | /** 4 | * @description: 字符串中第一个唯一字符 5 | * 给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。 6 | * 7 | * 案例: 8 | * s = "leetcode" 9 | * 返回 0. 10 | * 11 | * s = "loveleetcode", 12 | * 返回 2. 13 | * 14 | * 注意事项:您可以假定该字符串只包含小写字母。 15 | * @author: icecrea 16 | * @create: 2019-03-12 12:48 17 | **/ 18 | public class array34_firstUniqChar { 19 | 20 | /** 21 | * 小写字母 可以用26整形数组存出现次数,下标通过char类型相减变成整数,对应从a到z 22 | * @param s 23 | * @return 24 | */ 25 | public int firstUniqChar(String s) { 26 | int[] freq = new int[26]; 27 | for (int i = 0; i < s.length(); i++) { 28 | freq[s.charAt(i) - 'a']++; 29 | } 30 | for (int i = 0; i < s.length(); i++) { 31 | if (freq[s.charAt(i) - 'a'] == 1) { 32 | return i; 33 | } 34 | } 35 | return -1; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/string/array35_isAnagram.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.string; 2 | 3 | /** 4 | * @description: 有效的字母异位词 5 | * 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词。 6 | * 7 | * 示例 1: 8 | * 输入: s = "anagram", t = "nagaram" 9 | * 输出: true 10 | * 11 | * 示例 2: 12 | * 输入: s = "rat", t = "car" 13 | * 输出: false 14 | * 说明: 15 | * 你可以假设字符串只包含小写字母。 16 | * 17 | * 进阶: 18 | * 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况? 19 | * @author: icecrea 20 | * @create: 2019-03-12 12:55 21 | **/ 22 | public class array35_isAnagram { 23 | /** 24 | * 很像上一题唯一字符,都是小写字母,且需要条件为字母出现次数,用int[26]数组来解决 25 | * 26 | * @param s 27 | * @param t 28 | * @return 29 | */ 30 | public boolean isAnagram(String s, String t) { 31 | int[] cs = new int[26]; 32 | for (int i = 0; i < s.length(); i++) { 33 | cs[s.charAt(i) - 'a']++; 34 | } 35 | for (int i = 0; i < t.length(); i++) { 36 | cs[t.charAt(i) - 'a']--; 37 | } 38 | for (int i = 0; i < cs.length; i++) { 39 | if (cs[i] != 0) { 40 | return false; 41 | } 42 | } 43 | return true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/string/array39_countAndSay.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.string; 2 | 3 | /** 4 | * @description: 报数 5 | * 报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下: 6 | * 7 | * 1. 1 8 | * 2. 11 9 | * 3. 21 10 | * 4. 1211 11 | * 5. 111221 12 | * 1 被读作 "one 1" ("一个一") , 即 11。 13 | * 11 被读作 "two 1s" ("两个一"), 即 21。 14 | * 21 被读作 "one 2", "one 1" ("一个二" , "一个一") , 即 1211。 15 | * 16 | * 给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。 17 | * 注意:整数顺序将表示为一个字符串。 18 | * 19 | * 示例 1: 20 | * 输入: 1 21 | * 输出: "1" 22 | * 23 | * 示例 2: 24 | * 输入: 4 25 | * 输出: "1211" 26 | * 27 | * 28 | * (理解题意 : 是对之前的数进行计数,看之前的数中有几个对应的独立数字。 29 | * 比如说上一个数字为 2345 ,也就是“一个2一个3一个4一个5”则应该报数为 12131415; 30 | * 又比如说是 2233445 则是“两个2两个3两个4一个5”,报数结果为 22232415 31 | * 按照这种规律每次对前一个数字进行解读,报出下一个数字) 32 | * @author: icecrea 33 | * @create: 2019-03-13 13:07 34 | **/ 35 | public class array39_countAndSay { 36 | public String countAndSay(int n) { 37 | String s = "1"; 38 | int k; 39 | for (int i = 1; i < n; i++) { 40 | StringBuilder t = new StringBuilder(); 41 | for (int j = 0; j < s.length(); j = k) { 42 | k = j; 43 | //找有几个相同的. 44 | while (k < s.length() && s.charAt(k) == s.charAt(j)) { 45 | k++; 46 | } 47 | t.append(k - j).append(s.charAt(j)); 48 | } 49 | s = t.toString(); 50 | } 51 | return s; 52 | } 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/tree/array47_maxDepth.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.tree; 2 | 3 | import com.example.leetcode.linkedlist.pojo.TreeNode; 4 | 5 | import java.util.LinkedList; 6 | import java.util.Queue; 7 | 8 | /** 9 | * @description: 二叉树最大深度 10 | * 给定一个二叉树,找出其最大深度。 11 | * 12 | * 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 13 | * 14 | * 说明: 叶子节点是指没有子节点的节点。 15 | * 16 | * 示例: 17 | * 给定二叉树 [3,9,20,null,null,15,7], 18 | * 19 | * 3 20 | * / \ 21 | * 9 20 22 | * / \ 23 | * 15 7 24 | * 返回它的最大深度 3 。 25 | * @author: icecrea 26 | * @create: 2019-03-18 10:38 27 | **/ 28 | public class array47_maxDepth { 29 | public int maxDepth(TreeNode root) { 30 | if (root == null) { 31 | return 0; 32 | } 33 | int left = maxDepth(root.left); 34 | int right = maxDepth(root.right); 35 | return Math.max(left, right) + 1; 36 | } 37 | 38 | /** 39 | * 利用队列 40 | */ 41 | public int maxDepth2(TreeNode root) { 42 | if (root == null) { 43 | return 0; 44 | } 45 | Queue queue = new LinkedList<>(); 46 | queue.add(root); 47 | int depth = 0, count = 0, nextCount = 1; 48 | while (queue.size() != 0) { 49 | TreeNode top = queue.poll(); 50 | count++; 51 | if (top.left != null) { 52 | queue.add(top.left); 53 | } 54 | if (top.right != null) { 55 | queue.add(top.right); 56 | } 57 | if (count == nextCount) { 58 | nextCount = queue.size(); 59 | count = 0; 60 | depth++; 61 | } 62 | } 63 | return depth; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/tree/array48_isValidBST.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.tree; 2 | 3 | import com.example.leetcode.linkedlist.pojo.TreeNode; 4 | 5 | /** 6 | * @description: 验证二叉搜索树 7 | * 给定一个二叉树,判断其是否是一个有效的二叉搜索树。 8 | * 9 | * 假设一个二叉搜索树具有如下特征: 10 | * 节点的左子树只包含小于当前节点的数。 11 | * 节点的右子树只包含大于当前节点的数。 12 | * 所有左子树和右子树自身必须也是二叉搜索树。 13 | * 14 | * 示例 1: 15 | * 输入: 16 | * 2 17 | * / \ 18 | * 1 3 19 | * 输出: true 20 | * 21 | * 示例 2: 22 | * 输入: 23 | * 5 24 | * / \ 25 | * 1 4 26 | * / \ 27 | * 3 6 28 | * 输出: false 29 | * 解释: 输入为: [5,1,4,null,null,3,6]。 30 | * 根节点的值为 5 ,但是其右子节点值为 4 。 31 | * @author: icecrea 32 | * @create: 2019-03-18 10:55 33 | **/ 34 | public class array48_isValidBST { 35 | public boolean isValidBST(TreeNode root) { 36 | return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE); 37 | } 38 | 39 | /** 40 | * 防止这种情况 [10,5,15,null,null,6,20] 41 | * 所以每次传值 都要比较出最小值 要满足二叉搜索树 树的大小判断条件 42 | * 43 | * @param root 44 | * @param minVal 45 | * @param maxVal 46 | * @return 47 | */ 48 | public boolean isValidBST(TreeNode root, long minVal, long maxVal) { 49 | if (root == null) { 50 | return true; 51 | } 52 | if (root.val >= maxVal || root.val <= minVal) { 53 | return false; 54 | } 55 | return isValidBST(root.left, minVal, root.val) && isValidBST(root.right, root.val, maxVal); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/example/topinterview/easy/tree/array51_sortedArrayToBST.java: -------------------------------------------------------------------------------- 1 | package com.example.topinterview.easy.tree; 2 | 3 | import com.example.leetcode.linkedlist.pojo.TreeNode; 4 | 5 | /** 6 | * @description: 将有序数组转换为二叉搜索树 7 | * 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。 8 | * 9 | * 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。 10 | * 11 | * 示例: 12 | * 13 | * 给定有序数组: [-10,-3,0,5,9], 14 | * 15 | * 一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树: 16 | * 17 | * 0 18 | * / \ 19 | * -3 9 20 | * / / 21 | * -10 5 22 | * @author: icecrea 23 | * @create: 2019-03-18 14:14 24 | **/ 25 | public class array51_sortedArrayToBST { 26 | public TreeNode sortedArrayToBST(int[] num) { 27 | if (num.length == 0) { 28 | return null; 29 | } 30 | TreeNode head = helper(num, 0, num.length - 1); 31 | return head; 32 | } 33 | 34 | public TreeNode helper(int[] num, int low, int high) { 35 | //注意终止条件是大于 不是大于等于 36 | if (low > high) { 37 | return null; 38 | } 39 | int mid = low + (high - low) / 2; 40 | TreeNode node = new TreeNode(num[mid]); 41 | node.left = helper(num, low, mid - 1); 42 | node.right = helper(num, mid + 1, high); 43 | return node; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /wechat_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icecrea/leetcode/07dec29353ff0aebbf3afd059ade6a17f9f43ace/wechat_logo.jpg --------------------------------------------------------------------------------