├── .gitignore ├── LICENSE ├── README.md ├── images ├── leetcode-icon.png └── wxg.png └── src └── pp └── arithmetic ├── LCP ├── _1_game.java ├── _2_fraction.java ├── _3_robot.java ├── _4_domino.java ├── _5_bonus.java ├── _5_bonus_2.java └── _6_minCount.java ├── Util.java ├── easy ├── HammingWeightTest.java ├── HasCycleTest.java ├── IsPalindromeTest.java ├── MinDepthTest.java ├── ThreeSumClosestTest.java └── ThreeSumTest.java ├── leetcode ├── _1004_longestOnes.java ├── _100_isSameTree.java ├── _101_isSymmetric.java ├── _1025_divisorGame.java ├── _102_levelOrder.java ├── _103_zigzagLevelOrder.java ├── _1046_lastStoneWeight.java ├── _1049_lastStoneWeightII.java ├── _104_maxDepth.java ├── _1051_heightChecker.java ├── _1052_maxSatisfied.java ├── _1053_prevPermOpt1.java ├── _1054_rearrangeBarcodes.java ├── _105_buildTree.java ├── _106_buildTree.java ├── _107_levelOrderBottom.java ├── _108_sortedArrayToBST.java ├── _109_sortedListToBST.java ├── _10_isMatch.java ├── _10_isMatch_2.java ├── _110_isBalanced.java ├── _1114_Foo.java ├── _1115_FooBar.java ├── _1116_ZeroEvenOdd.java ├── _1117_H2O.java ├── _111_minDepth.java ├── _112_hasPathSum.java ├── _113_pathSum.java ├── _114_flatten.java ├── _115_numDistinct.java ├── _116_connect.java ├── _117_connect.java ├── _118_generate.java ├── _1195_FizzBuzz.java ├── _119_getRow.java ├── _11_maxArea.java ├── _120_minimumTotal.java ├── _121_maxProfit.java ├── _1226_DiningPhilosophers.java ├── _122_maxProfit.java ├── _123_maxProfit.java ├── _124_maxPathSum.java ├── _126_findLadders.java ├── _127_ladderLength.java ├── _127_ladderLength_2.java ├── _128_longestConsecutive.java ├── _129_sumNumbers.java ├── _12_intToRoman.java ├── _130_solve.java ├── _131_partition.java ├── _132_minCut.java ├── _133_cloneGraph.java ├── _136_singleNumber.java ├── _138_CopyRandomList.java ├── _139_wordBreak.java ├── _13_romanToInt.java ├── _141_HasCycle.java ├── _142_DetectCycle.java ├── _146_LRUCache.java ├── _147_insertionSortList.java ├── _148_sortList.java ├── _14_longestCommonPrefix.java ├── _151_reverseWords.java ├── _151_reverseWords_2.java ├── _152_maxProduct.java ├── _155_MinStack.java ├── _15_threeSum.java ├── _160_GetIntersectionNode.java ├── _167_twoSum.java ├── _169_majorityElement.java ├── _16_threeSumClosest.java ├── _174_calculateMinimumHP.java ├── _17_letterCombinations.java ├── _187_findRepeatedDnaSequences.java ├── _188_maxProfit.java ├── _18_fourSum.java ├── _190_reverseBits.java ├── _198_rob.java ├── _199_rightSideView.java ├── _19_RemoveNthFromEnd.java ├── _1_twoSum.java ├── _200_numIslands.java ├── _203_removeElements.java ├── _206_ReverseList.java ├── _206_ReverseList_2.java ├── _207_canFinish.java ├── _208_Trie.java ├── _20_isValid.java ├── _211_wordDictionary.java ├── _213_rob.java ├── _214_shortestPalindrome.java ├── _214_shortestPalindrome_2.java ├── _215_findKthLargest.java ├── _215_findKthLargest_2.java ├── _21_MergeTwoLists.java ├── _221_maximalSquare.java ├── _225_MyStack.java ├── _226_invertTree.java ├── _22_generateParenthesis.java ├── _232_MyQuene.java ├── _234_isPalindrome.java ├── _236_lowestCommonAncestor.java ├── _237_deleteNode.java ├── _238_productExceptSelf.java ├── _239_maxSlidingWindow.java ├── _23_mergeKLists.java ├── _240_searchMatrix.java ├── _24_SwapPairs.java ├── _25_reverseKGroup.java ├── _264_nthUglyNumber.java ├── _26_removeDuplicates.java ├── _279_numSquares.java ├── _27_removeElement.java ├── _283_moveZeroes.java ├── _287_findDuplicate.java ├── _28_strStr.java ├── _290_wordPattern.java ├── _297_Codec.java ├── _29_divide.java ├── _2_addTwoNumbers.java ├── _300_lengthOfLIS.java ├── _301_removeInvalidParentheses.java ├── _303_NumArray.java ├── _304_NumMatrix.java ├── _307_NumArray.java ├── _307_NumArray_2.java ├── _309_maxProfit.java ├── _30_findSubstring.java ├── _312_maxCoins.java ├── _315_countSmaller.java ├── _315_countSmaller_2.java ├── _31_nextPermutation.java ├── _322_coinChange.java ├── _328_OddEvenList.java ├── _32_longestValidParentheses.java ├── _336_palindromePairs.java ├── _336_palindromePairs_2.java ├── _337_rob.java ├── _338_countBits.java ├── _33_search.java ├── _343_integerBreak.java ├── _347_topKFrequent.java ├── _34_searchRange.java ├── _354_maxEnvelopes.java ├── _354_maxEnvelopes_2.java ├── _35_searchInsert.java ├── _36_isValidSudoku.java ├── _376_wiggleMaxLength.java ├── _37_solveSudoku.java ├── _38_countAndSay.java ├── _394_decodeString.java ├── _399_calcEquation.java ├── _39_combinationSum.java ├── _3_lengthOfLongestSubstring.java ├── _402_removeKdigits.java ├── _406_reconstructQueue.java ├── _409_longestPalindrome.java ├── _40_combinationSum2.java ├── _415_addStrings.java ├── _416_canPartition.java ├── _41_firstMissingPositive.java ├── _424_characterReplacement.java ├── _42_trap.java ├── _432_AllOne.java ├── _437_pathSum.java ├── _438_findAnagrams.java ├── _43_multiply.java ├── _448_findDisappearedNumbers.java ├── _449_serialize_deserialize.java ├── _44_isMatch.java ├── _450_deleteNode.java ├── _452_findMinArrowShots.java ├── _454_fourSumCount.java ├── _455_findContentChildren.java ├── _457_circularArrayLoop.java ├── _45_jump.java ├── _460_LFUCache.java ├── _461_hammingDistance.java ├── _46_permute.java ├── _473_makesquare.java ├── _47_permuteUnique.java ├── _485_findMaxConsecutiveOnes.java ├── _48_rotate.java ├── _494_findTargetSumWays.java ├── _49_groupAnagrams.java ├── _4_findMedianSortedArrays.java ├── _4_findMedianSortedArrays_2.java ├── _50_myPow.java ├── _516_longestPalindromeSubseq.java ├── _51_solveNQueens.java ├── _51_solveNQueens_2.java ├── _52_totalNQueens.java ├── _538_convertBST.java ├── _53_maxSubArray.java ├── _543_diameterOfBinaryTree.java ├── _547_findCircleNum.java ├── _547_findCircleNum_2.java ├── _54_spiralOrder.java ├── _55_canJump.java ├── _560_subarraySum.java ├── _563_findTilt.java ├── _567_checkInclusion.java ├── _56_merge.java ├── _57_insert.java ├── _581_findUnsortedSubarray.java ├── _58_lengthOfLastWord.java ├── _59_generateMatrix.java ├── _5_longestPalindrome.java ├── _60_getPermutation_m.java ├── _617_mergeTrees.java ├── _61_RotateRight.java ├── _621_leastInterval.java ├── _62_uniquePaths.java ├── _639_numDecodings.java ├── _63_uniquePathsWithObstacles.java ├── _647_countSubstrings.java ├── _64_minPathSum.java ├── _653_findTarget.java ├── _65_isNumber.java ├── _66_plusOne.java ├── _674_findLengthOfLCIS_e.java ├── _67_addBinary.java ├── _68_fullJustify.java ├── _695_maxAreaOfIsland.java ├── _69_mySqrt.java ├── _6_convert.java ├── _6_convert_2.java ├── _70_climbStairs.java ├── _71_simplifyPath.java ├── _72_minDistance.java ├── _739_dailyTemperatures.java ├── _73_setZeroes.java ├── _746_minCostClimbingStairs.java ├── _74_searchMatrix.java ├── _75_sortColors.java ├── _76_minWindow.java ├── _77_combine.java ├── _78_subsets.java ├── _79_exist.java ├── _7_reverse.java ├── _80_removeDuplicates.java ├── _81_search.java ├── _82_deleteDuplicates.java ├── _83_deleteDuplicates.java ├── _84_largestRectangleArea.java ├── _85_maximalRectangle.java ├── _86_Partition.java ├── _87_isScramble.java ├── _88_merge.java ├── _89_grayCode.java ├── _8_myAtoi.java ├── _90_subsetsWithDup.java ├── _91_numDecodings.java ├── _92_ReverseBetween.java ├── _93_restoreIpAddresses.java ├── _94_inorderTraversal.java ├── _95_generateTrees.java ├── _96_numTrees.java ├── _978_maxTurbulenceSize.java ├── _97_isInterleave.java ├── _98_isValidBST.java ├── _99_recoverTree.java └── _9_isPalindrome.java ├── medium ├── BasicCalculateTest.java ├── LegalOrder.java └── _poj_1915_move.java ├── model ├── DisjointSet.java ├── ListNode.java ├── Node.java ├── RandomListNode.java ├── TreeNode.java └── TrieTree.java ├── offer ├── _03_findRepeatNumber.java ├── _04_findNumberIn2DArray.java ├── _05_replaceSpace.java ├── _06_reversePrint.java ├── _07_buildTree.java ├── _09_CQueue.java ├── _10_2_numWays.java ├── _10_fib.java ├── _11_minArray.java ├── _12_exist.java ├── _13_movingCount.java ├── _14_1_cuttingRope.java ├── _15_hammingWeight.java ├── _16_myPow.java ├── _17_printNumbers.java └── _18_deleteNode.java └── other ├── Search.java └── Sort.java /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | .classpath 3 | .project 4 | /.settings 5 | .idea/ 6 | ArithmeticTest.iml 7 | out/ 8 | /src/pp/arithmetic/Test.java -------------------------------------------------------------------------------- /images/leetcode-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pphdsny/Leetcode-Java/f1b3876b2f3de7c06c17a6a2a6d483541d1af514/images/leetcode-icon.png -------------------------------------------------------------------------------- /images/wxg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pphdsny/Leetcode-Java/f1b3876b2f3de7c06c17a6a2a6d483541d1af514/images/wxg.png -------------------------------------------------------------------------------- /src/pp/arithmetic/LCP/_1_game.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.LCP; 2 | 3 | /** 4 | * Created by wangpeng on 2019-10-09. 5 | * LCP 1. 猜数字 6 | * 7 | * 小A 和 小B 在玩猜数字。小B 每次从 1, 2, 3 中随机选择一个,小A 每次也从 1, 2, 3 中选择一个猜。他们一共进行三次这个游戏,请返回 小A 猜对了几次? 8 | * 9 | *   10 | * 11 | * 输入的guess数组为 小A 每次的猜测,answer数组为 小B 每次的选择。guess和answer的长度都等于3。 12 | * 13 | *   14 | * 15 | * 示例 1: 16 | * 17 | * 输入:guess = [1,2,3], answer = [1,2,3] 18 | * 输出:3 19 | * 解释:小A 每次都猜对了。 20 | *   21 | * 22 | * 示例 2: 23 | * 24 | * 输入:guess = [2,2,3], answer = [3,2,1] 25 | * 输出:1 26 | * 解释:小A 只猜对了第二次。 27 | *   28 | * 29 | * 限制: 30 | * 31 | * guess的长度 = 3 32 | * answer的长度 = 3 33 | * guess的元素取值为 {1, 2, 3} 之一。 34 | * answer的元素取值为 {1, 2, 3} 之一。 35 | * 36 | * 来源:力扣(LeetCode) 37 | * 链接:https://leetcode-cn.com/problems/guess-numbers 38 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 39 | */ 40 | public class _1_game { 41 | 42 | public static void main(String[] args) { 43 | _1_game game = new _1_game(); 44 | System.out.println(game.game(new int[]{1, 2, 3}, new int[]{1, 2, 3})); 45 | System.out.println(game.game(new int[]{2, 2, 3}, new int[]{3, 2, 1})); 46 | } 47 | 48 | /** 49 | * 解题思路: 50 | * 最简单的循环比较是否相等即可 51 | * 52 | * @param guess 53 | * @param answer 54 | * @return 55 | */ 56 | public int game(int[] guess, int[] answer) { 57 | int ret = 0; 58 | for (int i = 0; i < guess.length; i++) { 59 | if (guess[i] == answer[i]) { 60 | ret++; 61 | } 62 | } 63 | return ret; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/pp/arithmetic/LCP/_6_minCount.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.LCP; 2 | 3 | /** 4 | * Created by wangpeng on 2020-09-02. 5 | * LCP 06. 拿硬币 6 | *

7 | * 桌上有 n 堆力扣币,每堆的数量保存在数组 coins 中。我们每次可以选择任意一堆,拿走其中的一枚或者两枚,求拿完所有力扣币的最少次数。 8 | *

9 | * 示例 1: 10 | *

11 | * 输入:[4,2,1] 12 | *

13 | * 输出:4 14 | *

15 | * 解释:第一堆力扣币最少需要拿 2 次,第二堆最少需要拿 1 次,第三堆最少需要拿 1 次,总共 4 次即可拿完。 16 | *

17 | * 示例 2: 18 | *

19 | * 输入:[2,3,10] 20 | *

21 | * 输出:8 22 | *

23 | * 限制: 24 | *

25 | * 1 <= n <= 4 26 | * 1 <= coins[i] <= 10 27 | *

28 | * 来源:力扣(LeetCode) 29 | * 链接:https://leetcode-cn.com/problems/na-ying-bi 30 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 31 | */ 32 | public class _6_minCount { 33 | 34 | public static void main(String[] args) { 35 | _6_minCount minCount = new _6_minCount(); 36 | System.out.println(minCount.minCount(new int[]{4, 2, 1})); 37 | System.out.println(minCount.minCount(new int[]{2, 3, 10})); 38 | 39 | } 40 | 41 | /** 42 | * 解题思路: 43 | * 需要最少次数,利用贪心的思路,每次尽可能的多拿(也就是2个) 44 | * 45 | * @param coins 46 | * @return 47 | */ 48 | public int minCount(int[] coins) { 49 | if (coins == null) return 0; 50 | int retVal = 0; 51 | for (int i = 0; i < coins.length; i++) { 52 | int coin = coins[i]; 53 | if (coin % 2 == 0) { 54 | retVal += coin / 2; 55 | } else { 56 | retVal += coin / 2 + 1; 57 | } 58 | } 59 | 60 | return retVal; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/pp/arithmetic/easy/HammingWeightTest.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.easy; 2 | 3 | import pp.arithmetic.model.TreeNode; 4 | 5 | /** 6 | * 7 | * @author pphdsny 8 | * 9 | * Write a function that takes an unsigned integer and returns the 10 | * number of ’1' bits it has (also known as the Hamming weight). 11 | * 12 | * For example, the 32-bit integer ’11' has binary representation 13 | * 00000000000000000000000000001011, so the function should return 3. 14 | * 15 | * {@link https://leetcode.com/problems/number-of-1-bits/} 16 | */ 17 | public class HammingWeightTest { 18 | 19 | public static void main(String[] args) { 20 | int result = hammingWeight(111); 21 | System.err.println("包含1的个数:" + result); 22 | } 23 | 24 | /** 25 | * 3ms 26 | * 27 | * @param n 28 | * @return 29 | */ 30 | public static int hammingWeight(int n) { 31 | String hexString = Integer.toBinaryString(n); 32 | char[] array = hexString.toCharArray(); 33 | int result = 0; 34 | for (int i = 0; i < array.length; i++) { 35 | if (array[i] == '1') { 36 | result++; 37 | } 38 | } 39 | return result; 40 | } 41 | 42 | /** 43 | * 2ms 44 | * 45 | * @param n 46 | * @return 47 | */ 48 | public static int hammingWeight1(int n) { 49 | int ones = 0; 50 | while (n != 0) { 51 | ones = ones + (n & 1); 52 | //无符号除2 53 | n = n >>> 1; 54 | } 55 | return ones; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/pp/arithmetic/easy/HasCycleTest.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.easy; 2 | 3 | /** 4 | * Created by wangpeng on 16/5/19. 5 | * Given a linked list, determine if it has a cycle in it. 6 | *

7 | * Follow up: 8 | * Can you solve it without using extra space? 9 | * {@link https://leetcode.com/problems/linked-list-cycle/} 10 | */ 11 | public class HasCycleTest { 12 | 13 | public static void main(String[] args) { 14 | 15 | } 16 | 17 | public boolean hasCycle(ListNode head) { 18 | if (head == null || head.next == null) { 19 | return false; 20 | } 21 | ListNode slower = head; 22 | ListNode faster = head; 23 | while (faster.next != null && faster.next.next != null) { 24 | slower = slower.next; 25 | faster = faster.next.next; 26 | if (slower == faster) { 27 | return true; 28 | } 29 | } 30 | return false; 31 | } 32 | 33 | private class ListNode { 34 | int val; 35 | ListNode next; 36 | 37 | ListNode(int x) { 38 | val = x; 39 | next = null; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/pp/arithmetic/easy/MinDepthTest.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.easy; 2 | 3 | import pp.arithmetic.model.TreeNode; 4 | 5 | /** 6 | * 7 | * @author pphdsny 8 | * 9 | * Given a binary tree, find its minimum depth. 10 | * 11 | * The minimum depth is the number of nodes along the shortest path from 12 | * the root node down to the nearest leaf node. 13 | * 14 | * {@link https://leetcode.com/problems/minimum-depth-of-binary-tree/} 15 | */ 16 | public class MinDepthTest { 17 | 18 | public static void main(String[] args) { 19 | } 20 | 21 | public static int minDepth(TreeNode root) { 22 | if (root == null) { 23 | return 0; 24 | } 25 | int left = minDepth(root.left); 26 | int right = minDepth(root.right); 27 | return (left == 0 || right == 0) ? left + right + 1 : Math.min(left, right) + 1; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/pp/arithmetic/easy/ThreeSumClosestTest.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.easy; 2 | 3 | /** 4 | * Created by wangpeng on 2017/1/13. 5 | */ 6 | public class ThreeSumClosestTest { 7 | public static void main(String[] args) { 8 | 9 | } 10 | 11 | /** 12 | * https://leetcode.com/problems/3sum-closest/ 13 | * @param nums 14 | * @param target 15 | * @return 16 | */ 17 | public static int threeSumClosest(int[] nums,int target){ 18 | return 0; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_100_isSameTree.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.model.TreeNode; 4 | 5 | /** 6 | * Created by wangpeng on 2019-12-04. 7 | * 100. 相同的树 8 | * 9 | * 给定两个二叉树,编写一个函数来检验它们是否相同。 10 | * 11 | * 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。 12 | * 13 | * 示例 1: 14 | * 15 | * 输入: 1 1 16 | * / \ / \ 17 | * 2 3 2 3 18 | * 19 | * [1,2,3], [1,2,3] 20 | * 21 | * 输出: true 22 | * 示例 2: 23 | * 24 | * 输入: 1 1 25 | * / \ 26 | * 2 2 27 | * 28 | * [1,2], [1,null,2] 29 | * 30 | * 输出: false 31 | * 示例 3: 32 | * 33 | * 输入: 1 1 34 | * / \ / \ 35 | * 2 1 1 2 36 | * 37 | * [1,2,1], [1,1,2] 38 | * 39 | * 输出: false 40 | * 41 | * 来源:力扣(LeetCode) 42 | * 链接:https://leetcode-cn.com/problems/same-tree 43 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 44 | */ 45 | public class _100_isSameTree { 46 | 47 | public static void main(String[] args) { 48 | _100_isSameTree isSameTree = new _100_isSameTree(); 49 | TreeNode p = new TreeNode(1); 50 | p.left = new TreeNode(2); 51 | p.right = new TreeNode(3); 52 | TreeNode q = new TreeNode(1); 53 | q.left = new TreeNode(2); 54 | // q.right = new TreeNode(3); 55 | 56 | System.out.println(isSameTree.isSameTree(p,q)); 57 | } 58 | 59 | /** 60 | * 解题思路: 61 | * 典型的树的深度遍历(DFS) 62 | * 1、判断左子树是否相同 63 | * 2、判断右子树是否相同 64 | * 3、判断父节点是否相同 65 | * 66 | * @param p 67 | * @param q 68 | * @return 69 | */ 70 | public boolean isSameTree(TreeNode p, TreeNode q) { 71 | if (p== null && q == null) return true; 72 | if (p == null || q == null) return false; 73 | return isSameTree(p.left,q.left) && isSameTree(p.right,q.right) && p.val == q.val; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_1025_divisorGame.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by wangpeng on 2019-04-22. 8 | * 1025. 除数博弈 9 | *

10 | * 爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。 11 | *

12 | * 最初,黑板上有一个数字 N 。在每个玩家的回合,玩家需要执行以下操作: 13 | *

14 | * 选出任一 x,满足 0 < x < N 且 N % x == 0 。 15 | * 用 N - x 替换黑板上的数字 N 。 16 | * 如果玩家无法执行这些操作,就会输掉游戏。 17 | *

18 | * 只有在爱丽丝在游戏中取得胜利时才返回 True,否则返回 false。假设两个玩家都以最佳状态参与游戏。 19 | *

20 | *

21 | *

22 | * 示例 1: 23 | *

24 | * 输入:2 25 | * 输出:true 26 | * 解释:爱丽丝选择 1,鲍勃无法进行操作。 27 | * 示例 2: 28 | *

29 | * 输入:3 30 | * 输出:false 31 | * 解释:爱丽丝选择 1,鲍勃也选择 1,然后爱丽丝无法进行操作。 32 | *

33 | *

34 | * 提示: 35 | *

36 | * 1 <= N <= 1000 37 | * 38 | * @see divisor-game 39 | */ 40 | public class _1025_divisorGame { 41 | public static void main(String[] args) { 42 | _1025_divisorGame divisorGame = new _1025_divisorGame(); 43 | System.out.println(divisorGame.divisorGame(3)); 44 | System.out.println(divisorGame.divisorGame(4)); 45 | } 46 | 47 | /** 48 | * 解题思路: 49 | * 爱丽丝可能有多种结局么?论证发现只要N给定了,结局也就定了,偶数爱丽丝必胜 50 | * 但是我们为了练习动态规划(DP),还是从动态规划的角度来思考下 51 | * 动态规划解题四部曲,可供参考 52 | *

53 | * - 确认原问题与子问题=>原问题:对于N来说爱丽丝是否能赢,子问题:对于i来说爱丽丝是否会赢 54 | * - 确认状态=> 55 | * - 确认边界状态的值=>dp[1]=false;dp[2]=true 56 | * - 确定状态转移方程=>dp[i]=!dp[i-1] 57 | * 58 | * 没看明白题目,没意思 59 | * 60 | * @param N 61 | * @return 62 | */ 63 | public boolean divisorGame(int N) { 64 | //把偶数留给自己, 把奇数留给对手, 最后剩2的时候选择1即可赢得比赛. 65 | //若己方拿到的是偶数, 每次选择 1, 就可以把奇数留给对手, 己方赢. 66 | //若己方拿到的是奇数, 一定不能选择偶数, 留给对手的一定是偶数, 对手可以留给你奇数, 对手赢. 67 | //动态规划,初始值。 68 | if (N == 1) return false; 69 | 70 | boolean[] dp = new boolean[N + 1]; 71 | dp[1] = false; 72 | 73 | for (int i = 2; i <= N; i++) { 74 | dp[i] = !dp[i - 1]; 75 | } 76 | return dp[N]; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_104_maxDepth.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.model.TreeNode; 4 | 5 | /** 6 | * Created by wangpeng on 2018/9/27. 7 | * 104.二叉树的最大深度 8 | *

9 | * 给定一个二叉树,找出其最大深度。 10 | *

11 | * 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 12 | *

13 | * 说明: 叶子节点是指没有子节点的节点。 14 | *

15 | * 示例: 16 | * 给定二叉树 [3,9,20,null,null,15,7], 17 | *

18 | * 3 19 | * / \ 20 | * 9 20 21 | * / \ 22 | * 15 7 23 | * 返回它的最大深度 3 。 24 | * 25 | * @see maximum-depth-of-binary-tree 26 | */ 27 | public class _104_maxDepth { 28 | public static void main(String[] args) { 29 | TreeNode srcRoot = new TreeNode(3); 30 | TreeNode leftTree = new TreeNode(9); 31 | TreeNode rightTree = new TreeNode(20); 32 | srcRoot.left = leftTree; 33 | srcRoot.right = rightTree; 34 | leftTree.left = new TreeNode(15); 35 | leftTree.left.left = new TreeNode(10); 36 | int maxDepth = maxDepth(srcRoot); 37 | System.out.println(maxDepth); 38 | } 39 | 40 | public static int maxDepth(TreeNode root) { 41 | if (root == null) { 42 | return 0; 43 | } 44 | int left = maxDepth(root.left); 45 | int right = maxDepth(root.right); 46 | return Math.max(left, right) + 1; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_1051_heightChecker.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by wangpeng on 2019-06-05. 7 | * 1051. 高度检查器 8 | *

9 | * 学校在拍年度纪念照时,一般要求学生按照 非递减 的高度顺序排列。 10 | *

11 | * 请你返回至少有多少个学生没有站在正确位置数量。该人数指的是:能让所有学生以 非递减 高度排列的必要移动人数。 12 | *

13 | * 示例: 14 | * 输入:[1,1,4,2,1,3] 15 | * 输出:3 16 | * 解释: 17 | * 高度为 4、3 和最后一个 1 的学生,没有站在正确的位置。 18 | *

19 | * 1 <= heights.length <= 100 20 | * 1 <= heights[i] <= 100 21 | * 22 | * @see height-checker 23 | */ 24 | public class _1051_heightChecker { 25 | public static void main(String[] args) { 26 | _1051_heightChecker heightChecker = new _1051_heightChecker(); 27 | System.out.println(heightChecker.heightChecker(new int[]{1, 1, 4, 2, 1, 3})); 28 | } 29 | 30 | /** 31 | * 解题思路: 32 | * 1.对数组进行排序 33 | * 2.循环遍历原始数组和排序数组,找到差异 34 | *

35 | * 解题时间复杂度(O(nLogn+n)),不知道是否能提交通过,easy的题看来不能考虑太多 36 | * 37 | * @param heights 38 | * @return 39 | */ 40 | public int heightChecker(int[] heights) { 41 | int[] sortHeights = new int[heights.length]; 42 | System.arraycopy(heights, 0, sortHeights, 0, heights.length); 43 | Arrays.sort(sortHeights); 44 | int diffCount = 0; 45 | for (int i = 0; i < heights.length; i++) { 46 | if (heights[i] != sortHeights[i]) { 47 | diffCount++; 48 | } 49 | } 50 | 51 | return diffCount; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_106_buildTree.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.TreeNode; 5 | 6 | import java.util.Arrays; 7 | 8 | /** 9 | * Created by wangpeng on 2019-12-09. 10 | * 106. 从中序与后序遍历序列构造二叉树 11 | * 12 | * 根据一棵树的中序遍历与后序遍历构造二叉树。 13 | * 14 | * 注意: 15 | * 你可以假设树中没有重复的元素。 16 | * 17 | * 例如,给出 18 | * 19 | * 中序遍历 inorder = [9,3,15,20,7] 20 | * 后序遍历 postorder = [9,15,7,20,3] 21 | * 返回如下的二叉树: 22 | * 23 | * 3 24 | * / \ 25 | * 9 20 26 | * / \ 27 | * 15 7 28 | * 29 | * 来源:力扣(LeetCode) 30 | * 链接:https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal 31 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 32 | */ 33 | public class _106_buildTree { 34 | 35 | public static void main(String[] args) { 36 | _106_buildTree buildTree = new _106_buildTree(); 37 | TreeNode treeNode = buildTree.buildTree(new int[]{9, 3, 15, 20, 7}, new int[]{9, 15, 7, 20, 3}); 38 | Util.printTree(treeNode); 39 | } 40 | 41 | /** 42 | * 解题思路: 43 | * 中序:左->中->右,后序:左->右->中 44 | * 1、取后序的最后一位就是根节点 45 | * 2、遍历中序,找到根节点在中序中的位置I,I左边的就是左子树,右边就是右子树 46 | * 3、分别取中序和后续的0-I位置,得到的就是左子树的中序和后续遍历接通,重复步骤1、2将左子树构造出来 47 | * 4、同理步骤3,将右子树构造出来 48 | * 49 | * 执行用时 :19 ms, 在所有 java 提交中击败了29.64%的用户 50 | * 内存消耗 :77.3 MB, 在所有 java 提交中击败了5.17%的用户 51 | * 52 | * 用时耗时优化建议:Arrays.copy可以转换为数组的index下标遍历 53 | * 54 | * @param inorder 55 | * @param postorder 56 | * @return 57 | */ 58 | public TreeNode buildTree(int[] inorder, int[] postorder) { 59 | if (inorder.length == 0) return null; 60 | int rootVal = postorder[postorder.length - 1]; 61 | TreeNode rootNode = new TreeNode(rootVal); 62 | int rootIndex = 0; 63 | for (int i = 0; i < inorder.length; i++) { 64 | if (inorder[i] == rootVal){ 65 | rootIndex = i; 66 | break; 67 | } 68 | } 69 | rootNode.left = buildTree(Arrays.copyOfRange(inorder, 0, rootIndex), Arrays.copyOfRange(postorder, 0, rootIndex)); 70 | rootNode.right = buildTree(Arrays.copyOfRange(inorder, rootIndex + 1, inorder.length), Arrays.copyOfRange(postorder, rootIndex, postorder.length - 1)); 71 | return rootNode; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_108_sortedArrayToBST.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.TreeNode; 5 | 6 | /** 7 | * Created by wangpeng on 2018/9/26. 8 | * 108.将有序数组转换为二叉搜索树 9 | *

10 | * 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。 11 | *

12 | * 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。 13 | *

14 | * 示例: 15 | *

16 | * 给定有序数组: [-10,-3,0,5,9], 17 | *

18 | * 一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树: 19 | *

20 | * 0 21 | * / \ 22 | * -3 9 23 | * / / 24 | * -10 5 25 | * 26 | * @see convert-sorted-array-to-binary-search-tree 27 | */ 28 | public class _108_sortedArrayToBST { 29 | 30 | public static void main(String[] args) { 31 | TreeNode treeNode = sortedArrayToBST(new int[]{-10, -3, 0, 5, 9}); 32 | Util.printTree(treeNode); 33 | } 34 | 35 | public static TreeNode sortedArrayToBST(int[] nums) { 36 | TreeNode treeNode = generate(nums, 0, nums.length); 37 | return treeNode; 38 | } 39 | 40 | private static TreeNode generate(int[] nums, 41 | int start, 42 | int end) { 43 | //[-10,-3,0,5,9] 44 | if (start >= end) { 45 | return null; 46 | } 47 | int middle = (start + end) / 2; 48 | TreeNode treeNode = new TreeNode(nums[middle]); 49 | TreeNode leftNode = generate(nums, start, middle); 50 | TreeNode rightNode = generate(nums, middle + 1, end); 51 | treeNode.left = leftNode; 52 | treeNode.right = rightNode; 53 | return treeNode; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_110_isBalanced.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import javafx.util.Pair; 4 | import pp.arithmetic.Util; 5 | import pp.arithmetic.model.TreeNode; 6 | 7 | /** 8 | * Created by wangpeng on 2019-12-12. 9 | * 110. 平衡二叉树 10 | * 11 | * 给定一个二叉树,判断它是否是高度平衡的二叉树。 12 | * 13 | * 本题中,一棵高度平衡二叉树定义为: 14 | * 15 | * 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。 16 | * 17 | * 示例 1: 18 | * 19 | * 给定二叉树 [3,9,20,null,null,15,7] 20 | * 21 | * 3 22 | * / \ 23 | * 9 20 24 | * / \ 25 | * 15 7 26 | * 返回 true 。 27 | * 28 | * 示例 2: 29 | * 30 | * 给定二叉树 [1,2,2,3,3,null,null,4,4] 31 | * 32 | * 1 33 | * / \ 34 | * 2 2 35 | * / \ 36 | * 3 3 37 | * / \ 38 | * 4 4 39 | * 返回 false 。 40 | * 41 | * 来源:力扣(LeetCode) 42 | * 链接:https://leetcode-cn.com/problems/balanced-binary-tree 43 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 44 | */ 45 | public class _110_isBalanced { 46 | 47 | public static void main(String[] args) { 48 | _110_isBalanced isBalanced = new _110_isBalanced(); 49 | TreeNode treeNode = Util.generateTreeNode(new Integer[]{3, 9, 20, null, null, 15, 7}); 50 | System.out.println(isBalanced.isBalanced(treeNode)); 51 | TreeNode treeNode2 = Util.generateTreeNode(new Integer[]{1,2,2,3,3,null,null,4,4}); 52 | System.out.println(isBalanced.isBalanced(treeNode2)); 53 | } 54 | 55 | /** 56 | * 解题思路: 57 | * 1、递归计算左右子树的高度 58 | * 2、取左右子树的最大高度+1,即是该根节点的高度 59 | * 3、由于每个节点都需要满足高度平衡二叉树的条件,所以递归返回一个Pair 60 | * @param root 61 | * @return 62 | */ 63 | public boolean isBalanced(TreeNode root) { 64 | return dfs(root).getKey(); 65 | } 66 | 67 | private Pair dfs(TreeNode root) { 68 | if (root == null) return new Pair<>(true, 0); 69 | Pair left = dfs(root.left); 70 | Pair right = dfs(root.right); 71 | return new Pair<>(left.getKey() && right.getKey() && (Math.abs(left.getValue() - right.getValue()) <= 1), Math.max(left.getValue(), right.getValue()) + 1); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_111_minDepth.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.TreeNode; 5 | 6 | /** 7 | * Created by wangpeng on 2019-12-12. 8 | * 111. 二叉树的最小深度 9 | * 10 | * 给定一个二叉树,找出其最小深度。 11 | * 12 | * 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 13 | * 14 | * 说明: 叶子节点是指没有子节点的节点。 15 | * 16 | * 示例: 17 | * 18 | * 给定二叉树 [3,9,20,null,null,15,7], 19 | * 20 | * 3 21 | * / \ 22 | * 9 20 23 | * / \ 24 | * 15 7 25 | * 返回它的最小深度  2. 26 | * 27 | * 来源:力扣(LeetCode) 28 | * 链接:https://leetcode-cn.com/problems/minimum-depth-of-binary-tree 29 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 30 | */ 31 | public class _111_minDepth { 32 | 33 | public static void main(String[] args) { 34 | _111_minDepth minDepth = new _111_minDepth(); 35 | System.out.println(minDepth.minDepth(Util.generateTreeNode(new Integer[]{3, 9, 20, null, null, 15, 7}))); 36 | } 37 | 38 | /** 39 | * 解题思路:DFS求解 40 | * 1、求左子树的最小深度 41 | * 2、求右子树的最小深度 42 | * 3、求根节点的最小深度 = Math.min(left,right)+1 43 | * 44 | * 需要注意一点:如左/右子树为空,得取有值得叶节点长度 45 | * 46 | * @param root 47 | * @return 48 | */ 49 | public int minDepth(TreeNode root) { 50 | if (root == null) return 0; 51 | int left = minDepth(root.left); 52 | int right = minDepth(root.right); 53 | return (left == 0 || right == 0) ? left + right + 1 : Math.min(left, right) + 1; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_112_hasPathSum.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.TreeNode; 5 | 6 | /** 7 | * Created by wangpeng on 2019-12-12. 8 | * 112. 路径总和 9 | * 10 | * 给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。 11 | * 12 | * 说明: 叶子节点是指没有子节点的节点。 13 | * 14 | * 示例:  15 | * 给定如下二叉树,以及目标和 sum = 22, 16 | * 17 | * 5 18 | * / \ 19 | * 4 8 20 | * / / \ 21 | * 11 13 4 22 | * / \ \ 23 | * 7 2 1 24 | * 返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。 25 | * 26 | * 来源:力扣(LeetCode) 27 | * 链接:https://leetcode-cn.com/problems/path-sum 28 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 29 | */ 30 | public class _112_hasPathSum { 31 | 32 | public static void main(String[] args) { 33 | _112_hasPathSum hasPathSum = new _112_hasPathSum(); 34 | TreeNode treeNode = Util.generateTreeNode(new Integer[]{5, 4, 7, 11, null, 13, 4, 7, 2, null, null, null, 1}); 35 | System.out.println(hasPathSum.hasPathSum(treeNode,22)); 36 | System.out.println(hasPathSum.hasPathSum(Util.generateTreeNode(new Integer[]{1,2}),1)); 37 | } 38 | 39 | /** 40 | * 解题思路: 41 | * 1、sum减去当前根节点的val,将新的sum传递给左右子树 42 | * 2、左右子树重复步骤1 43 | * 3、如最终的节点==null并且sum==0则找到目标路径 44 | * 45 | * 注意:叶节点的定义 46 | * 47 | * @param root 48 | * @param sum 49 | * @return 50 | */ 51 | public boolean hasPathSum(TreeNode root, int sum) { 52 | if (root == null) return false; 53 | return dfs(root, sum); 54 | } 55 | 56 | private boolean dfs(TreeNode root, int sum) { 57 | if (root == null) return sum == 0; 58 | int newSum = sum - root.val; 59 | if (root.left == null && root.right == null) return newSum == 0; 60 | boolean left = dfs(root.left, newSum); 61 | boolean right = dfs(root.right, newSum); 62 | if (root.left != null && root.right != null) return left || right; 63 | if (root.left != null) return left; 64 | if (root.right != null) return right; 65 | return false; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_113_pathSum.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.TreeNode; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * Created by wangpeng on 2018/9/14. 11 | * 113. 路径总和 II 12 | * 给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。 13 | *

14 | * 说明: 叶子节点是指没有子节点的节点。 15 | *

16 | * 示例: 17 | * 给定如下二叉树,以及目标和 sum = 22, 18 | *

19 | * 5 20 | * / \ 21 | * 4 8 22 | * / / \ 23 | * 11 13 4 24 | * / \ / \ 25 | * 7 2 5 1 26 | * 返回: 27 | *

28 | * [ 29 | * [5,4,11,2], 30 | * [5,8,4,5] 31 | * ] 32 | * 33 | * @see path-sum-ii 34 | */ 35 | public class _113_pathSum { 36 | public static void main(String[] args) { 37 | TreeNode treeNode = Util.generateTreeNode(); 38 | List> lists = pathSum(treeNode, 22); 39 | for (int i = 0; i < lists.size(); i++) { 40 | Util.printList(lists.get(i)); 41 | } 42 | } 43 | 44 | public static List> pathSum(TreeNode root, int sum) { 45 | List> result = new ArrayList<>(); 46 | List path = new ArrayList<>(); 47 | dfs(root, sum, path, 0, result); 48 | return result; 49 | } 50 | 51 | private static void dfs(TreeNode root, 52 | int sum, 53 | List path, 54 | int pathSum, 55 | List> result) { 56 | if (root == null) { 57 | return; 58 | } 59 | path.add(root.val); 60 | pathSum += root.val; 61 | if (pathSum == sum && root.left == null && root.right == null) { 62 | result.add(new ArrayList<>(path)); 63 | } 64 | dfs(root.left, sum, path, pathSum, result); 65 | dfs(root.right, sum, path, pathSum, result); 66 | path.remove(path.size() - 1); 67 | pathSum -= root.val; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_118_generate.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by wangpeng on 2019-12-18. 10 | * 118. 杨辉三角 11 | * 12 | * 13 | * 给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。 14 | * 15 | * https://upload.wikimedia.org/wikipedia/commons/0/0d/PascalTriangleAnimated2.gif 16 | * 17 | * 在杨辉三角中,每个数是它左上方和右上方的数的和。 18 | * 19 | * 示例: 20 | * 21 | * 输入: 5 22 | * 输出: 23 | * [ 24 | * [1], 25 | * [1,1], 26 | * [1,2,1], 27 | * [1,3,3,1], 28 | * [1,4,6,4,1] 29 | * ] 30 | * 31 | * 来源:力扣(LeetCode) 32 | * 链接:https://leetcode-cn.com/problems/pascals-triangle 33 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 34 | */ 35 | public class _118_generate { 36 | 37 | 38 | public static void main(String[] args) { 39 | _118_generate generate = new _118_generate(); 40 | List> list = generate.generate(5); 41 | for (int i = 0; i < list.size(); i++) { 42 | Util.printList(list.get(i)); 43 | } 44 | } 45 | 46 | /** 47 | * 解题思路: 48 | * 0、用一个list数组保存上一行的遍历结果 49 | * 1、当下一行是头和尾,直接赋值1 50 | * 2、当下一行在中间位置j,结果=preItem.get(j - 1) + preItem.get(j) 51 | * 52 | * 执行用时 :1 ms, 在所有 java 提交中击败了98.18%的用户 53 | * 内存消耗 :34.5 MB, 在所有 java 提交中击败了25.70%的用户 54 | * @param numRows 55 | * @return 56 | */ 57 | public List> generate(int numRows) { 58 | List> retList = new ArrayList<>(); 59 | List preItem = null; 60 | for (int i = 0; i < numRows; i++) { 61 | List item = new ArrayList<>(); 62 | for (int j = 0; j <= i; j++) { 63 | if (j == 0 || j == i) { 64 | item.add(1); 65 | } else { 66 | item.add(preItem.get(j - 1) + preItem.get(j)); 67 | } 68 | } 69 | preItem = item; 70 | retList.add(item); 71 | } 72 | return retList; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_119_getRow.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by wangpeng on 2019-12-18. 10 | * 119. 杨辉三角 II 11 | * 12 | * 给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。 13 | * 14 | * https://upload.wikimedia.org/wikipedia/commons/0/0d/PascalTriangleAnimated2.gif 15 | * 16 | * 在杨辉三角中,每个数是它左上方和右上方的数的和。 17 | * 18 | * 示例: 19 | * 20 | * 输入: 3 21 | * 输出: [1,3,3,1] 22 | * 进阶: 23 | * 24 | * 你可以优化你的算法到 O(k) 空间复杂度吗? 25 | * 26 | * 来源:力扣(LeetCode) 27 | * 链接:https://leetcode-cn.com/problems/pascals-triangle-ii 28 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 29 | */ 30 | public class _119_getRow { 31 | 32 | public static void main(String[] args) { 33 | _119_getRow getRow = new _119_getRow(); 34 | Util.printList(getRow.getRow(6)); 35 | } 36 | 37 | /** 38 | * 解题思路: 39 | * 最简单的就是像 {@link _118_generate} 中解题方式,求出第row行的结果,可是期望 O(k) 空间复杂度,这是难点 40 | * 考虑能不能通过规律找出直接计算第row行的结果? 41 | * 通过杨辉三角规律可知,第i行第j个得数字结果是(i,j)的组合数 42 | * 43 | * 执行用时 :1 ms, 在所有 java 提交中击败了93.68%的用户 44 | * 内存消耗 :33.6 MB, 在所有 java 提交中击败了23.63%的用户 45 | * 46 | * @param rowIndex 47 | * @return 48 | */ 49 | public List getRow(int rowIndex) { 50 | List retList = new ArrayList<>(); 51 | int N = rowIndex; 52 | long pre = 1; 53 | retList.add(1); 54 | for (int k = 1; k <= N; k++) { 55 | long cur = pre * (N - k + 1) / k; 56 | retList.add((int) cur); 57 | pre = cur; 58 | } 59 | return retList; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_11_maxArea.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-03-22. 5 | * 11. 盛最多水的容器 6 | *

7 | * 给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。 8 | * 在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。 9 | * 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 10 | *

11 | * 说明:你不能倾斜容器,且 n 的值至少为 2。 12 | * 13 | * 14 | *

15 | * 图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。 16 | *

17 | * 示例: 18 | *

19 | * 输入: [1,8,6,2,5,4,8,3,7] 20 | * 输出: 49 21 | * 22 | * @see container-with-most-water 23 | */ 24 | public class _11_maxArea { 25 | 26 | public static void main(String[] args) { 27 | _11_maxArea maxArea = new _11_maxArea(); 28 | System.out.println(maxArea.maxArea(new int[]{1, 8, 6, 2, 5, 4, 8, 3, 7})); 29 | } 30 | 31 | public int maxArea(int[] height) { 32 | int startI = 0, endI = height.length - 1; 33 | int max = 0; 34 | while (startI < endI) { 35 | int minHeight = Math.min(height[startI], height[endI]); 36 | int area = minHeight * (endI - startI); 37 | max = Math.max(area, max); 38 | if (height[startI] < height[endI]) { 39 | startI++; 40 | } else { 41 | endI--; 42 | } 43 | } 44 | 45 | return max; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_121_maxProfit.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018-12-04. 5 | * 121. 买卖股票的最佳时机 6 | *

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 | * 25 | * @see best-time-to-buy-and-sell-stock 26 | */ 27 | public class _121_maxProfit { 28 | public static void main(String[] args) { 29 | System.out.println(maxProfit(new int[]{7, 1, 5, 3, 6, 4})); 30 | } 31 | 32 | /** 33 | * 解答: 34 | * 35 | * @param prices 36 | * @return 37 | */ 38 | public static int maxProfit(int[] prices) { 39 | if (prices == null || prices.length <= 1) { 40 | return 0; 41 | } 42 | int min = prices[0]; 43 | int max = 0; 44 | for (int i = 1; i < prices.length; i++) { 45 | if (prices[i] > min) { 46 | int temp = prices[i] - min; 47 | max = temp > max ? temp : max; 48 | } else { 49 | min = prices[i]; 50 | } 51 | } 52 | return max; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_122_maxProfit.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018-12-04. 5 | * 122. 买卖股票的最佳时机 II 6 | *

7 | * 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 8 | *

9 | * 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 10 | *

11 | * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 12 | *

13 | * 示例 1: 14 | *

15 | * 输入: [7,1,5,3,6,4] 16 | * 输出: 7 17 | * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 18 | * 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 19 | * 示例 2: 20 | *

21 | * 输入: [1,2,3,4,5] 22 | * 输出: 4 23 | * 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 24 | * 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 25 | * 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 26 | * 示例 3: 27 | *

28 | * 输入: [7,6,4,3,1] 29 | * 输出: 0 30 | * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 31 | * 32 | * @see best-time-to-buy-and-sell-stock-ii 33 | */ 34 | public class _122_maxProfit { 35 | public static void main(String[] args) { 36 | System.out.println(maxProfit(new int[]{7, 1, 5, 3, 6, 4})); 37 | System.out.println(maxProfit(new int[]{1, 2, 3, 4, 5})); 38 | } 39 | 40 | /** 41 | * 贪心规律(谷底谷峰):只要涨我就一直不卖,当我开始跌就开始卖 42 | *

43 | * 解法说明: 44 | * 45 | * @param prices 46 | * @return 47 | */ 48 | public static int maxProfit(int[] prices) { 49 | if (prices == null || prices.length <= 1) { 50 | return 0; 51 | } 52 | int min = prices[0]; 53 | int max = prices[0]; 54 | int sum = 0; 55 | for (int i = 1; i < prices.length; i++) { 56 | if (prices[i] > max) { 57 | max = prices[i]; 58 | } else { 59 | sum += max - min; 60 | min = prices[i]; 61 | max = prices[i]; 62 | } 63 | } 64 | return sum + max - min; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_128_longestConsecutive.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * Created by wangpeng on 2019-02-26. 7 | * 128. 最长连续序列 8 | *

9 | * 给定一个未排序的整数数组,找出最长连续序列的长度。 10 | *

11 | * 要求算法的时间复杂度为 O(n)。 12 | *

13 | * 示例: 14 | *

15 | * 输入: [100, 4, 200, 1, 3, 2] 16 | * 输出: 4 17 | * 解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。 18 | * 19 | * @see longest-consecutive-sequence 20 | */ 21 | public class _128_longestConsecutive { 22 | public static void main(String[] args) { 23 | int longestConsecutive = new _128_longestConsecutive().longestConsecutive(new int[]{100, 2, 3, 299, 3, 4, 111, 6, 5, 1}); 24 | int longestConsecutive2 = new _128_longestConsecutive().longestConsecutive(new int[]{100, 4, 200, 1, 3, 2}); 25 | System.out.println(longestConsecutive); 26 | System.out.println(longestConsecutive2); 27 | } 28 | 29 | /** 30 | * 利用了并查集的思想 31 | * 32 | * @param nums 33 | * @return 34 | */ 35 | public int longestConsecutive(int[] nums) { 36 | HashMap map = new HashMap<>(); 37 | int max = 0; 38 | for (int i = 0; i < nums.length; i++) { 39 | int num = nums[i]; 40 | if (map.containsKey(num)) continue; 41 | //获取左右数字连续个数 42 | Integer leftCount = map.getOrDefault(num - 1, 0); 43 | Integer rightCount = map.getOrDefault(num + 1, 0); 44 | int count = leftCount + rightCount + 1; 45 | //更新 46 | map.put(num, count); 47 | map.put(num - leftCount, count); 48 | map.put(num + rightCount, count); 49 | max = Math.max(max, count); 50 | } 51 | return max; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_129_sumNumbers.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.TreeNode; 5 | 6 | /** 7 | * Created by wangpeng on 2019-12-21. 8 | * 129. 求根到叶子节点数字之和 9 | * 10 | * 给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。 11 | * 12 | * 例如,从根到叶子节点路径 1->2->3 代表数字 123。 13 | * 14 | * 计算从根到叶子节点生成的所有数字之和。 15 | * 16 | * 说明: 叶子节点是指没有子节点的节点。 17 | * 18 | * 示例 1: 19 | * 20 | * 输入: [1,2,3] 21 | * 1 22 | * / \ 23 | * 2 3 24 | * 输出: 25 25 | * 解释: 26 | * 从根到叶子节点路径 1->2 代表数字 12. 27 | * 从根到叶子节点路径 1->3 代表数字 13. 28 | * 因此,数字总和 = 12 + 13 = 25. 29 | * 示例 2: 30 | * 31 | * 输入: [4,9,0,5,1] 32 | * 4 33 | * / \ 34 | * 9 0 35 | *  / \ 36 | * 5 1 37 | * 输出: 1026 38 | * 解释: 39 | * 从根到叶子节点路径 4->9->5 代表数字 495. 40 | * 从根到叶子节点路径 4->9->1 代表数字 491. 41 | * 从根到叶子节点路径 4->0 代表数字 40. 42 | * 因此,数字总和 = 495 + 491 + 40 = 1026. 43 | * 44 | * 来源:力扣(LeetCode) 45 | * 链接:https://leetcode-cn.com/problems/sum-root-to-leaf-numbers 46 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 47 | */ 48 | public class _129_sumNumbers { 49 | 50 | public static void main(String[] args) { 51 | _129_sumNumbers sumNumbers = new _129_sumNumbers(); 52 | TreeNode treeNode = Util.generateTreeNode(new Integer[]{4, 9, 0, 5, 1}); 53 | System.out.println(sumNumbers.sumNumbers(treeNode)); 54 | } 55 | 56 | private int sum = 0; 57 | 58 | /** 59 | * 解题思路: 60 | * DFS遍历将之前的拼接节点代入,当到达叶节点后累加结果 61 | * 62 | * @param root 63 | * @return 64 | */ 65 | public int sumNumbers(TreeNode root) { 66 | if (root == null) return 0; 67 | dfs("",root); 68 | return sum; 69 | } 70 | 71 | private void dfs(String preVal, TreeNode root) { 72 | if (root.left == null && root.right == null) { 73 | sum += Integer.parseInt(preVal + root.val); 74 | return; 75 | } 76 | if (root.left != null) { 77 | dfs(preVal + root.val, root.left); 78 | } 79 | if (root.right != null) { 80 | dfs(preVal + root.val, root.right); 81 | } 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_132_minCut.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-12-27. 5 | * 132. 分割回文串 II 6 | * 7 | * 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。 8 | * 9 | * 返回符合要求的最少分割次数。 10 | * 11 | * 示例: 12 | * 13 | * 输入: "aab" 14 | * 输出: 1 15 | * 解释: 进行一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。 16 | * 17 | * 来源:力扣(LeetCode) 18 | * 链接:https://leetcode-cn.com/problems/palindrome-partitioning-ii 19 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 20 | */ 21 | public class _132_minCut { 22 | 23 | public static void main(String[] args) { 24 | _132_minCut minCut = new _132_minCut(); 25 | System.out.println(minCut.minCut("aab")); 26 | } 27 | 28 | /** 29 | * 解题思路: 30 | * 要求最少分割次数,所以在一次分割中尽可能的形成较长的回文子串,当然你也可以将所有的可能性都列出来,取其中最少的(耗时) 31 | * 32 | * @param s 33 | * @return 34 | */ 35 | public int minCut(String s) { 36 | boolean[][] dp = new boolean[s.length()][s.length()]; 37 | int[] min = new int[s.length()]; 38 | min[0] = 0; 39 | for (int i = 1; i < s.length(); i++) { 40 | int temp = Integer.MAX_VALUE; 41 | for (int j = 0; j <= i; j++) { 42 | if (s.charAt(j) == s.charAt(i) && (j + 1 > i - 1 || dp[j + 1][i - 1])) { 43 | dp[j][i] = true; 44 | if (j == 0) { 45 | temp = 0; 46 | } else { 47 | temp = Math.min(temp, min[j - 1] + 1); 48 | } 49 | } 50 | } 51 | min[i] = temp; 52 | 53 | } 54 | return min[s.length() - 1]; 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_136_singleNumber.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-07-30. 5 | * 136. 只出现一次的数字 6 | * 7 | * 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 8 | * 9 | * 说明: 10 | * 11 | * 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? 12 | * 13 | * 示例 1: 14 | * 15 | * 输入: [2,2,1] 16 | * 输出: 1 17 | * 示例 2: 18 | * 19 | * 输入: [4,1,2,1,2] 20 | * 输出: 4 21 | * 22 | * 来源:力扣(LeetCode) 23 | * 链接:https://leetcode-cn.com/problems/single-number 24 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 25 | */ 26 | public class _136_singleNumber { 27 | public static void main(String[] args) { 28 | _136_singleNumber singleNumber = new _136_singleNumber(); 29 | System.out.println(singleNumber.singleNumber(new int[]{2, 2, 1})); 30 | System.out.println(singleNumber.singleNumber(new int[]{4, 1, 2, 1, 2})); 31 | } 32 | 33 | /** 34 | * 思考: 35 | * 线性的时间复杂度就是O(n),不适用额外空间也就是最好常量级空间也不要有 36 | * O(n)的复杂度只允许遍历数组一次,一次遍历如何标识数字出现的次数?不能用额外空间就只能用数组本身进行存储 37 | * 是不是可以建立数字在数组中位置的映射关系? 38 | * 39 | * 解题思路: 40 | * 映射关系最常见的就是哈希表,比如数字对数组长度取模,但是可能会发生冲突(两个数组取模结果一致),需解决,处理复杂==>放弃 41 | * 看了提示说位运算,思考了下的确可以,判断只出现一次,其他都出现两次,正好可以使用异或运算,两次结果复原,出现一次的数据停留在bit上 42 | * 1.取bit=0 43 | * 2.循环遍历数组,与bit做异或操作 44 | * 3.将最终的bit返回 45 | * 46 | * 47 | * @param nums 48 | * @return 49 | */ 50 | public int singleNumber(int[] nums) { 51 | int bit = 0; 52 | for (int i = 0; i < nums.length; i++) { 53 | bit = bit ^ nums[i]; 54 | } 55 | return bit; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_141_HasCycle.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.ListNode; 5 | 6 | /** 7 | * Created by wangpeng on 2018/8/16. 8 | * 给定一个链表,判断链表中是否有环。 9 | *

10 | * 进阶: 11 | * 你能否不使用额外空间解决此题? 12 | */ 13 | public class _141_HasCycle { 14 | 15 | public static void main(String[] args) { 16 | ListNode srcNode = Util.generateListNodeBySort(5); 17 | ListNode lastNode = Util.getLastNode(srcNode); 18 | lastNode.next = srcNode.next.next; 19 | boolean b = hasCycle(srcNode); 20 | System.out.println("是否带环:" + b); 21 | } 22 | 23 | public static boolean hasCycle(ListNode head) { 24 | if (head == null) return false; 25 | ListNode head1 = head; 26 | ListNode head2 = head; 27 | while (head2.next != null && head2.next.next != null) { 28 | head1 = head1.next; 29 | head2 = head2.next.next; 30 | if (head1 == head2) { 31 | return true; 32 | } 33 | } 34 | return false; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_147_insertionSortList.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.ListNode; 5 | 6 | /** 7 | * Created by wangpeng on 2018/9/3. 8 | * 147. 对链表进行插入排序 9 | *

10 | * 对链表进行插入排序。 11 | *

12 | *

13 | * 插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。 14 | * 每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。 15 | *

16 | *

17 | *

18 | * 插入排序算法: 19 | *

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

24 | *

25 | * 示例 1: 26 | *

27 | * 输入: 4->2->1->3 28 | * 输出: 1->2->3->4 29 | * 示例 2: 30 | *

31 | * 输入: -1->5->3->4->0 32 | * 输出: -1->0->3->4->5 33 | * 34 | * @see insertion-sort-list 35 | */ 36 | public class _147_insertionSortList { 37 | 38 | public static void main(String[] args) { 39 | ListNode node = Util.generateListNodeBySize(5); 40 | Util.printListNode(node); 41 | Util.printListNode(insertionSortList(node)); 42 | } 43 | 44 | /** 45 | * 如果去替换单链表的前置节点?思路卡住了。 46 | * 对于链表来说,只能通过头节点进行遍历 47 | * 48 | * @param head 49 | * @return 50 | */ 51 | public static ListNode insertionSortList(ListNode head) { 52 | if (head == null) { 53 | return head; 54 | } 55 | 56 | ListNode dummy = new ListNode(0); //new starter of the sorted list 57 | ListNode cur = head; //the node will be inserted 58 | ListNode pre = dummy; //insert node between pre and pre.next 59 | ListNode next = null; //the next node will be inserted 60 | //not the end of input list 61 | while (cur != null) { 62 | next = cur.next; 63 | //find the right place to insert 64 | while (pre.next != null && pre.next.val < cur.val) { 65 | pre = pre.next; 66 | } 67 | //insert between pre and pre.next 68 | cur.next = pre.next; 69 | pre.next = cur; 70 | pre = dummy; 71 | cur = next; 72 | } 73 | 74 | return dummy.next; 75 | } 76 | } -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_148_sortList.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.ListNode; 5 | 6 | /** 7 | * Created by wangpeng on 2018/9/1. 8 | * 148. 排序链表 9 | * 在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。 10 | *

11 | * 示例 1: 12 | *

13 | * 输入: 4->2->1->3 14 | * 输出: 1->2->3->4 15 | * 示例 2: 16 | *

17 | * 输入: -1->5->3->4->0 18 | * 输出: -1->0->3->4->5 19 | * 20 | * @see sort-list 21 | */ 22 | public class _148_sortList { 23 | public static void main(String[] args) { 24 | Util.printListNode(sortList(Util.generateListNodeBySize(2))); 25 | } 26 | 27 | public static ListNode sortList(ListNode head) { 28 | if (head == null || head.next == null) { 29 | return head; 30 | } 31 | ListNode slow = head; 32 | ListNode fast = head; 33 | ListNode pre = slow; 34 | while (slow != null && fast != null && fast.next != null) { 35 | pre = slow; 36 | slow = slow.next; 37 | fast = fast.next.next; 38 | } 39 | pre.next = null; 40 | ListNode left = sortList(head); 41 | ListNode right = sortList(slow); 42 | return merge(left, right); 43 | } 44 | 45 | private static ListNode merge(ListNode left, ListNode right) { 46 | ListNode dummy = new ListNode(0); 47 | ListNode next = dummy; 48 | while (left != null && right != null) { 49 | if (left.val < right.val) { 50 | next.next = left; 51 | left = left.next; 52 | } else { 53 | next.next = right; 54 | right = right.next; 55 | } 56 | next = next.next; 57 | } 58 | if (left != null) { 59 | next.next = left; 60 | } 61 | if (right != null) { 62 | next.next = right; 63 | } 64 | return dummy.next; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_151_reverseWords.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-02-01. 5 | * 151. 翻转字符串里的单词 6 | *

7 | * 给定一个字符串,逐个翻转字符串中的每个单词。 8 | *

9 | * 示例: 10 | *

11 | * 输入: "the sky is blue", 12 | * 输出: "blue is sky the". 13 | * 说明: 14 | *

15 | * 无空格字符构成一个单词。 16 | * 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 17 | * 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 18 | * 进阶: 请选用C语言的用户尝试使用 O(1) 空间复杂度的原地解法。 19 | * 20 | * @see reverse-words-in-a-string 21 | */ 22 | public class _151_reverseWords { 23 | 24 | public static void main(String[] args) { 25 | System.out.println(reverseWords("the sky is blue")); 26 | System.out.println(reverseWords(" ")); 27 | } 28 | 29 | /** 30 | * 执行用时: 15 ms, 在Reverse Words in a String的Java提交中击败了47.75% 的用户 31 | * 内存消耗: 29.6 MB, 在Reverse Words in a String的Java提交中击败了26.64% 的用户 32 | * 33 | * @param s 34 | * @return 35 | */ 36 | public static String reverseWords(String s) { 37 | StringBuilder builder = new StringBuilder(); 38 | int si = 0; 39 | int ei = 0; 40 | while (si < s.length() && ei < s.length()) { 41 | while (si < s.length() && s.charAt(si) == ' ') { 42 | si++; 43 | } 44 | if (si == s.length()) { 45 | break; 46 | } 47 | ei = si; 48 | while (ei < s.length() && s.charAt(ei) != ' ') { 49 | ei++; 50 | } 51 | if (ei == s.length()) { 52 | break; 53 | } 54 | builder.insert(0, s.substring(si, ei)); 55 | builder.insert(0, " "); 56 | si = ei; 57 | } 58 | if (si != ei) { 59 | if ((ei < s.length() && s.charAt(ei) == ' ')) { 60 | if (builder.length() > 0) { 61 | builder.deleteCharAt(0); 62 | } 63 | } else { 64 | builder.insert(0, s.substring(si, ei)); 65 | } 66 | } 67 | 68 | return builder.toString(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_151_reverseWords_2.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-02-01. 5 | * 151. 翻转字符串里的单词 6 | *

7 | * 给定一个字符串,逐个翻转字符串中的每个单词。 8 | *

9 | * 示例: 10 | *

11 | * 输入: "the sky is blue", 12 | * 输出: "blue is sky the". 13 | * 说明: 14 | *

15 | * 无空格字符构成一个单词。 16 | * 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 17 | * 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 18 | * 进阶: 请选用C语言的用户尝试使用 O(1) 空间复杂度的原地解法。 19 | * 20 | * @see reverse-words-in-a-string 21 | */ 22 | public class _151_reverseWords_2 { 23 | 24 | public static void main(String[] args) { 25 | System.out.println(reverseWords("the sky is blue")); 26 | System.out.println(reverseWords(" ")); 27 | } 28 | 29 | public static String reverseWords(String s) { 30 | if (s.length() == 0) return s; 31 | char[] ch = s.toCharArray(); 32 | char[] res = new char[ch.length]; 33 | int len = helper(ch, ch.length - 1, res, 0, 0); 34 | return new String(res, 0, len); 35 | } 36 | 37 | private static int helper(char[] ch, int r, char[] res, int l, int len) { 38 | while (r >= 0 && ch[r] == ' ') { 39 | r--; 40 | } 41 | if (r < 0) return Math.max(0, len - 1); 42 | int right = r; 43 | while (r >= 0 && ch[r] != ' ') { 44 | r--; 45 | } 46 | len += right - r + 1; 47 | for (int left = r + 1; left <= right; left++, l++) { 48 | res[l] = ch[left]; 49 | } 50 | if (l < res.length) { 51 | res[l++] = ' '; 52 | } 53 | return helper(ch, r, res, l, len); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_167_twoSum.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | /** 6 | * Created by wangpeng on 2019-03-20. 7 | * 167. 两数之和 II - 输入有序数组 8 | *

9 | * 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。 10 | *

11 | * 函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。 12 | *

13 | * 说明: 14 | *

15 | * 返回的下标值(index1 和 index2)不是从零开始的。 16 | * 你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。 17 | * 示例: 18 | *

19 | * 输入: numbers = [2, 7, 11, 15], target = 9 20 | * 输出: [1,2] 21 | * 解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。 22 | * 23 | * @see two-sum-ii-input-array-is-sorted 24 | */ 25 | public class _167_twoSum { 26 | 27 | public static void main(String[] args) { 28 | _167_twoSum twoSum = new _167_twoSum(); 29 | Util.printArray(twoSum.twoSum(new int[]{2, 7, 11, 15}, 9)); 30 | } 31 | 32 | public int[] twoSum(int[] numbers, int target) { 33 | int[] result = new int[2]; 34 | int startI = 0, endI = numbers.length - 1; 35 | while (startI < endI) { 36 | int add = numbers[startI] + numbers[endI]; 37 | if (add == target) { 38 | result[0] = startI + 1; 39 | result[1] = endI + 1; 40 | break; 41 | } else if (add > target) { 42 | endI--; 43 | } else { 44 | startI++; 45 | } 46 | } 47 | return result; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_16_threeSumClosest.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by wangpeng on 2019-04-09. 7 | * 16. 最接近的三数之和 8 | *

9 | * 给定一个包括 n 个整数的数组 nums 和 一个目标值 target。 10 | * 找出 nums 中的三个整数,使得它们的和与 target 最接近。 11 | * 返回这三个数的和。假定每组输入只存在唯一答案。 12 | *

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

15 | * 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2). 16 | * 17 | * @see 3sum-closest 18 | */ 19 | public class _16_threeSumClosest { 20 | 21 | public static void main(String[] args) { 22 | _16_threeSumClosest threeSumClosest = new _16_threeSumClosest(); 23 | System.out.println(threeSumClosest.threeSumClosest(new int[]{-1, 2, 1, -4}, 1)); 24 | } 25 | 26 | /** 27 | * 解题思路: 28 | * 1、先排序,快排(O(nLogn)) 29 | * 2、随机取一个数i(第一个开始),头尾各取一个数开始遍历si=i+1,ei=n-1 30 | * 3、三数相加S1,S1-T1=D 31 | * 4、D==0则直接返回,D>0则ei--,D<0则si++ 32 | *

33 | * 最坏时间复杂度在O(n^2) 34 | *

35 | * 执行用时 : 12 ms, 在3Sum Closest的Java提交中击败了98.06% 的用户 36 | * 内存消耗 : 36.1 MB, 在3Sum Closest的Java提交中击败了0.86% 的用户 37 | * 38 | * @param nums 39 | * @param target 40 | * @return 41 | */ 42 | public int threeSumClosest(int[] nums, int target) { 43 | Arrays.sort(nums); 44 | int ret = 0; 45 | int minDiff = Integer.MAX_VALUE; 46 | int len = nums.length; 47 | for (int i = 0; i < len - 2; i++) { 48 | int si = i + 1, ei = len - 1; 49 | while (si < ei) { 50 | int sum = nums[i] + nums[si] + nums[ei]; 51 | if (sum == target) return sum; 52 | int diff = Math.abs(sum - target); 53 | if (diff < minDiff) { 54 | minDiff = diff; 55 | ret = sum; 56 | } 57 | if (sum > target) 58 | ei--; 59 | else 60 | si++; 61 | } 62 | } 63 | 64 | return ret; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_174_calculateMinimumHP.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/9/25. 5 | * 174. 地下城游戏 6 | *

7 | * 一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。 8 | *

9 | * 骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。 10 | *

11 | * 有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。 12 | *

13 | * 为了尽快到达公主,骑士决定每次只向右或向下移动一步。 14 | *

15 | *

16 | *

17 | * 编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。 18 | *

19 | * 例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。 20 | *

21 | * -2 (K) -3 3 22 | * -5 -10 1 23 | * 10 30 -5 (P) 24 | *

25 | *

26 | * 说明: 27 | *

28 | * 骑士的健康点数没有上限。 29 | *

30 | * 任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。 31 | * 32 | * @see dungeon-game 33 | */ 34 | public class _174_calculateMinimumHP { 35 | public static void main(String[] args) { 36 | 37 | int i = calculateMinimumHP(new int[][]{ 38 | {-2, -3, 3}, 39 | {-5, -10, 1}, 40 | {10, 30, -5} 41 | }); 42 | System.out.println(i); 43 | } 44 | 45 | public static int calculateMinimumHP(int[][] dungeon) { 46 | if (dungeon == null || dungeon.length == 0) { 47 | return 0; 48 | } 49 | int column = dungeon[0].length; 50 | int row = dungeon.length; 51 | int[][] dp = new int[row][column]; 52 | dp[row - 1][column - 1] = Math.max(1, 1 - dungeon[row - 1][column - 1]); 53 | for (int i = column - 2; i >= 0; i--) { 54 | dp[row - 1][i] = Math.max(1, dp[row - 1][i + 1] - dungeon[row - 1][i]); 55 | } 56 | for (int i = row - 2; i >= 0; i--) { 57 | dp[i][column - 1] = Math.max(1, dp[i + 1][column - 1] - dungeon[i][column - 1]); 58 | for (int j = column - 2; j >= 0; j--) { 59 | int min = Math.min(dp[i + 1][j], dp[i][j + 1]); 60 | dp[i][j] = Math.max(1, min - dungeon[i][j]); 61 | } 62 | } 63 | return dp[0][0]; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_190_reverseBits.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/11/1. 5 | * 190. 颠倒二进制位 6 | *

7 | * 颠倒给定的 32 位无符号整数的二进制位。 8 | *

9 | * 示例: 10 | *

11 | * 输入: 43261596 12 | * 输出: 964176192 13 | * 解释: 43261596 的二进制表示形式为 00000010100101000001111010011100 , 14 | * 返回 964176192,其二进制表示形式为 00111001011110000010100101000000 。 15 | * 进阶: 16 | * 如果多次调用这个函数,你将如何优化你的算法? 17 | * 18 | * @see reverse-bits 19 | */ 20 | public class _190_reverseBits { 21 | public static void main(String[] args) { 22 | int i = reverseBits(1); 23 | System.out.println(i); 24 | } 25 | 26 | // you need treat n as an unsigned value 27 | public static int reverseBits(int n) { 28 | int result = 0; 29 | for (int i = 0; i < 32; i++) { 30 | result += n & 1; 31 | n >>= 1; 32 | if (i < 31) { 33 | result <<= 1; 34 | } 35 | } 36 | return result; 37 | } 38 | /** 39 | * 反转操作总结 40 | * - 求回文 41 | * - 字符串回文:从头和尾以此遍历,最简单 42 | * - 数字回文:n/10,构建一半,是否相等 _9_isPalindrome 43 | * - 链表回文:链表反转一半 _234_isPalindrome 44 | * - 反转 45 | * - 数字反转:n/10,注意Int越界 _7_reverse 46 | * - 二进制反转:>>1 _190_reverseBits 47 | */ 48 | } 49 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_198_rob.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/9/21. 5 | * 198.打家劫舍 6 | * 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 7 | *

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

10 | * 示例 1: 11 | *

12 | * 输入: [1,2,3,1] 13 | * 输出: 4 14 | * 解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 15 | * 偷窃到的最高金额 = 1 + 3 = 4 。 16 | * 示例 2: 17 | *

18 | * 输入: [2,7,9,3,1] 19 | * 输出: 12 20 | * 解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。 21 | * 偷窃到的最高金额 = 2 + 9 + 1 = 12 。 22 | * 23 | * @see house-robber 24 | */ 25 | public class _198_rob { 26 | 27 | public static void main(String[] args) { 28 | int rob = rob(new int[]{2, 7, 9, 3, 1}); 29 | System.out.println(rob); 30 | } 31 | 32 | public static int rob(int[] nums) { 33 | if (nums == null || nums.length == 0) { 34 | return 0; 35 | } 36 | if (nums.length < 2) { 37 | return nums[0]; 38 | } 39 | int[] dp = new int[nums.length]; 40 | dp[0] = nums[0]; 41 | dp[1] = Math.max(nums[0], nums[1]); 42 | for (int i = 2; i < nums.length; i++) { 43 | dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]); 44 | } 45 | return dp[nums.length - 1]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_203_removeElements.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.ListNode; 5 | 6 | /** 7 | * Created by wangpeng on 2018/10/27. 8 | * 203. 移除链表元素 9 | *

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

12 | * 示例: 13 | *

14 | * 输入: 1->2->6->3->4->5->6, val = 6 15 | * 输出: 1->2->3->4->5 16 | * 17 | * @see remove-linked-list-elements 18 | */ 19 | public class _203_removeElements { 20 | 21 | public static void main(String[] args) { 22 | ListNode listNode1 = new ListNode(1); 23 | ListNode listNode2 = new ListNode(2); 24 | ListNode listNode3 = new ListNode(3); 25 | ListNode listNode4 = new ListNode(4); 26 | ListNode listNode5 = new ListNode(1); 27 | listNode1.next = listNode2; 28 | listNode2.next = listNode3; 29 | listNode3.next = listNode4; 30 | listNode4.next = listNode5; 31 | Util.printListNode(listNode1); 32 | ListNode node1 = removeElements(listNode1, 1); 33 | Util.printListNode(node1); 34 | } 35 | 36 | public static ListNode removeElements(ListNode head, int val) { 37 | ListNode dummyNode = new ListNode(0); 38 | ListNode node = dummyNode; 39 | dummyNode.next = head; 40 | while (node.next != null) { 41 | if (node.next.val == val) { 42 | node.next = node.next.next; 43 | } else { 44 | node = node.next; 45 | } 46 | } 47 | return dummyNode.next; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_206_ReverseList.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.model.ListNode; 4 | import pp.arithmetic.Util; 5 | 6 | /** 7 | * Created by wangpeng on 2018/7/9. 8 | */ 9 | public class _206_ReverseList { 10 | 11 | public static void main(String[] args) { 12 | ListNode listNode1 = new ListNode(1); 13 | ListNode listNode2 = new ListNode(2); 14 | ListNode listNode3 = new ListNode(3); 15 | ListNode listNode4 = new ListNode(4); 16 | ListNode listNode5 = new ListNode(5); 17 | listNode1.next = listNode2; 18 | listNode2.next = listNode3; 19 | listNode3.next = listNode4; 20 | listNode4.next = listNode5; 21 | // ListNode retList = reverseList(listNode1); 22 | // Util.printListNode(retList); 23 | ListNode retList2 = reverseList2(listNode1); 24 | Util.printListNode(retList2); 25 | } 26 | 27 | /** 28 | * 就地逆置法 29 | * @param listNode 30 | * @return 31 | */ 32 | public static ListNode reverseList(ListNode listNode) { 33 | if (listNode == null || listNode.next == null) { 34 | return listNode; 35 | } 36 | ListNode head = listNode; 37 | ListNode newListNode = null; 38 | while (head != null) { 39 | ListNode next = head.next; 40 | head.next = newListNode; 41 | newListNode = head; 42 | head = next; 43 | } 44 | return newListNode; 45 | } 46 | 47 | /** 48 | * 头插法 49 | * @param listNode 50 | * @return 51 | */ 52 | public static ListNode reverseList2(ListNode listNode) { 53 | if (listNode == null || listNode.next == null) { 54 | return listNode; 55 | } 56 | ListNode head = listNode; 57 | ListNode tempNode = new ListNode(0); 58 | while (head != null) { 59 | ListNode next = head.next; 60 | head.next = tempNode.next; 61 | tempNode.next = head; 62 | head = next; 63 | } 64 | return tempNode.next; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_206_ReverseList_2.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.ListNode; 5 | 6 | /** 7 | * Created by wangpeng on 2018/7/9. 8 | * 递归实现 9 | */ 10 | public class _206_ReverseList_2 { 11 | 12 | public static void main(String[] args) { 13 | ListNode listNode1 = Util.generateListNodeBySize(10); 14 | Util.printListNode(listNode1); 15 | ListNode retList = reverseList(listNode1); 16 | Util.printListNode(retList); 17 | } 18 | 19 | /** 20 | * 递归实现 21 | * 22 | * @param listNode 23 | * @return 24 | */ 25 | private static ListNode reverseList(ListNode listNode) { 26 | if (listNode.next == null) { 27 | return listNode; 28 | } 29 | ListNode dummy = new ListNode(0); 30 | generate(dummy, listNode); 31 | return dummy.next; 32 | } 33 | 34 | private static void generate(ListNode dummp, ListNode node) { 35 | if (node == null) { 36 | return; 37 | } 38 | ListNode temp = dummp.next; 39 | ListNode next = node.next; 40 | dummp.next = node; 41 | node.next = temp; 42 | generate(dummp, next); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_213_rob.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-05-09. 5 | * 213. 打家劫舍 II 6 | * 7 | * 你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 8 | * 9 | * 给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。 10 | * 11 | * 示例 1: 12 | * 13 | * 输入: [2,3,2] 14 | * 输出: 3 15 | * 解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。 16 | * 示例 2: 17 | * 18 | * 输入: [1,2,3,1] 19 | * 输出: 4 20 | * 解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。 21 | * 偷窃到的最高金额 = 1 + 3 = 4 。 22 | * 23 | * @see house-robber-ii 24 | */ 25 | public class _213_rob { 26 | public static void main(String[] args) { 27 | _213_rob rob = new _213_rob(); 28 | System.out.println(rob.rob(new int[]{2, 3, 2})); 29 | System.out.println(rob.rob(new int[]{1, 2, 3, 1})); 30 | } 31 | 32 | /** 33 | * 解题思路: 34 | * 难点->最后一个既然是和第一个相连的,不然一个动态规划等式就能解决了 35 | * dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]); 36 | * 突破这个难点,使用两个规划数组,一个从0开始,n-1结束,另一个从1开始,n结束 37 | * 求出两个数组的最大值 38 | * 39 | * @param nums 40 | * @return 41 | */ 42 | public int rob(int[] nums) { 43 | int length = nums.length; 44 | if (length == 0) return 0; 45 | if (length == 1) return nums[0]; 46 | if (length == 2) return Math.max(nums[0], nums[1]); 47 | //0->n-1 48 | int[] dp = new int[length - 1]; 49 | dp[0] = nums[0]; 50 | dp[1] = Math.max(nums[0], nums[1]); 51 | for (int i = 2; i < length - 1; i++) { 52 | dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]); 53 | } 54 | //1->n 55 | int[] dp1 = new int[length - 1]; 56 | dp1[0] = nums[1]; 57 | dp1[1] = Math.max(nums[1], nums[2]); 58 | for (int i = 3; i < length; i++) { 59 | dp1[i - 1] = Math.max(dp1[i - 3] + nums[i], dp1[i - 2]); 60 | } 61 | 62 | return Math.max(dp[length - 2], dp1[length - 2]); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_214_shortestPalindrome_2.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/11/5. 5 | * 214. 最短回文串 6 | *

7 | * 给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。 8 | *

9 | * 示例 1: 10 | *

11 | * 输入: "aacecaaa" 12 | * 输出: "aaacecaaa" 13 | * 示例 2: 14 | *

15 | * 输入: "abcd" 16 | * 输出: "dcbabcd" 17 | * 18 | * @see shortest-palindrome 19 | */ 20 | public class _214_shortestPalindrome_2 { 21 | public static void main(String[] args) { 22 | String s1 = shortestPalindrome("aacecaaa"); 23 | System.out.println(s1); 24 | String s2 = shortestPalindrome("abcd"); 25 | System.out.println(s2); 26 | String s3 = shortestPalindrome("abbacd"); 27 | System.out.println(s3); 28 | String s4 = shortestPalindrome("aaaabbaa"); 29 | System.out.println(s4); 30 | String s5 = shortestPalindrome("abcdefba"); 31 | System.out.println(s5); 32 | } 33 | 34 | /** 35 | * 实现,时间复杂度O() 36 | * 37 | * @param s 38 | * @return 39 | */ 40 | public static String shortestPalindrome(String s) { 41 | int j = 0; 42 | 43 | // 找出s对于s.reverse的子串 44 | for (int i = s.length() - 1; i >= 0; i--) { 45 | if (s.charAt(i) == s.charAt(j)) { 46 | j++; 47 | } 48 | } 49 | 50 | // 递归边界: s本身就是回文子串 51 | if (j == s.length()) { 52 | return s; 53 | } 54 | 55 | 56 | String suffix = s.substring(j); 57 | 58 | return new StringBuffer(suffix).reverse(). 59 | append(shortestPalindrome(s.substring(0, j))). 60 | append(suffix). 61 | toString(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_215_findKthLargest.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import java.util.PriorityQueue; 4 | 5 | /** 6 | * Created by wangpeng on 2018/8/28. 7 | * 215. 数组中的第K个最大元素 8 | * 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 9 | *

10 | * 示例 1: 11 | *

12 | * 输入: [3,2,1,5,6,4] 和 k = 2 13 | * 输出: 5 14 | *

15 | * 示例 2: 16 | *

17 | * 输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 18 | * 输出: 4 19 | * 说明: 20 | *

21 | * 你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。 22 | * 23 | * @see kth-largest-element-in-an-array 24 | */ 25 | public class _215_findKthLargest { 26 | 27 | public static void main(String[] args) { 28 | int[] nums = new int[]{3, 2, 3, 1, 2, 4, 5, 5, 6}; 29 | int kthLargest = findKthLargest(nums, 4); 30 | System.out.println("kthLargest:" + kthLargest); 31 | } 32 | 33 | /** 34 | * 使用堆进行实现,时间复杂度n*logn,logn是堆排序需要是时间 35 | * 36 | * @param nums 37 | * @param k 38 | * @return 39 | */ 40 | public static int findKthLargest(int[] nums, int k) { 41 | PriorityQueue priorityQueue = new PriorityQueue<>(); 42 | for (int i = 0; i < nums.length; i++) { 43 | int num = nums[i]; 44 | priorityQueue.add(num); 45 | if (priorityQueue.size() > k) { 46 | priorityQueue.poll(); 47 | } 48 | } 49 | return priorityQueue.peek(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_21_MergeTwoLists.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.ListNode; 5 | 6 | /** 7 | * Created by wangpeng on 2018/8/15. 8 | */ 9 | public class _21_MergeTwoLists { 10 | public static void main(String[] args) { 11 | ListNode node1 = Util.generateListNodeBySort(5); 12 | Util.printListNode(node1); 13 | ListNode node2 = Util.generateListNodeBySort(5); 14 | Util.printListNode(node2); 15 | // ListNode newNode = mergeTwoListsSelf(node1, node2); 16 | ListNode newNode = mergeTwoListsOther(node1, node2); 17 | Util.printListNode(newNode); 18 | } 19 | 20 | public static ListNode mergeTwoListsSelf(ListNode l1, ListNode l2) { 21 | ListNode dummyNode = new ListNode(0); 22 | ListNode preNode = dummyNode; 23 | //1、比较大小 24 | while (l1 != null && l2 != null) { 25 | if (l1.val < l2.val) { 26 | preNode.next = l1; 27 | l1 = l1.next; 28 | } else { 29 | preNode.next = l2; 30 | l2 = l2.next; 31 | } 32 | preNode = preNode.next; 33 | } 34 | //2、将剩余拼接到后面 35 | if (l1 != null) { 36 | preNode.next = l1; 37 | } 38 | if (l2 != null) { 39 | preNode.next = l2; 40 | } 41 | return dummyNode.next; 42 | } 43 | 44 | public static ListNode mergeTwoListsOther(ListNode l1, ListNode l2) { 45 | if (l1 == null) return l2; 46 | if (l2 == null) return l1; 47 | 48 | if (l1.val < l2.val) { 49 | l1.next = mergeTwoListsOther(l1.next, l2); 50 | return l1; 51 | } else { 52 | l2.next = mergeTwoListsOther(l2.next, l1); 53 | return l2; 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_225_MyStack.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import java.util.ArrayDeque; 4 | 5 | /** 6 | * Created by wangpeng on 2018/8/24. 7 | * 225. 用队列实现栈 8 | * 使用队列实现栈的下列操作: 9 | * push(x) -- 元素 x 入栈 10 | * pop() -- 移除栈顶元素 11 | * top() -- 获取栈顶元素 12 | * empty() -- 返回栈是否为空 13 | * 注意: 14 | *

15 | * 你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。 16 | * 你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。 17 | * 你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。 18 | */ 19 | public class _225_MyStack { 20 | 21 | public static void main(String[] args) { 22 | MyStack obj = new MyStack(); 23 | obj.push(1); 24 | obj.push(2); 25 | int param_2 = obj.pop(); 26 | System.out.println("param_2:" + param_2); 27 | int param_3 = obj.top(); 28 | System.out.println("param_3:" + param_3); 29 | boolean param_4 = obj.empty(); 30 | System.out.println("param_4:" + param_4); 31 | } 32 | 33 | public static class MyStack { 34 | ArrayDeque arrayDeque; 35 | 36 | /** 37 | * Initialize your data structure here. 38 | */ 39 | public MyStack() { 40 | arrayDeque = new ArrayDeque(); 41 | } 42 | 43 | /** 44 | * Push element x onto stack. 45 | */ 46 | public void push(int x) { 47 | ArrayDeque tempQuene = new ArrayDeque<>(); 48 | tempQuene.push(x); 49 | while (!arrayDeque.isEmpty()) { 50 | tempQuene.push(arrayDeque.pop()); 51 | } 52 | while (!tempQuene.isEmpty()) { 53 | arrayDeque.push(tempQuene.pop()); 54 | } 55 | } 56 | 57 | /** 58 | * Removes the element on top of the stack and returns that element. 59 | */ 60 | public int pop() { 61 | return arrayDeque.pop(); 62 | } 63 | 64 | /** 65 | * Get the top element. 66 | */ 67 | public int top() { 68 | return arrayDeque.peek(); 69 | } 70 | 71 | /** 72 | * Returns whether the stack is empty. 73 | */ 74 | public boolean empty() { 75 | return arrayDeque.isEmpty(); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_226_invertTree.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.TreeNode; 5 | 6 | /** 7 | * Created by wangpeng on 2019-08-02. 8 | * 226. 翻转二叉树 9 | * 10 | * 翻转一棵二叉树。 11 | * 12 | * 示例: 13 | * 14 | * 输入: 15 | * 16 | * 4 17 | * / \ 18 | * 2 7 19 | * / \ / \ 20 | * 1 3 6 9 21 | * 输出: 22 | * 23 | * 4 24 | * / \ 25 | * 7 2 26 | * / \ / \ 27 | * 9 6 3 1 28 | * 备注: 29 | * 这个问题是受到 Max Howell 的 原问题 启发的 : 30 | * 31 | * 谷歌:我们90%的工程师使用您编写的软件(Homebrew),但是您却无法在面试时在白板上写出翻转二叉树这道题,这太糟糕了。 32 | * 33 | * 来源:力扣(LeetCode) 34 | * 链接:https://leetcode-cn.com/problems/invert-binary-tree 35 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 36 | */ 37 | public class _226_invertTree { 38 | 39 | public static void main(String[] args) { 40 | _226_invertTree invertTree = new _226_invertTree(); 41 | TreeNode treeNode = Util.generateTreeNode(); 42 | Util.printTree(treeNode); 43 | TreeNode treeNode1 = invertTree.invertTree(treeNode); 44 | Util.printTree(treeNode1); 45 | } 46 | 47 | /** 48 | * 解题思路: 49 | * 树的经典解题:左、右、自己,递归遍历,拿到翻转后的左右子树,将root的左右子树坐下替换 50 | * 1.翻转左子树 51 | * 2.翻转右子树 52 | * 3.替换root的左右子树(翻转后) 53 | * 54 | * 55 | * @param root 56 | * @return 57 | */ 58 | public TreeNode invertTree(TreeNode root) { 59 | if (root ==null) return null; 60 | //1 61 | TreeNode left = invertTree(root.left); 62 | //2 63 | TreeNode right = invertTree(root.right); 64 | //3 65 | root.left = right; 66 | root.right = left; 67 | return root; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_234_isPalindrome.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.ListNode; 5 | 6 | /** 7 | * Created by wangpeng on 2018/8/23. 8 | * 234. 回文链表 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 | * 21 | * @see palindrome-linked-list 22 | */ 23 | public class _234_isPalindrome { 24 | 25 | public static void main(String[] args) { 26 | ListNode node = Util.generateListNodeBySize(3); 27 | Util.printListNode(node); 28 | boolean palindrome = isPalindrome(node); 29 | System.out.println("是否是回文链表:" + palindrome); 30 | } 31 | 32 | public static boolean isPalindrome(ListNode head) { 33 | ListNode fast = head; 34 | ListNode slow = head; 35 | while (fast != null && fast.next != null) { 36 | fast = fast.next.next; 37 | slow = slow.next; 38 | } 39 | ListNode node = _206_ReverseList.reverseList(slow); 40 | fast = head; 41 | slow = node; 42 | while (fast != null && slow != null) { 43 | if (fast.val != slow.val) { 44 | return false; 45 | } 46 | fast = fast.next; 47 | slow = slow.next; 48 | } 49 | return true; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_237_deleteNode.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.ListNode; 5 | 6 | /** 7 | * Created by wangpeng on 2018/10/27. 8 | * 237. 删除链表中的节点 9 | *

10 | * 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。 11 | *

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

14 | * 4 -> 5 -> 1 -> 9 15 | * 示例 1: 16 | *

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

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

27 | * 链表至少包含两个节点。 28 | * 链表中所有节点的值都是唯一的。 29 | * 给定的节点为非末尾节点并且一定是链表中的一个有效节点。 30 | * 不要从你的函数中返回任何结果。 31 | * 32 | * @see delete-node-in-a-linked-list 33 | */ 34 | public class _237_deleteNode { 35 | 36 | public static void main(String[] args) { 37 | ListNode listNode1 = new ListNode(1); 38 | ListNode listNode2 = new ListNode(2); 39 | ListNode listNode3 = new ListNode(3); 40 | ListNode listNode4 = new ListNode(4); 41 | listNode1.next = listNode2; 42 | listNode2.next = listNode3; 43 | listNode3.next = listNode4; 44 | Util.printListNode(listNode1); 45 | deleteNode(listNode2); 46 | Util.printListNode(listNode1); 47 | } 48 | 49 | public static void deleteNode(ListNode node) { 50 | ListNode next = node.next; 51 | node.next = next.next; 52 | node.val = next.val; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_24_SwapPairs.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.ListNode; 5 | 6 | /** 7 | * Created by wangpeng on 2018/8/21. 8 | *

9 | * 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 10 | *

11 | * 示例: 12 | *

13 | * 给定 1->2->3->4, 你应该返回 2->1->4->3. 14 | * 说明: 15 | * 你的算法只能使用常数的额外空间。 16 | * 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 17 | * 18 | * @see swap-nodes-in-pairs 19 | */ 20 | public class _24_SwapPairs { 21 | public static void main(String[] args) { 22 | ListNode node = Util.generateListNodeBySize(10); 23 | Util.printListNode(node); 24 | ListNode swapPairs = swapPairs(node); 25 | Util.printListNode(swapPairs); 26 | } 27 | 28 | public static ListNode swapPairs(ListNode head) { 29 | ListNode dummy = new ListNode(0); 30 | ListNode pre = dummy; 31 | while (head != null && head.next != null) { 32 | //获取第一第二个的节点 33 | ListNode first = head; 34 | ListNode second = head.next; 35 | //交换位置 36 | first.next = second.next; 37 | second.next = first; 38 | //循环 39 | head = first.next; 40 | pre.next = second; 41 | pre = first; 42 | } 43 | 44 | return dummy.next == null ? head : dummy.next; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_26_removeDuplicates.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-03-22. 5 | * 26. 删除排序数组中的重复项 6 | *

7 | * 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 8 | *

9 | * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 10 | *

11 | * 示例 1: 12 | *

13 | * 给定数组 nums = [1,1,2], 14 | *

15 | * 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 16 | *

17 | * 你不需要考虑数组中超出新长度后面的元素。 18 | * 示例 2: 19 | *

20 | * 给定 nums = [0,0,1,1,1,2,2,3,3,4], 21 | *

22 | * 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 23 | *

24 | * 你不需要考虑数组中超出新长度后面的元素。 25 | * 说明: 26 | *

27 | * 为什么返回数值是整数,但输出的答案是数组呢? 28 | *

29 | * 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 30 | *

31 | * 你可以想象内部操作如下: 32 | *

33 | * // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 34 | * int len = removeDuplicates(nums); 35 | *

36 | * // 在函数里修改输入数组对于调用者是可见的。 37 | * // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 38 | * for (int i = 0; i < len; i++) { 39 | * print(nums[i]); 40 | * } 41 | * 42 | * @see remove-duplicates-from-sorted-array 43 | */ 44 | public class _26_removeDuplicates { 45 | 46 | public static void main(String[] args) { 47 | _26_removeDuplicates removeDuplicates = new _26_removeDuplicates(); 48 | System.out.println(removeDuplicates.removeDuplicates(new int[]{0, 0, 1, 1, 1, 2, 2, 3, 3, 4})); 49 | } 50 | 51 | public int removeDuplicates(int[] nums) { 52 | int preNumIndex = 0, lastIndex = 0; 53 | for (int index = 1; index < nums.length; index++) { 54 | if (nums[index] > nums[preNumIndex]) { 55 | lastIndex++; 56 | nums[lastIndex] = nums[index]; 57 | preNumIndex = index; 58 | } 59 | } 60 | 61 | return lastIndex + 1; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_279_numSquares.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-05-09. 5 | * 279. 完全平方数 6 | *

7 | * 给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。 8 | *

9 | * 示例 1: 10 | *

11 | * 输入: n = 12 12 | * 输出: 3 13 | * 解释: 12 = 4 + 4 + 4. 14 | * 示例 2: 15 | *

16 | * 输入: n = 13 17 | * 输出: 2 18 | * 解释: 13 = 4 + 9. 19 | * 20 | * @see perfect-squares 21 | */ 22 | public class _279_numSquares { 23 | 24 | public static void main(String[] args) { 25 | _279_numSquares numSquares = new _279_numSquares(); 26 | System.out.println(numSquares.numSquares(12)); 27 | System.out.println(numSquares.numSquares(13)); 28 | } 29 | 30 | /** 31 | * 直接思路:找出N最接近的平方数,再循环找出剩余最接近的平方数集合(结果可能不是最优) 32 | * 比如:12->9+1+1+1,最优的是12->4+4+4 33 | * 所以,上面的思路还得把所有的情况都求出来,再选出最少的,性能较差 34 | *

35 | * 优化思路:利用之前计算的步数,转换为动态规划方程 36 | * dp[i]代表第i需要的最少步骤,遍历所有的情况,从而找出最优解 37 | * for (int j = 1; i - j * j >= 0; j++) { 38 | * dp[i] = Math.min(dp[i], dp[i - j * j] + 1); 39 | * } 40 | * 41 | * 42 | * @param n 43 | * @return 44 | */ 45 | public int numSquares(int n) { 46 | //利用动态规划 定义长度为n+1的数组 对应索引所对应的数装最少的步数 47 | int[] dp = new int[n + 1]; 48 | dp[0] = 0; 49 | for (int i = 1; i <= n; i++) { 50 | dp[i] = i; //先假设到这一步的最大的步数为每次+1 51 | for (int j = 1; i - j * j >= 0; j++) { //i-j*j>=0 找到最大的j j*j就是i里面最大的完全平方数 52 | //dp[i-j*j]+1 表示d[i-j*j]的步数+1 1即j*j这个完全平方数只需要一步 53 | dp[i] = Math.min(dp[i], dp[i - j * j] + 1); 54 | } 55 | } 56 | return dp[n]; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_283_moveZeroes.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | /** 6 | * Created by wangpeng on 2019-08-07. 7 | * 283. 移动零 8 | *

9 | * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 10 | *

11 | * 示例: 12 | *

13 | * 输入: [0,1,0,3,12] 14 | * 输出: [1,3,12,0,0] 15 | * 说明: 16 | *

17 | * 必须在原数组上操作,不能拷贝额外的数组。 18 | * 尽量减少操作次数。 19 | *

20 | * 来源:力扣(LeetCode) 21 | * 链接:https://leetcode-cn.com/problems/move-zeroes 22 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 23 | */ 24 | public class _283_moveZeroes { 25 | public static void main(String[] args) { 26 | _283_moveZeroes moveZeroes = new _283_moveZeroes(); 27 | int[] nums = {0, 1, 0, 3, 12}; 28 | moveZeroes.moveZeroes(nums); 29 | Util.printArray(nums); 30 | } 31 | 32 | /** 33 | * 解题思路: 34 | * 1.遍历数组,找到第一个0并标记zeroIndex 35 | * 2.找到下一个非0,将其与0交互,zeroIndex++ 36 | * 3.找到下一个0,不做任何处理 37 | * 38 | * @param nums 39 | */ 40 | public void moveZeroes(int[] nums) { 41 | int zeroIndex = -1; 42 | //1 43 | for (int i = 0; i < nums.length; i++) { 44 | int num = nums[i]; 45 | if (num == 0) { 46 | //1 47 | if (zeroIndex == -1) { 48 | zeroIndex = i; 49 | } 50 | //3 51 | } else { 52 | //2 53 | if (zeroIndex != -1) { 54 | nums[zeroIndex] = num; 55 | nums[i] = 0; 56 | zeroIndex++; 57 | } 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_287_findDuplicate.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-08-07. 5 | * 287. 寻找重复数 6 | *

7 | * 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。 8 | *

9 | * 示例 1: 10 | *

11 | * 输入: [1,3,4,2,2] 12 | * 输出: 2 13 | * 示例 2: 14 | *

15 | * 输入: [3,1,3,4,2] 16 | * 输出: 3 17 | * 说明: 18 | *

19 | * 不能更改原数组(假设数组是只读的)。 20 | * 只能使用额外的 O(1) 的空间。 21 | * 时间复杂度小于 O(n^2) 。 22 | * 数组中只有一个重复的数字,但它可能不止重复出现一次。 23 | *

24 | * 来源:力扣(LeetCode) 25 | * 链接:https://leetcode-cn.com/problems/find-the-duplicate-number 26 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 27 | */ 28 | public class _287_findDuplicate { 29 | 30 | public static void main(String[] args) { 31 | _287_findDuplicate findDuplicate = new _287_findDuplicate(); 32 | // System.out.println(findDuplicate.findDuplicate(new int[]{1, 3, 4, 2, 2})); 33 | // System.out.println(findDuplicate.findDuplicate(new int[]{3, 1, 3, 4, 2})); 34 | System.out.println(findDuplicate.findDuplicate(new int[]{2, 5, 9, 6, 9, 3, 8, 9, 7, 1})); 35 | } 36 | 37 | /** 38 | * 题意解读: 39 | * 1、数组只读==>不能对数组进行重排序==>排序取连续两个相同的 40 | * 2、O(1)空间==>不能用哈希等进行遍历存储==>哈希取出现次数>1的 41 | * 3、O(n^2)的时间复杂度==>少于2次循环遍历,可以一次循环或者二分 42 | * 如果没有上述限制,上面的方法都可行 43 | *

44 | * 解题思路: 45 | * 仔细看题目,发现数组大小n+1,数组数字1-n,一定会存在重复数字 46 | * 从0开始遍历,最开始一条直线,到后面会形成个环,可参考这张图 https://img-blog.csdn.net/20160101111128525 47 | * 从图中来看,环和直线相遇的点就是重复数 48 | * 1.用快慢指针,找到第一次相遇的点 49 | * 2.将一个指针移至起始点,再次相遇的一定是环和直线相遇的点,也就是重复数 50 | * 51 | * 计算详解:https://leetcode-cn.com/problems/find-the-duplicate-number/solution/287-xun-zhao-zhong-fu-shu-java-kuai-man-zhi-zhen-t/ 52 | * 53 | * @param nums 54 | * @return 55 | */ 56 | public int findDuplicate(int[] nums) { 57 | // 1.找到第一次相遇点 58 | int slow = nums[0]; 59 | int fast = nums[0]; 60 | do { 61 | slow = nums[slow]; 62 | fast = nums[nums[fast]]; 63 | } while (slow != fast); 64 | 65 | // 2.找第二次相遇点 66 | int ptr1 = nums[0]; 67 | int ptr2 = slow; 68 | while (ptr1 != ptr2) { 69 | ptr1 = nums[ptr1]; 70 | ptr2 = nums[ptr2]; 71 | } 72 | 73 | return ptr1; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_28_strStr.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-04-15. 5 | * 28. 实现strStr() 6 | *

7 | * 实现 strStr() 函数。 8 | *

9 | * 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。 10 | *

11 | * 示例 1: 12 | *

13 | * 输入: haystack = "hello", needle = "ll" 14 | * 输出: 2 15 | * 示例 2: 16 | *

17 | * 输入: haystack = "aaaaa", needle = "bba" 18 | * 输出: -1 19 | * 说明: 20 | *

21 | * 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 22 | *

23 | * 对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。 24 | * 25 | * @see implement-strstr 26 | */ 27 | public class _28_strStr { 28 | public static void main(String[] args) { 29 | _28_strStr str = new _28_strStr(); 30 | System.out.println(str.strStr("hello", "ll")); 31 | System.out.println(str.strStr("aaaaa", "aab")); 32 | System.out.println(str.strStr("a", "a")); 33 | System.out.println(str.strStr("babbbbbabb", "bbab")); 34 | } 35 | 36 | /** 37 | * 解题思路 38 | * 本题是实现Java字符串中的 {@link String#indexOf(String)}方法 39 | * 1、开始遍历 haystack,找到和 needle 相同的起始下标si 40 | * 2、从si开始同时遍历 haystack和needle 41 | * 3、如遍历过程中一直相同,则返回si,否则si后移1位 42 | * 43 | * @param haystack 44 | * @param needle 45 | * @return 46 | */ 47 | public int strStr(String haystack, String needle) { 48 | if (needle.length() == 0) { 49 | return 0; 50 | } 51 | if (haystack.length() < needle.length()) { 52 | return -1; 53 | } 54 | int ei; 55 | for (int i = 0; i < haystack.length() - needle.length() + 1; i++) { 56 | if (haystack.charAt(i) == needle.charAt(0)) { 57 | ei = i; 58 | for (int j = 1; j < needle.length(); j++) { 59 | if (haystack.charAt(++ei) != needle.charAt(j)) { 60 | break; 61 | } 62 | } 63 | if (haystack.charAt(ei) == needle.charAt(ei - i)) { 64 | //找到了 65 | return i; 66 | } 67 | } 68 | } 69 | 70 | 71 | return -1; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_307_NumArray.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/9/29. 5 | * 307.区域和检索 - 数组可修改 6 | *

7 | * 给定一个整数数组 nums,求出数组从索引 i 到 j (i ≤ j) 范围内元素的总和,包含 i, j 两点。 8 | *

9 | * update(i, val) 函数可以通过将下标为 i 的数值更新为 val,从而对数列进行修改。 10 | *

11 | * 示例: 12 | *

13 | * Given nums = [1, 3, 5] 14 | *

15 | * sumRange(0, 2) -> 9 16 | * update(1, 2) 17 | * sumRange(0, 2) -> 8 18 | * 说明: 19 | *

20 | * 数组仅可以在 update 函数下进行修改。 21 | * 你可以假设 update 函数与 sumRange 函数的调用次数是均匀分布的。 22 | * 23 | * @see range-sum-query-mutable 24 | */ 25 | public class _307_NumArray { 26 | 27 | public static void main(String[] args) { 28 | NumArray numArray = new NumArray(new int[]{1, 3, 5}); 29 | System.out.println(numArray.sumRange(0,2)); 30 | numArray.update(1,2); 31 | System.out.println(numArray.sumRange(0,2)); 32 | } 33 | 34 | /** 35 | * 最简单的实现 36 | * update复杂度O(1) 37 | * sum复杂度O(n) 38 | */ 39 | private static class NumArray { 40 | int[] nums; 41 | 42 | public NumArray(int[] nums) { 43 | this.nums = nums; 44 | } 45 | 46 | public void update(int i, int val) { 47 | nums[i] = val; 48 | } 49 | 50 | public int sumRange(int i, int j) { 51 | int total = 0; 52 | for (int k = i; k <= j; k++) { 53 | total += nums[k]; 54 | } 55 | return total; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_315_countSmaller_2.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by wangpeng on 2018/9/13. 10 | */ 11 | public class _315_countSmaller_2 { 12 | public static void main(String[] args) { 13 | long start = System.currentTimeMillis(); 14 | List list = countSmaller(new int[]{5, 2, 6, 1}); 15 | long end = System.currentTimeMillis(); 16 | System.out.println("(end-start):" + (end - start)); 17 | Util.printList(list); 18 | } 19 | 20 | public static List countSmaller(int[] nums) { 21 | if (nums.length == 0) { 22 | return new ArrayList<>(); 23 | } 24 | int min = Integer.MAX_VALUE; 25 | for (int value : nums) { 26 | if (value < min) { 27 | min = value; 28 | } 29 | } 30 | for (int i = 0; i < nums.length; i++) { 31 | nums[i] = nums[i] - min + 1; 32 | } 33 | int max = Integer.MIN_VALUE; 34 | for (int value : nums) { 35 | if (value > max) { 36 | max = value; 37 | } 38 | } 39 | int[] BITree = new int[max + 1]; 40 | BITree[0] = 0; 41 | int[] countArr = new int[nums.length]; 42 | for (int i = nums.length - 1; i >= 0; i--) { 43 | int count = getSum(nums[i] - 1, BITree); 44 | countArr[i] = count; 45 | update(nums[i], BITree); 46 | } 47 | List result = new ArrayList<>(); 48 | for (int value : countArr) { 49 | result.add(value); 50 | } 51 | return result; 52 | } 53 | 54 | public static int getSum(int value, int[] BITree) { 55 | int sum = 0; 56 | while (value > 0) { 57 | sum += BITree[value]; 58 | value -= (value & -value); 59 | } 60 | return sum; 61 | } 62 | 63 | public static void update(int value, int[] BITree) { 64 | while (value <= BITree.length - 1) { 65 | BITree[value] += 1; 66 | value += (value & -value); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_328_OddEvenList.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.ListNode; 5 | 6 | /** 7 | * Created by wangpeng on 2018/8/21. 8 | * 奇偶链表 9 | * 给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。 10 | *

11 | * 请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。 12 | *

13 | * 示例 1: 14 | * 输入: 1->2->3->4->5->NULL 15 | * 输出: 1->3->5->2->4->NULL 16 | * 17 | * @see odd-even-linked-list 18 | */ 19 | public class _328_OddEvenList { 20 | 21 | public static void main(String[] args) { 22 | ListNode node = Util.generateListNodeBySize(5); 23 | Util.printListNode(node); 24 | ListNode oddEvenList = oddEvenList(node); 25 | Util.printListNode(oddEvenList); 26 | } 27 | 28 | public static ListNode oddEvenList(ListNode head) { 29 | ListNode oddDummy = new ListNode(0); 30 | ListNode evenDummy = new ListNode(0); 31 | ListNode oddNext = oddDummy; 32 | ListNode evenNext = evenDummy; 33 | int index = 1; 34 | while (head != null) { 35 | if (index % 2 == 0) { 36 | evenNext.next = head; 37 | evenNext = head; 38 | } else { 39 | oddNext.next = head; 40 | oddNext = head; 41 | } 42 | index++; 43 | head = head.next; 44 | } 45 | evenNext.next = null; 46 | oddNext.next = evenDummy.next; 47 | 48 | return oddDummy.next; 49 | } 50 | 51 | public static ListNode oddEvenListOther(ListNode head) { 52 | if (head != null) { 53 | 54 | ListNode odd = head, even = head.next, evenHead = even; 55 | 56 | while (even != null && even.next != null) { 57 | odd.next = odd.next.next; 58 | even.next = even.next.next; 59 | odd = odd.next; 60 | even = even.next; 61 | } 62 | odd.next = evenHead; 63 | } 64 | return head; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_338_countBits.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | /** 6 | * Created by wangpeng on 2019-05-13. 7 | * 338. 比特位计数 8 | *

9 | * 给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。 10 | *

11 | * 示例 1: 12 | *

13 | * 输入: 2 14 | * 输出: [0,1,1] 15 | * 示例 2: 16 | *

17 | * 输入: 5 18 | * 输出: [0,1,1,2,1,2] 19 | * 进阶: 20 | *

21 | * 给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗? 22 | * 要求算法的空间复杂度为O(n)。 23 | * 你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount)来执行此操作。 24 | * 25 | * @see counting-bits 26 | */ 27 | public class _338_countBits { 28 | public static void main(String[] args) { 29 | _338_countBits countBits = new _338_countBits(); 30 | Util.printArray(countBits.countBits(2)); 31 | Util.printArray(countBits.countBits(5)); 32 | } 33 | 34 | /** 35 | * 题目已经强调了需要O(n)的复杂度,只能遍历一遍,可以考虑动态规划 36 | * 根据题目意思,先手动画一下数字和2进制的具体映射关系 37 | * 数字 0 1 2 3 4 5 6 7 8 38 | * 二进 0 1 10 11 100 101 110 111 1000 39 | * 1个数 0 1 1 2 1 2 2 3 1 40 | * 根据递推效果,看着好像没有什么规律 41 | * 但是仔细思考下,10进制转2进制必须要除以2,有些能整除,有些不能整除 42 | * 不能整除的3的1个数=3/1=数字1的1个数+1 43 | * 能整除的4的的1个数=4/2=数字2的1个数 44 | * 拿其他数字验证后发现的确是这个规律,得到动态规划状态转移方程: 45 | * int d = i / 2; 46 | * int m = i % 2; 47 | * if (m == 0) { 48 | * dp[i] = dp[d]; 49 | * } else { 50 | * dp[i] = dp[d] + 1; 51 | * } 52 | * 53 | * @param num 54 | * @return 55 | */ 56 | public int[] countBits(int num) { 57 | if (num < 0) return new int[0]; 58 | int[] dp = new int[num + 1]; 59 | dp[0] = 0; 60 | for (int i = 1; i <= num; i++) { 61 | int d = i / 2; 62 | int m = i % 2; 63 | if (m == 0) { 64 | dp[i] = dp[d]; 65 | } else { 66 | dp[i] = dp[d] + 1; 67 | } 68 | } 69 | 70 | return dp; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_343_integerBreak.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-05-13. 5 | * 343. 整数拆分 6 | *

7 | * 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 8 | *

9 | * 示例 1: 10 | *

11 | * 输入: 2 12 | * 输出: 1 13 | * 解释: 2 = 1 + 1, 1 × 1 = 1。 14 | * 示例 2: 15 | *

16 | * 输入: 10 17 | * 输出: 36 18 | * 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。 19 | * 说明: 你可以假设 n 不小于 2 且不大于 58。 20 | * 21 | * @see integer-break 22 | */ 23 | public class _343_integerBreak { 24 | public static void main(String[] args) { 25 | _343_integerBreak integerBreak = new _343_integerBreak(); 26 | System.out.println(integerBreak.integerBreak(8)); 27 | System.out.println(integerBreak.integerBreak(10)); 28 | System.out.println(integerBreak.integerBreak(14)); 29 | } 30 | 31 | /** 32 | * 解题思路: 33 | * 手动模拟了从2-10的最大乘积数字拆解,发现了一个现象: 34 | * 对于数字n,n一直除以2到1为止,得到的数字就是最大的乘积,举例如下: 35 | * 数字n 2 3 4 5 6 7 8 9 10 36 | * 乘积 1,1 1,2 2,2 2,3 3,3 3,4(2,2) 4(2,2),4(2,2) 4,5(2,3) 5(2,3),5(2,3) 37 | * 发现到了后面的最大乘积可以利用之前的计算好的结果,从而得出动态规划转移方程 38 | * dp[i]=dp[i/2]*dp[i-i/2](i>3) 39 | * 上面有问题,例如8的最大值不是除以2得到4*4=16,而是3*2*3=18,所以得双重循环取所有情况的最大值 40 | * for (int j = 1; j <= i / 2; j++) { 41 | * dp[i] = Math.max(dp[i], dp[j] * dp[i - j]); 42 | * } 43 | * 44 | * @param n 45 | * @return 46 | */ 47 | public int integerBreak(int n) { 48 | if (n <= 3) return n - 1; 49 | int[] dp = new int[n + 1]; 50 | //初始化,1,2,3特殊处理 51 | dp[1] = 1; 52 | dp[2] = 2; 53 | dp[3] = 3; 54 | for (int i = 4; i <= n; i++) { 55 | for (int j = 1; j <= i / 2; j++) { 56 | dp[i] = Math.max(dp[i], dp[j] * dp[i - j]); 57 | } 58 | } 59 | return dp[n]; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_35_searchInsert.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/9/12. 5 | * 35. 搜索插入位置 6 | *

7 | * 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 8 | *

9 | * 你可以假设数组中无重复元素。 10 | *

11 | * 示例 1: 12 | *

13 | * 输入: [1,3,5,6], 5 14 | * 输出: 2 15 | * 示例 2: 16 | *

17 | * 输入: [1,3,5,6], 2 18 | * 输出: 1 19 | * 示例 3: 20 | *

21 | * 输入: [1,3,5,6], 7 22 | * 输出: 4 23 | * 示例 4: 24 | *

25 | * 输入: [1,3,5,6], 0 26 | * 输出: 0 27 | * 28 | * @see search-insert-position 29 | */ 30 | public class _35_searchInsert { 31 | public static void main(String[] args) { 32 | int i = searchInsert(new int[]{1, 3, 5, 6}, 2); 33 | System.out.println(i); 34 | int i1 = searchInsert(new int[]{1, 3, 5, 6}, 7); 35 | System.out.println(i1); 36 | int i2 = searchInsert(new int[]{1, 3, 5, 6}, 0); 37 | System.out.println(i2); 38 | int i3 = searchInsert(new int[]{}, 0); 39 | System.out.println(i3); 40 | } 41 | 42 | public static int searchInsert(int[] nums, int target) { 43 | if (nums == null || nums.length == 0) { 44 | return 0; 45 | } 46 | int start = 0; 47 | int end = nums.length - 1; 48 | int middle; 49 | while (start <= end) { 50 | middle = (start + end) / 2; 51 | if (target < nums[middle]) { 52 | if (middle == 0) { 53 | return 0; 54 | } else if (target > nums[middle - 1]) { 55 | return middle; 56 | } 57 | end = middle - 1; 58 | } else if (target > nums[middle]) { 59 | if (middle == nums.length - 1) { 60 | return nums.length; 61 | } else if (target < nums[middle + 1]) { 62 | return middle + 1; 63 | } 64 | start = middle + 1; 65 | } else { 66 | return middle; 67 | } 68 | } 69 | return 0; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_38_countAndSay.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-05-14. 5 | * 38. 报数 6 | *

7 | * 报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下: 8 | *

9 | * 1. 1 10 | * 2. 11 11 | * 3. 21 12 | * 4. 1211 13 | * 5. 111221 14 | * 1 被读作 "one 1" ("一个一") , 即 11。 15 | * 11 被读作 "two 1s" ("两个一"), 即 21。 16 | * 21 被读作 "one 2", "one 1" ("一个二" , "一个一") , 即 1211。 17 | *

18 | * 给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。 19 | *

20 | * 注意:整数顺序将表示为一个字符串。 21 | *

22 | *

23 | *

24 | * 示例 1: 25 | *

26 | * 输入: 1 27 | * 输出: "1" 28 | * 示例 2: 29 | *

30 | * 输入: 4 31 | * 输出: "1211" 32 | * 33 | * @see count-and-say 34 | */ 35 | public class _38_countAndSay { 36 | 37 | public static void main(String[] args) { 38 | _38_countAndSay countAndSay = new _38_countAndSay(); 39 | System.out.println(countAndSay.countAndSay(4)); 40 | System.out.println(countAndSay.countAndSay(5)); 41 | System.out.println(countAndSay.countAndSay(6)); 42 | } 43 | 44 | /** 45 | * 解题思路: 46 | * 本题的难点在于:报数的概念理解,至少我从题意中没有很清晰的理解,但是感觉像是个递推式 47 | * 从4->5分析,将4个每一位拆开看(个数+数字),4=1211 => 1=11,2=12,11=21,所以5=111221 48 | * 所以解题用循环,从1->n可求解出来 49 | * 50 | * @param n 51 | * @return 52 | */ 53 | public String countAndSay(int n) { 54 | String str = "1"; 55 | for (int i = 2; i <= n; i++) { 56 | StringBuilder builder = new StringBuilder(); 57 | char pre = str.charAt(0); 58 | int count = 1; 59 | for (int j = 1; j < str.length(); j++) { 60 | char c = str.charAt(j); 61 | if (c == pre) { 62 | count++; 63 | } else { 64 | builder.append(count).append(pre); 65 | pre = c; 66 | count = 1; 67 | } 68 | } 69 | builder.append(count).append(pre); 70 | str = builder.toString(); 71 | } 72 | 73 | return str; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_406_reconstructQueue.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | import java.util.Arrays; 6 | import java.util.LinkedList; 7 | import java.util.List; 8 | 9 | /** 10 | * Created by wangpeng on 2019-08-27. 11 | * 406. 根据身高重建队列 12 | *

13 | * 假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)表示,其中h是这个人的身高,k是排在这个人前面且身高大于或等于h的人数。 编写一个算法来重建这个队列。 14 | *

15 | * 注意: 16 | * 总人数少于1100人。 17 | *

18 | * 示例 19 | *

20 | * 输入: 21 | * [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]] 22 | *

23 | * 输出: 24 | * [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]] 25 | *

26 | * 来源:力扣(LeetCode) 27 | * 链接:https://leetcode-cn.com/problems/queue-reconstruction-by-height 28 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 29 | */ 30 | public class _406_reconstructQueue { 31 | 32 | public static void main(String[] args) { 33 | _406_reconstructQueue reconstructQueue = new _406_reconstructQueue(); 34 | int[][] ints = reconstructQueue.reconstructQueue(new int[][]{ 35 | {7, 0}, {7, 1}, {6, 1}, {5, 0}, {5, 2}, {4, 4} 36 | }); 37 | for (int i = 0; i < ints.length; i++) { 38 | Util.printArray(ints[i]); 39 | } 40 | } 41 | 42 | /** 43 | * 解题思路:先排序再插入 44 | * 1.排序规则:按照先H高度降序,K个数升序排序 45 | * 2.遍历排序后的数组,根据K插入到K的位置上 46 | * 47 | * 核心思想:高个子先站好位,矮个子插入到K位置上,前面肯定有K个高个子,矮个子再插到前面也满足K的要求 48 | * 49 | * @param people 50 | * @return 51 | */ 52 | public int[][] reconstructQueue(int[][] people) { 53 | // [7,0], [7,1], [6,1], [5,0], [5,2], [4,4] 54 | // 再一个一个插入。 55 | // [7,0] 56 | // [7,0], [7,1] 57 | // [7,0], [6,1], [7,1] 58 | // [5,0], [7,0], [6,1], [7,1] 59 | // [5,0], [7,0], [5,2], [6,1], [7,1] 60 | // [5,0], [7,0], [5,2], [6,1], [4,4], [7,1] 61 | Arrays.sort(people, (o1, o2) -> o1[0] == o2[0] ? o1[1] - o2[1] : o2[0] - o1[0]); 62 | 63 | LinkedList list = new LinkedList<>(); 64 | for (int[] i : people) { 65 | list.add(i[1], i); 66 | } 67 | 68 | return list.toArray(new int[list.size()][2]); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_415_addStrings.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-02-01. 5 | * 415. 字符串相加 6 | *

7 | * 给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。 8 | *

9 | * 注意: 10 | *

11 | * num1 和num2 的长度都小于 5100. 12 | * num1 和num2 都只包含数字 0-9. 13 | * num1 和num2 都不包含任何前导零。 14 | * 你不能使用任何內建 BigInteger 库, 也不能直接将输入的字符串转换为整数形式。 15 | * 16 | * @see add-strings 17 | */ 18 | public class _415_addStrings { 19 | 20 | public static void main(String[] args) { 21 | System.out.println(addStrings("1000", "8000")); 22 | } 23 | 24 | public static String addStrings(String num1, String num2) { 25 | int i = 0; 26 | int nextAdd = 0; 27 | char[] chars = new char[Math.max(num1.length(), num2.length()) + 1]; 28 | for (int j = 0; j < chars.length; j++) { 29 | chars[j] = '0'; 30 | } 31 | while (i < num1.length() && i < num2.length()) { 32 | int i1 = num1.charAt(num1.length() - i - 1) - '0'; 33 | int i2 = num2.charAt(num2.length() - i - 1) - '0'; 34 | int current = i1 + i2 + nextAdd; 35 | nextAdd = current / 10; 36 | current = current % 10; 37 | chars[chars.length - i - 1] = (char) (current + '0'); 38 | i++; 39 | } 40 | while (i < num1.length()) { 41 | int i1 = num1.charAt(num1.length() - i - 1) - '0'; 42 | int current = i1 + nextAdd; 43 | nextAdd = current / 10; 44 | current = current % 10; 45 | chars[chars.length - i - 1] = (char) (current + '0'); 46 | i++; 47 | } 48 | while (i < num2.length()) { 49 | int i2 = num2.charAt(num2.length() - i - 1) - '0'; 50 | int current = i2 + nextAdd; 51 | nextAdd = current / 10; 52 | current = current % 10; 53 | chars[chars.length - i - 1] = (char) (current + '0'); 54 | i++; 55 | } 56 | if (nextAdd > 0) { 57 | chars[chars.length - i - 1] = (char) (nextAdd + '0'); 58 | } 59 | if (chars[0] == '0') { 60 | return new String(chars).substring(1); 61 | } 62 | return new String(chars); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_42_trap.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-03-04. 5 | * 42. 接雨水 6 | *

7 | * 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 8 | *

9 | * 10 | *

11 | * 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。 12 | *

13 | * 示例: 14 | *

15 | * 输入: [0,1,0,2,1,0,1,3,2,1,2,1] 16 | * 输出: 6 17 | * 18 | * @see trapping-rain-water 19 | */ 20 | public class _42_trap { 21 | 22 | public static void main(String[] args) { 23 | _42_trap trap = new _42_trap(); 24 | int trap1 = trap.trap(new int[]{0, 1, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}); 25 | System.out.println(trap1); 26 | System.out.println(trap.trap(new int[]{2, 6, 3, 8, 2, 7, 2, 5, 0})); 27 | } 28 | 29 | public int trap(int[] height) { 30 | int n = height.length, idx = 0, lefth = 0, righth = 0, area = 0; 31 | for (int i = 0; i < n; i++) 32 | idx = height[idx] <= height[i] ? i : idx; 33 | for (int i = 0; i < idx; i++) { 34 | if (height[i] < lefth) 35 | area += lefth - height[i]; 36 | else 37 | lefth = height[i]; 38 | } 39 | for (int i = n - 1; i > idx; i--) { 40 | if (height[i] < righth) 41 | area += righth - height[i]; 42 | else 43 | righth = height[i]; 44 | } 45 | return area; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_438_findAnagrams.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by wangpeng on 2019-01-29. 10 | * 438. 找到字符串中所有字母异位词 11 | *

12 | * 给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。 13 | *

14 | * 字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。 15 | *

16 | * 说明: 17 | *

18 | * 字母异位词指字母相同,但排列不同的字符串。 19 | * 不考虑答案输出的顺序。 20 | * 示例 1: 21 | *

22 | * 输入: 23 | * s: "cbaebabacd" p: "abc" 24 | *

25 | * 输出: 26 | * [0, 6] 27 | *

28 | * 解释: 29 | * 起始索引等于 0 的子串是 "cba", 它是 "abc" 的字母异位词。 30 | * 起始索引等于 6 的子串是 "bac", 它是 "abc" 的字母异位词。 31 | * 示例 2: 32 | *

33 | * 输入: 34 | * s: "abab" p: "ab" 35 | *

36 | * 输出: 37 | * [0, 1, 2] 38 | *

39 | * 解释: 40 | * 起始索引等于 0 的子串是 "ab", 它是 "ab" 的字母异位词。 41 | * 起始索引等于 1 的子串是 "ba", 它是 "ab" 的字母异位词。 42 | * 起始索引等于 2 的子串是 "ab", 它是 "ab" 的字母异位词。 43 | * 44 | * @see find-leetcode-anagrams-in-a-string 45 | */ 46 | public class _438_findAnagrams { 47 | 48 | public static void main(String[] args) { 49 | Util.printList(findAnagrams("cbaebabacd", "abc")); 50 | Util.printList(findAnagrams("abab", "ab")); 51 | } 52 | 53 | /** 54 | * 更优的解法 55 | * 56 | * @param s 57 | * @param p 58 | * @return 59 | */ 60 | public static List findAnagrams(String s, String p) { 61 | int l = 0, r = 0; 62 | int count = p.length(); 63 | int[] freq = new int[26]; 64 | for (int i = 0; i res = new ArrayList<>(); 68 | while (r < s.length()) { 69 | //当前元素次数减一 70 | freq[s.charAt(r)-'a']--; 71 | if (freq[s.charAt(r++)-'a'] >= 0) { 72 | count--; 73 | } 74 | while (count == 0) { 75 | if ((r - l) == p.length()) { 76 | res.add(l); 77 | } 78 | if (freq[s.charAt(l)-'a'] == 0){ 79 | count++; 80 | } 81 | freq[s.charAt(l++)-'a']++; 82 | } 83 | 84 | } 85 | return res; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_43_multiply.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-02-01. 5 | * 43. 字符串相乘 6 | *

7 | * 给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。 8 | *

9 | * 示例 1: 10 | *

11 | * 输入: num1 = "2", num2 = "3" 12 | * 输出: "6" 13 | * 示例 2: 14 | *

15 | * 输入: num1 = "123", num2 = "456" 16 | * 输出: "56088" 17 | * 说明: 18 | *

19 | * num1 和 num2 的长度小于110。 20 | * num1 和 num2 只包含数字 0-9。 21 | * num1 和 num2 均不以零开头,除非是数字 0 本身。 22 | * 不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。 23 | * 24 | * @see multiply-strings 25 | */ 26 | public class _43_multiply { 27 | 28 | public static void main(String[] args) { 29 | System.out.println(multiply("2", "3")); 30 | System.out.println(multiply("123", "456")); 31 | System.out.println(multiply("0", "0")); 32 | System.out.println(multiply("9", "9")); 33 | } 34 | 35 | public static String multiply(String num1, String num2) { 36 | char[] chars = new char[num1.length() + num2.length()]; 37 | for (int i = 0; i < chars.length; i++) { 38 | chars[i] = '0'; 39 | } 40 | for (int i = 0; i < num1.length(); i++) { 41 | int i1 = num1.charAt(num1.length() - i - 1) - '0'; 42 | int next = 0; 43 | for (int j = 0; j < num2.length(); j++) { 44 | int i2 = num2.charAt(num2.length() - j - 1) - '0'; 45 | int charInt = chars[chars.length - i - j - 1] - '0'; 46 | int current = i1 * i2 + charInt + next; 47 | next = current / 10; 48 | current = current % 10; 49 | chars[chars.length - i - j - 1] = (char) (current + '0'); 50 | } 51 | if (next > 0) { 52 | chars[chars.length - i - num2.length() - 1] = (char) (next + '0'); 53 | } 54 | } 55 | int i = 0; 56 | while (i < chars.length && chars[i] == '0') { 57 | i++; 58 | } 59 | if (i >= chars.length) { 60 | return "0"; 61 | } 62 | return new String(chars).substring(i); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_454_fourSumCount.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * Created by wangpeng on 2019-04-10. 7 | * 454. 四数相加 II 8 | *

9 | * 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。 10 | *

11 | * 为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -228 到 228 - 1 之间,最终结果不会超过 231 - 1 。 12 | *

13 | * 例如: 14 | *

15 | * 输入: 16 | * A = [ 1, 2] 17 | * B = [-2,-1] 18 | * C = [-1, 2] 19 | * D = [ 0, 2] 20 | *

21 | * 输出: 22 | * 2 23 | *

24 | * 解释: 25 | * 两个元组如下: 26 | * 1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0 27 | * 2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0 28 | * 29 | * @see 4sum-ii 30 | */ 31 | public class _454_fourSumCount { 32 | public static void main(String[] args) { 33 | _454_fourSumCount fourSumCount = new _454_fourSumCount(); 34 | System.out.println(fourSumCount.fourSumCount( 35 | new int[]{-1, -1}, 36 | new int[]{-1, 1}, 37 | new int[]{-1, 1}, 38 | new int[]{-1, 1}) 39 | ); 40 | } 41 | 42 | /** 43 | * 最直接的方案就是四次循环拿到满足条件的计数,不过这个通不过,时间复杂度在O(n^4) 44 | * 可行解题思路: 45 | * 看题目关联到哈希表,所以往那个方向考虑下 46 | * 1、先将4个数组分层两组A+B,C+D 47 | * 2、定义个一个hash表,存储A+B所有的结果计数 48 | * 3、在遍历C+D的时候,取反后,看hash表中是否存在计数 49 | * 50 | * @param A 51 | * @param B 52 | * @param C 53 | * @param D 54 | * @return 55 | */ 56 | public int fourSumCount(int[] A, int[] B, int[] C, int[] D) { 57 | int retCount = 0; 58 | HashMap map = new HashMap<>(); 59 | for (int i = 0; i < A.length; i++) { 60 | for (int j = 0; j < B.length; j++) { 61 | int sumAB = A[i] + B[j]; 62 | map.put(sumAB, map.getOrDefault(sumAB, 0) + 1); 63 | } 64 | } 65 | for (int i = 0; i < C.length; i++) { 66 | for (int j = 0; j < D.length; j++) { 67 | int sumCD = C[i] + D[j]; 68 | retCount += map.getOrDefault(-sumCD, 0); 69 | } 70 | } 71 | 72 | return retCount; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_455_findContentChildren.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by wangpeng on 2018/9/6. 7 | * 455. 分发饼干 8 | *

9 | * 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。 10 | * 但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi , 11 | * 这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。 12 | * 如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。 13 | * 你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 14 | *

15 | * 注意: 16 | *

17 | * 你可以假设胃口值为正。 18 | * 一个小朋友最多只能拥有一块饼干。 19 | *

20 | * 示例 1: 21 | *

22 | * 输入: [1,2,3], [1,1] 23 | *

24 | * 输出: 1 25 | *

26 | * 解释: 27 | * 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 28 | * 虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 29 | * 所以你应该输出1。 30 | * 示例 2: 31 | *

32 | * 输入: [1,2], [1,2,3] 33 | *

34 | * 输出: 2 35 | *

36 | * 解释: 37 | * 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 38 | * 你拥有的饼干数量和尺寸都足以让所有孩子满足。 39 | * 所以你应该输出2. 40 | * 41 | * @see assign-cookies 42 | */ 43 | public class _455_findContentChildren { 44 | public static void main(String[] args) { 45 | int contentChildren = findContentChildren(new int[]{10, 9, 9, 7}, new int[]{5, 6, 7, 8}); 46 | System.out.println(contentChildren); 47 | } 48 | 49 | /** 50 | * 贪心策略:用尽可能小的饼干,满足胃口尽可能小的孩子 51 | * g、s可能是无序的 52 | * 53 | * @param g 54 | * @param s 55 | * @return 56 | */ 57 | public static int findContentChildren(int[] g, int[] s) { 58 | //先排序 59 | Arrays.sort(g); 60 | Arrays.sort(s); 61 | int child = 0; 62 | for (int i = 0; i < s.length && child < g.length; i++) { 63 | if (s[i] < g[child]) { 64 | continue; 65 | } 66 | child++; 67 | } 68 | return child; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_45_jump.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/9/7. 5 | * 45. 跳跃游戏 II 6 | * 给定一个非负整数数组,你最初位于数组的第一个位置。 7 | *

8 | * 数组中的每个元素代表你在该位置可以跳跃的最大长度。 9 | *

10 | * 你的目标是使用最少的跳跃次数到达数组的最后一个位置。 11 | *

12 | * 示例: 13 | *

14 | * 输入: [2,3,1,1,4] 15 | * 输出: 2 16 | * 解释: 跳到最后一个位置的最小跳跃数是 2。 17 | * 从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。 18 | * 说明: 19 | *

20 | * 假设你总是可以到达数组的最后一个位置。 21 | * 22 | * @see jump-game-ii 23 | */ 24 | public class _45_jump { 25 | public static void main(String[] args) { 26 | int b1 = jump(new int[]{2, 3, 1, 1, 4}); 27 | //2 28 | System.out.println(b1); 29 | //1 30 | int b2 = jump(new int[]{1, 2}); 31 | System.out.println(b2); 32 | //1 33 | int b3 = jump(new int[]{2, 0, 0}); 34 | System.out.println(b3); 35 | //0 36 | int b4 = jump(new int[]{0}); 37 | System.out.println(b4); 38 | } 39 | 40 | /** 41 | * 贪心规律:每步走的更远,那么用的步数就越少 42 | * 43 | * @param nums 44 | * @return 45 | */ 46 | public static int jump(int[] nums) { 47 | if (nums.length < 2) { 48 | return 0; 49 | } 50 | //1,2 51 | //2, 3, 1, 1, 4 52 | int step = 1; 53 | //之前最大的 54 | int pre = nums[0]; 55 | //当前能走最远的 56 | int cur = nums[0]; 57 | for (int i = 0; i < nums.length; i++) { 58 | if (i > cur) { 59 | step++; 60 | cur = pre; 61 | } 62 | if (i + nums[i] > pre) { 63 | pre = i + nums[i]; 64 | } 65 | } 66 | return step; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_485_findMaxConsecutiveOnes.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-03-27. 5 | * 485. 最大连续1的个数 6 | *

7 | * 给定一个二进制数组, 计算其中最大连续1的个数。 8 | *

9 | * 示例 1: 10 | *

11 | * 输入: [1,1,0,1,1,1] 12 | * 输出: 3 13 | * 解释: 开头的两位和最后的三位都是连续1,所以最大连续1的个数是 3. 14 | * 注意: 15 | *

16 | * 输入的数组只包含 0 和1。 17 | * 输入数组的长度是正整数,且不超过 10,000。 18 | * 19 | * @see max-consecutive-ones 20 | */ 21 | public class _485_findMaxConsecutiveOnes { 22 | 23 | public static void main(String[] args) { 24 | _485_findMaxConsecutiveOnes ones = new _485_findMaxConsecutiveOnes(); 25 | System.out.println(ones.findMaxConsecutiveOnes(new int[]{1, 1, 0, 1, 1, 1})); 26 | } 27 | 28 | public int findMaxConsecutiveOnes(int[] nums) { 29 | int max = 0; 30 | int itemCount = 0; 31 | for (int ri = 0; ri < nums.length; ri++) { 32 | if (nums[ri] == 1) { 33 | itemCount++; 34 | } else { 35 | max = Math.max(max, itemCount); 36 | itemCount = 0; 37 | } 38 | } 39 | max = Math.max(max, itemCount); 40 | 41 | return max; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_49_groupAnagrams.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | import java.util.*; 6 | 7 | /** 8 | * Created by wangpeng on 2018/9/18. 9 | * 49.字母异位词分组 10 | *

11 | * 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 12 | *

13 | * 示例: 14 | *

15 | * 输入: ["eat", "tea", "tan", "ate", "nat", "bat"], 16 | * 输出: 17 | * [ 18 | * ["ate","eat","tea"], 19 | * ["nat","tan"], 20 | * ["bat"] 21 | * ] 22 | * 说明: 23 | *

24 | * 所有输入均为小写字母。 25 | * 不考虑答案输出的顺序。 26 | * 27 | * @see group-anagrams 28 | */ 29 | public class _49_groupAnagrams { 30 | 31 | public static void main(String[] args) { 32 | String[] strs = new String[]{"eat", "tea", "tan", "ate", "nat", "bat"}; 33 | List> lists = groupAnagrams(strs); 34 | for (int i = 0; i < lists.size(); i++) { 35 | Util.printStringList(lists.get(i)); 36 | } 37 | } 38 | 39 | public static List> groupAnagrams(String[] strs) { 40 | List> result = new ArrayList<>(); 41 | Map> map = new HashMap<>(); 42 | for (int i = 0; i < strs.length; i++) { 43 | String sort = sort(strs[i]); 44 | List list = map.get(sort); 45 | if (list == null) { 46 | list = new ArrayList<>(); 47 | map.put(sort, list); 48 | } 49 | list.add(strs[i]); 50 | } 51 | for (Map.Entry> entry : 52 | map.entrySet()) { 53 | result.add(entry.getValue()); 54 | } 55 | return result; 56 | } 57 | 58 | private static String sort(String src) { 59 | char[] chars = src.toCharArray(); 60 | Arrays.sort(chars); 61 | return new String(chars); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_4_findMedianSortedArrays.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/10/24. 5 | * 4. 两个排序数组的中位数 6 | *

7 | * 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 。 8 | *

9 | * 请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。 10 | *

11 | * 你可以假设 nums1 和 nums2 不同时为空。 12 | *

13 | * 示例 1: 14 | *

15 | * nums1 = [1, 3] 16 | * nums2 = [2] 17 | *

18 | * 中位数是 2.0 19 | * 示例 2: 20 | *

21 | * nums1 = [1, 2] 22 | * nums2 = [3, 4] 23 | *

24 | * 中位数是 (2 + 3)/2 = 2.5 25 | * 26 | * @see median-of-two-sorted-arrays 27 | */ 28 | public class _4_findMedianSortedArrays { 29 | 30 | public static void main(String[] args) { 31 | double medianSortedArrays = findMedianSortedArrays(new int[]{1, 3}, new int[]{2}); 32 | System.out.println(medianSortedArrays); 33 | double medianSortedArrays1 = findMedianSortedArrays(new int[]{1, 2}, new int[]{3, 4}); 34 | System.out.println(medianSortedArrays1); 35 | } 36 | 37 | /** 38 | * 时间复杂度O(n),不满足要求 39 | * 40 | * @param nums1 41 | * @param nums2 42 | * @return 43 | */ 44 | public static double findMedianSortedArrays(int[] nums1, int[] nums2) { 45 | //先对两个有序数组进行排序,O(log)的时间复杂度=>归并排序 46 | int[] newArr = new int[nums1.length + nums2.length]; 47 | int i = 0; 48 | int j = 0; 49 | while (i < nums1.length && j < nums2.length) { 50 | if (nums1[i] < nums2[j]) { 51 | newArr[i + j] = nums1[i]; 52 | i++; 53 | } else { 54 | newArr[i + j] = nums2[j]; 55 | j++; 56 | } 57 | } 58 | while (i < nums1.length) { 59 | newArr[i + j] = nums1[i]; 60 | i++; 61 | } 62 | while (j < nums2.length) { 63 | newArr[i + j] = nums2[j]; 64 | j++; 65 | } 66 | double retVal; 67 | if (newArr.length % 2 == 0) { 68 | retVal = (newArr[newArr.length / 2] + newArr[newArr.length / 2 - 1]) / 2f; 69 | } else { 70 | retVal = newArr[newArr.length / 2]; 71 | } 72 | return retVal; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_50_myPow.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-06-22. 5 | * 50. Pow(x, n) 6 | *

7 | * 实现 pow(x, n) ,即计算 x 的 n 次幂函数。 8 | *

9 | * 示例 1: 10 | *

11 | * 输入: 2.00000, 10 12 | * 输出: 1024.00000 13 | * 示例 2: 14 | *

15 | * 输入: 2.10000, 3 16 | * 输出: 9.26100 17 | * 示例 3: 18 | *

19 | * 输入: 2.00000, -2 20 | * 输出: 0.25000 21 | * 解释: 2-2 = 1/22 = 1/4 = 0.25 22 | * 说明: 23 | *

24 | * -100.0 < x < 100.0 25 | * n 是 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1] 。 26 | *

27 | * 来源:力扣(LeetCode) 28 | * 链接:https://leetcode-cn.com/problems/powx-n 29 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 30 | */ 31 | public class _50_myPow { 32 | 33 | public static void main(String[] args) { 34 | _50_myPow pow = new _50_myPow(); 35 | System.out.println(pow.myPow(2.1, 3)); 36 | System.out.println(pow.myPow(2, -2)); 37 | System.out.println(pow.myPow(0.3, -2)); 38 | System.out.println(pow.myPow(0.3, 1)); 39 | System.out.println(pow.myPow(0.4127, 0)); 40 | System.out.println(pow.myPow(0.00001, 2147483647)); 41 | } 42 | 43 | /** 44 | * 解析思路: 45 | * 平方不就是n个数相乘么,n为负数的时候,先将x求倒数,再n次相乘(此方法会提交超时O(n)) 46 | *

47 | * 优化: 48 | * 将上述循环相乘的方法根据分治思想,一分为二(只需要求一半即可,另一半是相同的,奇数再*x),不断拆分至两个数相乘,时间复杂度优化到O(LogN) 49 | * 这个方法称为"快速幂乘法" 50 | * 51 | * @param x 52 | * @param n 53 | * @return 54 | */ 55 | public double myPow(double x, int n) { 56 | if (n < 0) { 57 | x = 1f / x; 58 | } 59 | n = Math.abs(n); 60 | //分治求解 61 | return fastPow(x, n); 62 | } 63 | 64 | double fastPow(double x, long n) { 65 | if (n == 0) { 66 | return 1.0; 67 | } 68 | double half = fastPow(x, n / 2); 69 | if (n % 2 == 0) { 70 | return half * half; 71 | } else { 72 | return half * half * x; 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_516_longestPalindromeSubseq.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/11/8. 5 | * 516. 最长回文子序列 6 | *

7 | * 给定一个字符串s,找到其中最长的回文子序列。可以假设s的最大长度为1000。 8 | *

9 | * 示例 1: 10 | * 输入: 11 | *

12 | * "bbbab" 13 | * 输出: 14 | *

15 | * 4 16 | * 一个可能的最长回文子序列为 "bbbb"。 17 | *

18 | * 示例 2: 19 | * 输入: 20 | *

21 | * "cbbd" 22 | * 输出: 23 | *

24 | * 2 25 | * 一个可能的最长回文子序列为 "bb"。 26 | * 27 | * @see longest-palindromic-subsequence 28 | */ 29 | public class _516_longestPalindromeSubseq { 30 | 31 | public static void main(String[] args) { 32 | int l1 = longestPalindromeSubseq("bbbab"); 33 | System.out.println(l1); 34 | long start = System.currentTimeMillis(); 35 | int l2 = longestPalindromeSubseq("euazbipzncptldueeuechubrcourfpftcebikrxhybkymimgvldiwqvkszfycvqyvtiwfckexmowcxztkfyzqovbtmzpxojfofbvwnncajvrvdbvjhcrameamcfmcoxryjukhpljwszknhiypvyskmsujkuggpztltpgoczafmfelahqwjbhxtjmebnymdyxoeodqmvkxittxjnlltmoobsgzdfhismogqfpfhvqnxeuosjqqalvwhsidgiavcatjjgeztrjuoixxxoznklcxolgpuktirmduxdywwlbikaqkqajzbsjvdgjcnbtfksqhquiwnwflkldgdrqrnwmshdpykicozfowmumzeuznolmgjlltypyufpzjpuvucmesnnrwppheizkapovoloneaxpfinaontwtdqsdvzmqlgkdxlbeguackbdkftzbnynmcejtwudocemcfnuzbttcoew"); 36 | System.out.println(l2); 37 | long end = System.currentTimeMillis(); 38 | System.out.println(end - start); 39 | } 40 | 41 | /** 42 | * 动态规划,时间复杂度O(n^2) 43 | * 44 | * @param s 45 | * @return 46 | */ 47 | public static int longestPalindromeSubseq(String s) { 48 | if (s == null || s.length() == 0) { 49 | return 0; 50 | } 51 | //i..j的区间内最大的子序列长度 52 | int[][] dp = new int[s.length()][s.length()]; 53 | for (int i = s.length() - 1; i >= 0; i--) { 54 | dp[i][i] = 1; 55 | for (int j = i + 1; j < s.length(); j++) { 56 | if (s.charAt(i) == s.charAt(j)) { 57 | dp[i][j] = dp[i + 1][j - 1] + 2; 58 | } else { 59 | dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]); 60 | } 61 | } 62 | } 63 | return dp[0][s.length() - 1]; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_538_convertBST.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.TreeNode; 5 | 6 | /** 7 | * Created by wangpeng on 2018/9/27. 8 | * 538.把二叉搜索树转换为累加树 9 | *

10 | * 给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和。 11 | *

12 | * 例如: 13 | *

14 | * 输入: 二叉搜索树: 15 | * 5 16 | * / \ 17 | * 2 13 18 | *

19 | * 输出: 转换为累加树: 20 | * 18 21 | * / \ 22 | * 20 13 23 | * 24 | * @see convert-bst-to-greater-tree 25 | */ 26 | public class _538_convertBST { 27 | public static void main(String[] args) { 28 | //[2,0,3,-4,1] 29 | TreeNode srcRoot = new TreeNode(2); 30 | TreeNode leftTree = new TreeNode(0); 31 | TreeNode rightTree = new TreeNode(3); 32 | srcRoot.left = leftTree; 33 | srcRoot.right = rightTree; 34 | leftTree.left = new TreeNode(-4); 35 | leftTree.right = new TreeNode(1); 36 | Util.printTree(srcRoot); 37 | convertBST(srcRoot); 38 | Util.printDivideLine(); 39 | Util.printTree(srcRoot); 40 | } 41 | 42 | private static int totalSum; 43 | 44 | public static TreeNode convertBST(TreeNode root) { 45 | totalSum = 0; 46 | dfs(root); 47 | return root; 48 | } 49 | 50 | private static void dfs(TreeNode node) { 51 | if (node == null) { 52 | return; 53 | } 54 | dfs(node.right); 55 | totalSum += node.val; 56 | node.val = totalSum; 57 | dfs(node.left); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_53_maxSubArray.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | /** 6 | * Created by wangpeng on 2018/9/24. 7 | * 53.最大子序和 8 | *

9 | * 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 10 | *

11 | * 示例: 12 | *

13 | * 输入: [-2,1,-3,4,-1,2,1,-5,4], 14 | * 输出: 6 15 | * 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 16 | * 进阶: 17 | *

18 | * 如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 19 | * 20 | * @see maximum-subarray 21 | */ 22 | public class _53_maxSubArray { 23 | public static void main(String[] args) { 24 | int i = maxSubArray(new int[]{-2, 1, -3, 4, -1, 2, 1, -5, 4}); 25 | System.out.println(i); 26 | int i1 = maxSubArray(new int[]{-2, 1}); 27 | System.out.println(i1); 28 | Util.printDivideLine(); 29 | //更优解法 30 | int i2 = maxSubArray2(new int[]{-2, 1, -3, 4, -1, 2, 1, -5, 4}); 31 | System.out.println(i2); 32 | } 33 | 34 | public static int maxSubArray(int[] nums) { 35 | if (nums == null || nums.length == 0) { 36 | return 0; 37 | } 38 | int[] dp = new int[nums.length]; 39 | int[] dp2 = new int[nums.length]; 40 | dp[0] = nums[0]; 41 | dp2[0] = nums[0]; 42 | for (int i = 1; i < nums.length; i++) { 43 | dp[i] = Math.max(Math.max(dp2[i - 1] + nums[i], dp[i - 1]), nums[i]); 44 | dp2[i] = Math.max(dp2[i - 1] + nums[i], nums[i]); 45 | } 46 | return dp[nums.length - 1]; 47 | } 48 | 49 | /** 50 | * 时间复杂度一样,空间复杂度O(1) 51 | * @param nums 52 | * @return 53 | */ 54 | public static int maxSubArray2(int[] nums) { 55 | 56 | int sum = Integer.MIN_VALUE;; 57 | 58 | int total_sum = 0; 59 | int i = 0; 60 | while(i < nums.length){ 61 | total_sum += nums[i]; 62 | sum = Math.max(sum, total_sum); 63 | if(total_sum < 0){ 64 | total_sum = 0 ; 65 | } 66 | 67 | i++; 68 | } 69 | 70 | return sum; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_543_diameterOfBinaryTree.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import javafx.util.Pair; 4 | import pp.arithmetic.model.TreeNode; 5 | 6 | /** 7 | * Created by wangpeng on 2019-09-03. 8 | * 543. 二叉树的直径 9 | * 10 | * 给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过根结点。 11 | * 12 | * 示例 : 13 | * 给定二叉树 14 | * 15 | * 1 16 | * / \ 17 | * 2 3 18 | * / \ 19 | * 4 5 20 | * 返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。 21 | * 22 | * 注意:两结点之间的路径长度是以它们之间边的数目表示。 23 | * 24 | * 来源:力扣(LeetCode) 25 | * 链接:https://leetcode-cn.com/problems/diameter-of-binary-tree 26 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 27 | */ 28 | public class _543_diameterOfBinaryTree { 29 | 30 | public static void main(String[] args) { 31 | _543_diameterOfBinaryTree diameterOfBinaryTree = new _543_diameterOfBinaryTree(); 32 | TreeNode root = new TreeNode(1); 33 | root.left = new TreeNode(2); 34 | root.right = new TreeNode(3); 35 | root.left.left = new TreeNode(4); 36 | root.left.right = new TreeNode(5); 37 | 38 | System.out.println(diameterOfBinaryTree.diameterOfBinaryTree(root)); 39 | 40 | } 41 | 42 | private int ret = 0; 43 | 44 | /** 45 | * 解题思路: 46 | * 对于树的问题,正常思路就是遍历,此题也不例外 47 | * 如题所示,找到最长的路径,有两种可能: 48 | * 一、根节点+左右子树节点 49 | * 二、根节点+最长的子树节点作为其父节点的子节点 50 | * 递归遍历过程中,用一个全局变量保存遍历过程中的最大值 51 | * 52 | * @param root 53 | * @return 54 | */ 55 | public int diameterOfBinaryTree(TreeNode root) { 56 | dfs(root); 57 | return ret; 58 | } 59 | 60 | private int dfs(TreeNode root) { 61 | if (root == null) return 0; 62 | int left = dfs(root.left); 63 | int right = dfs(root.right); 64 | int count = left + right; 65 | ret = Math.max(ret, count); 66 | return Math.max(left, right) + 1; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_547_findCircleNum.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/9/29. 5 | * 547.朋友圈 6 | *

7 | * 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。 8 | *

9 | * 给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 10 | *

11 | * 示例 1: 12 | *

13 | * 输入: 14 | * [[1,1,0], 15 | * [1,1,0], 16 | * [0,0,1]] 17 | * 输出: 2 18 | * 说明:已知学生0和学生1互为朋友,他们在一个朋友圈。 19 | * 第2个学生自己在一个朋友圈。所以返回2。 20 | * 示例 2: 21 | *

22 | * 输入: 23 | * [[1,1,0], 24 | * [1,1,1], 25 | * [0,1,1]] 26 | * 输出: 1 27 | * 说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。 28 | * 注意: 29 | *

30 | * N 在[1,200]的范围内。 31 | * 对于所有学生,有M[i][i] = 1。 32 | * 如果有M[i][j] = 1,则有M[j][i] = 1。 33 | * 34 | * @see friend-circles 35 | */ 36 | public class _547_findCircleNum { 37 | 38 | public static void main(String[] args) { 39 | int circleNum = findCircleNum(new int[][]{ 40 | {1, 1, 0}, 41 | {1, 1, 0}, 42 | {0, 0, 1} 43 | }); 44 | System.out.println(circleNum); 45 | int circleNum2 = findCircleNum(new int[][]{ 46 | {1, 0, 0}, {0, 1, 0}, {0, 0, 1} 47 | }); 48 | System.out.println(circleNum2); 49 | } 50 | 51 | /** 52 | * 图的深度遍历 53 | * 54 | * @param M 55 | * @return 56 | */ 57 | public static int findCircleNum(int[][] M) { 58 | if (M.length == 0) { 59 | return 0; 60 | } 61 | int[] visit = new int[M.length]; 62 | int count = 0; 63 | for (int i = 0; i < M.length; i++) { 64 | if (visit[i] == 0) { 65 | dfs(i, M, visit); 66 | count++; 67 | } 68 | } 69 | return count; 70 | } 71 | 72 | private static void dfs(int index, int[][] M, int[] visit) { 73 | visit[index] = 1; 74 | int[] items = M[index]; 75 | for (int i = 0; i < items.length; i++) { 76 | if (visit[i] == 0 && M[index][i] == 1) { 77 | dfs(i, M, visit); 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_547_findCircleNum_2.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.model.DisjointSet; 4 | 5 | /** 6 | * Created by wangpeng on 2018/9/29. 7 | * 547.朋友圈 8 | *

9 | * 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。 10 | *

11 | * 给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 12 | *

13 | * 示例 1: 14 | *

15 | * 输入: 16 | * [[1,1,0], 17 | * [1,1,0], 18 | * [0,0,1]] 19 | * 输出: 2 20 | * 说明:已知学生0和学生1互为朋友,他们在一个朋友圈。 21 | * 第2个学生自己在一个朋友圈。所以返回2。 22 | * 示例 2: 23 | *

24 | * 输入: 25 | * [[1,1,0], 26 | * [1,1,1], 27 | * [0,1,1]] 28 | * 输出: 1 29 | * 说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。 30 | * 注意: 31 | *

32 | * N 在[1,200]的范围内。 33 | * 对于所有学生,有M[i][i] = 1。 34 | * 如果有M[i][j] = 1,则有M[j][i] = 1。 35 | * 36 | * @see friend-circles 37 | */ 38 | public class _547_findCircleNum_2 { 39 | 40 | public static void main(String[] args) { 41 | int circleNum = findCircleNum(new int[][]{ 42 | {1, 1, 0}, 43 | {1, 1, 0}, 44 | {0, 0, 1} 45 | }); 46 | System.out.println(circleNum); 47 | int circleNum2 = findCircleNum(new int[][]{ 48 | {1, 1, 0, 0, 0, 0, 0, 0}, 49 | {1, 1, 1, 0, 0, 0, 0, 0}, 50 | {0, 1, 1, 1, 0, 0, 0, 0}, 51 | {1, 0, 1, 1, 1, 0, 0, 0}, 52 | {1, 0, 0, 1, 1, 1, 0, 0}, 53 | {1, 0, 0, 0, 1, 1, 1, 0}, 54 | {1, 0, 0, 0, 0, 1, 1, 1}, 55 | {0, 0, 0, 0, 0, 0, 1, 1} 56 | }); 57 | System.out.println(circleNum2); 58 | } 59 | 60 | /** 61 | * 并查集--森林实现 62 | * 63 | * @param M 64 | * @return 65 | */ 66 | public static int findCircleNum(int[][] M) { 67 | DisjointSet disjointSet = new DisjointSet(M.length); 68 | for (int i = 0; i < M.length; i++) { 69 | for (int j = i + 1; j < M.length; j++) { 70 | if (M[i][j] == 1) { 71 | disjointSet.union(i, j); 72 | } 73 | } 74 | } 75 | return disjointSet.count(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_55_canJump.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/9/6. 5 | * 55. 跳跃游戏 6 | *

7 | * 给定一个非负整数数组,你最初位于数组的第一个位置。 8 | *

9 | * 数组中的每个元素代表你在该位置可以跳跃的最大长度。 10 | *

11 | * 判断你是否能够到达最后一个位置。 12 | *

13 | * 示例 1: 14 | *

15 | * 输入: [2,3,1,1,4] 16 | * 输出: true 17 | * 解释: 从位置 0 到 1 跳 1 步, 然后跳 3 步到达最后一个位置。 18 | * 示例 2: 19 | *

20 | * 输入: [3,2,1,0,4] 21 | * 输出: false 22 | * 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 23 | * 24 | * @see jump-game 25 | */ 26 | public class _55_canJump { 27 | 28 | public static void main(String[] args) { 29 | boolean b1 = canJump(new int[]{2, 3, 1, 1, 4}); 30 | System.out.println(b1); 31 | boolean b2 = canJump(new int[]{3, 2, 1, 0, 4}); 32 | System.out.println(b2); 33 | boolean b3 = canJump(new int[]{2, 0, 0}); 34 | System.out.println(b3); 35 | boolean b4 = canJump(new int[]{0}); 36 | System.out.println(b4); 37 | } 38 | 39 | /** 40 | * 贪心算法:每一步都跳的更远(index+num[i]最大),就更有机会跳到最后 41 | * 42 | * @param nums 43 | * @return 44 | */ 45 | public static boolean canJump(int[] nums) { 46 | int[] index = new int[nums.length]; 47 | for (int i = 0; i < nums.length; i++) { 48 | index[i] = i + nums[i]; 49 | } 50 | int jump = 0; 51 | int maxIndex = index[0]; 52 | while (jump < nums.length && jump <= maxIndex) { 53 | if (index[jump] > maxIndex) { 54 | maxIndex = index[jump]; 55 | } 56 | jump++; 57 | } 58 | if (jump == nums.length) { 59 | return true; 60 | } 61 | return false; 62 | } 63 | 64 | /** 65 | * 官方解答,更优,不需要额外的存储空间,循环也少一半 66 | * 67 | * @param nums 68 | * @return 69 | */ 70 | public static boolean canJumpOther(int[] nums) { 71 | int lastPos = nums.length - 1; 72 | for (int i = nums.length - 1; i >= 0; i--) { 73 | if (i + nums[i] >= lastPos) { 74 | lastPos = i; 75 | } 76 | } 77 | return lastPos == 0; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_563_findTilt.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import javafx.util.Pair; 4 | import pp.arithmetic.Util; 5 | import pp.arithmetic.model.TreeNode; 6 | 7 | /** 8 | * Created by wangpeng on 2018/10/31. 9 | * 563. 二叉树的坡度 10 | *

11 | * 给定一个二叉树,计算整个树的坡度。 12 | *

13 | * 一个树的节点的坡度定义即为,该节点左子树的结点之和和右子树结点之和的差的绝对值。空结点的的坡度是0。 14 | *

15 | * 整个树的坡度就是其所有节点的坡度之和。 16 | *

17 | * 示例: 18 | *

19 | * 输入: 20 | * 1 21 | * / \ 22 | * 2 3 23 | * 输出: 1 24 | * 解释: 25 | * 结点的坡度 2 : 0 26 | * 结点的坡度 3 : 0 27 | * 结点的坡度 1 : |2-3| = 1 28 | * 树的坡度 : 0 + 0 + 1 = 1 29 | * 注意: 30 | *

31 | * 任何子树的结点的和不会超过32位整数的范围。 32 | * 坡度的值不会超过32位整数的范围 33 | * 34 | * @see binary-tree-tilt 35 | */ 36 | public class _563_findTilt { 37 | public static void main(String[] args) { 38 | TreeNode treeNode = new TreeNode(1); 39 | TreeNode treeNode1 = new TreeNode(2); 40 | TreeNode treeNode2 = new TreeNode(3); 41 | treeNode1.left = new TreeNode(4); 42 | treeNode2.right = new TreeNode(5); 43 | treeNode.left = treeNode1; 44 | treeNode.right = treeNode2; 45 | Util.printTree(treeNode); 46 | int tilt = findTilt(treeNode); 47 | System.out.println(tilt); 48 | } 49 | 50 | public static int findTilt(TreeNode root) { 51 | Pair generate = generate(root); 52 | return generate.getKey(); 53 | } 54 | 55 | private static Pair generate(TreeNode root) { 56 | if (root == null) { 57 | return new Pair<>(0, 0); 58 | } 59 | if (root.left == null && root.right == null) { 60 | return new Pair<>(0, root.val); 61 | } 62 | Pair left = generate(root.left); 63 | Pair right = generate(root.right); 64 | int tilt = left.getKey() + right.getKey() + Math.abs(left.getValue() - right.getValue()); 65 | return new Pair<>(tilt, root.val + left.getValue() + right.getValue()); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_567_checkInclusion.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-01-29. 5 | * 567. 字符串的排列 6 | *

7 | * 给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。 8 | *

9 | * 换句话说,第一个字符串的排列之一是第二个字符串的子串。 10 | *

11 | * 示例1: 12 | *

13 | * 输入: s1 = "ab" s2 = "eidbaooo" 14 | * 输出: True 15 | * 解释: s2 包含 s1 的排列之一 ("ba"). 16 | *

17 | *

18 | * 示例2: 19 | *

20 | * 输入: s1= "ab" s2 = "eidboaoo" 21 | * 输出: False 22 | *

23 | *

24 | * 注意: 25 | *

26 | * 1.输入的字符串只包含小写字母 27 | * 2.两个字符串的长度都在 [1, 10,000] 之间 28 | * 29 | * @see permutation-in-string 30 | */ 31 | public class _567_checkInclusion { 32 | 33 | public static void main(String[] args) { 34 | 35 | System.out.println(checkInclusion("ab", "eidbaooo")); 36 | System.out.println(checkInclusion("ab", "eidboaoo")); 37 | } 38 | 39 | /** 40 | * 方法1:最简单最暴力的方法其实就是找到s1的所有全排列,然后在s2中查找是否这些全排列字符串在s2中。但是这种方法耗时太大,会导致超时。 41 | *

42 | * 方法2:滑动窗口 43 | * 其实不需要找到s1的全排列,因为我们只需要考虑s2中是否包含s1中同样个数的字符,并且这些字符是连在一起的就行了。 44 | * 因此,我们可以使用一个滑动窗口,在s2上滑动。在这个滑动窗口中的字符及其个数是否刚好等于s1中的字符及其个数, 45 | * 此外滑动窗口保证了这些字符是连在一起的。 46 | * 47 | * @param s1 48 | * @param s2 49 | * @return 50 | */ 51 | public static boolean checkInclusion(String s1, String s2) { 52 | if (s1.length() > s2.length()) { 53 | return false; 54 | } 55 | int[] diff = new int[26]; 56 | for (int i = 0; i < s1.length(); i++) { 57 | diff[s1.charAt(i) - 'a']++; 58 | diff[s2.charAt(i) - 'a']--; 59 | } 60 | for (int i = s1.length(); i < s2.length(); i++) { 61 | if (isSame(diff)) { 62 | return true; 63 | } 64 | diff[s2.charAt(i - s1.length()) - 'a']++; 65 | diff[s2.charAt(i) - 'a']--; 66 | } 67 | return isSame(diff); 68 | } 69 | 70 | private static boolean isSame(int[] diff) { 71 | for (int i = 0; i < diff.length; i++) { 72 | if (diff[i] != 0) { 73 | return false; 74 | } 75 | } 76 | return true; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_581_findUnsortedSubarray.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * Created by wangpeng on 2019-09-12. 7 | * 581. 最短无序连续子数组 8 | *

9 | * 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。 10 | *

11 | * 你找到的子数组应是最短的,请输出它的长度。 12 | *

13 | * 示例 1: 14 | *

15 | * 输入: [2, 6, 4, 8, 10, 9, 15] 16 | * 输出: 5 17 | * 解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。 18 | * 说明 : 19 | *

20 | * 输入的数组长度范围在 [1, 10,000]。 21 | * 输入的数组可能包含重复元素 ,所以升序的意思是<=。 22 | *

23 | * 来源:力扣(LeetCode) 24 | * 链接:https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray 25 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 26 | */ 27 | public class _581_findUnsortedSubarray { 28 | 29 | public static void main(String[] args) { 30 | _581_findUnsortedSubarray findUnsortedSubarray = new _581_findUnsortedSubarray(); 31 | System.out.println(findUnsortedSubarray.findUnsortedSubarray(new int[]{2, 6, 4, 8, 10, 9, 15})); 32 | System.out.println(findUnsortedSubarray.findUnsortedSubarray(new int[]{8, 6, 4, 8, 10, 9, 15})); 33 | System.out.println(findUnsortedSubarray.findUnsortedSubarray(new int[]{2, 3, 3, 2, 4})); 34 | System.out.println(findUnsortedSubarray.findUnsortedSubarray(new int[]{1, 3, 2, 2, 2})); 35 | System.out.println(findUnsortedSubarray.findUnsortedSubarray(new int[]{1, 1})); 36 | System.out.println(findUnsortedSubarray.findUnsortedSubarray(new int[]{1, 2, 4, 5, 3})); 37 | } 38 | 39 | /** 40 | * 解题思路: 41 | * 核心是我们需要找到无序子数组中最小元素和最大元素分别对应的正确位置 42 | * 43 | * @param nums 44 | * @return 45 | */ 46 | public int findUnsortedSubarray(int[] nums) { 47 | Stack stack = new Stack<>(); 48 | int l = nums.length, r = 0; 49 | for (int i = 0; i < nums.length; i++) { 50 | while (!stack.isEmpty() && nums[stack.peek()] > nums[i]) 51 | l = Math.min(l, stack.pop()); 52 | stack.push(i); 53 | } 54 | stack.clear(); 55 | for (int i = nums.length - 1; i >= 0; i--) { 56 | while (!stack.isEmpty() && nums[stack.peek()] < nums[i]) 57 | r = Math.max(r, stack.pop()); 58 | stack.push(i); 59 | } 60 | return r - l > 0 ? r - l + 1 : 0; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_58_lengthOfLastWord.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-07-02. 5 | * 58. 最后一个单词的长度 6 | *

7 | * 给定一个仅包含大小写字母和空格 ' ' 的字符串,返回其最后一个单词的长度。 8 | *

9 | * 如果不存在最后一个单词,请返回 0 。 10 | *

11 | * 说明:一个单词是指由字母组成,但不包含任何空格的字符串。 12 | *

13 | * 示例: 14 | *

15 | * 输入: "Hello World" 16 | * 输出: 5 17 | *

18 | *

19 | * 来源:力扣(LeetCode) 20 | * 链接:https://leetcode-cn.com/problems/length-of-last-word 21 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 22 | */ 23 | public class _58_lengthOfLastWord { 24 | 25 | public static void main(String[] args) { 26 | _58_lengthOfLastWord length = new _58_lengthOfLastWord(); 27 | System.out.println(length.lengthOfLastWord("Hello World")); 28 | System.out.println(length.lengthOfLastWord(" s ")); 29 | System.out.println(length.lengthOfLastWord(" Hell ")); 30 | } 31 | 32 | /** 33 | * 解题思路: 34 | * 从s的最后一个开始遍历,遇到首个非空的字母开始计数到下一个为空的时候停止 35 | * 36 | * @param s 37 | * @return 38 | */ 39 | public int lengthOfLastWord(String s) { 40 | int startIndex = -1, endIndex = -1; 41 | for (int i = s.length() - 1; i >= 0; i--) { 42 | if (startIndex != -1 && s.charAt(i) == ' ') { 43 | endIndex = i; 44 | break; 45 | } 46 | if (startIndex == -1 && s.charAt(i) != ' ') { 47 | startIndex = i; 48 | } 49 | } 50 | if (startIndex == -1) { 51 | return 0; 52 | } 53 | return startIndex - endIndex; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_59_generateMatrix.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | /** 6 | * Created by wangpeng on 2019-07-02. 7 | * 59. 螺旋矩阵 II 8 | *

9 | * 给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。 10 | *

11 | * 示例: 12 | *

13 | * 输入: 3 14 | * 输出: 15 | * [ 16 | * [ 1, 2, 3 ], 17 | * [ 8, 9, 4 ], 18 | * [ 7, 6, 5 ] 19 | * ] 20 | *

21 | * 来源:力扣(LeetCode) 22 | * 链接:https://leetcode-cn.com/problems/spiral-matrix-ii 23 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 24 | */ 25 | public class _59_generateMatrix { 26 | public static void main(String[] args) { 27 | _59_generateMatrix generateMatrix = new _59_generateMatrix(); 28 | int[][] ints = generateMatrix.generateMatrix(3); 29 | for (int i = 0; i < ints.length; i++) { 30 | Util.printArray(ints[i]); 31 | } 32 | } 33 | 34 | /** 35 | * 解题思路: 36 | * 通过四个变量(2个行0~n、2个列0~n),一圈一圈的遍历,每一圈遍历的时候做四个方向的遍历 37 | * 38 | * @param n 39 | * @return 40 | */ 41 | public int[][] generateMatrix(int n) { 42 | int[][] matrix = new int[n][n]; 43 | int r1 = 0, r2 = matrix.length - 1; 44 | int c1 = 0, c2 = matrix[0].length - 1; 45 | int index = 1; 46 | while (r1 <= r2 && c1 <= c2) { 47 | for (int c = c1; c <= c2; c++) matrix[r1][c] = index++; 48 | for (int r = r1 + 1; r <= r2; r++) matrix[r][c2] = index++; 49 | if (r1 < r2 && c1 < c2) { 50 | for (int c = c2 - 1; c > c1; c--) matrix[r2][c] = index++; 51 | for (int r = r2; r > r1; r--) matrix[r][c1] = index++; 52 | } 53 | r1++; 54 | r2--; 55 | c1++; 56 | c2--; 57 | } 58 | return matrix; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_61_RotateRight.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.ListNode; 5 | 6 | /** 7 | * Created by wangpeng on 2018/8/22. 8 | * 61. 旋转链表 9 | * 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。 10 | * 示例 1: 11 | * 输入: 1->2->3->4->5->NULL, k = 2 12 | * 输出: 4->5->1->2->3->NULL 13 | * 解释: 14 | * 向右旋转 1 步: 5->1->2->3->4->NULL 15 | * 向右旋转 2 步: 4->5->1->2->3->NULL 16 | * 示例 2: 17 | *

18 | * 输入: 0->1->2->NULL, k = 4 19 | * 输出: 2->0->1->NULL 20 | * 解释: 21 | * 向右旋转 1 步: 2->0->1->NULL 22 | * 向右旋转 2 步: 1->2->0->NULL 23 | * 向右旋转 3 步: 0->1->2->NULL 24 | * 向右旋转 4 步: 2->0->1->NULL 25 | * 26 | * @see rotate-list 27 | */ 28 | public class _61_RotateRight { 29 | 30 | public static void main(String[] args) { 31 | ListNode node = Util.generateListNodeBySize(1); 32 | Util.printListNode(node); 33 | ListNode rotateRight = rotateRight(node, 4); 34 | Util.printListNode(rotateRight); 35 | } 36 | 37 | public static ListNode rotateRight(ListNode head, int k) { 38 | if (head == null) return null; 39 | //先形成一个环 40 | ListNode next = head; 41 | int length = 1; 42 | while (next != null && next.next != null) { 43 | next = next.next; 44 | length++; 45 | } 46 | next.next = head; 47 | next = head; 48 | int step = length - k % length - 1; 49 | while (step > 0) { 50 | next = next.next; 51 | step--; 52 | } 53 | ListNode kNode = next.next; 54 | next.next = null; 55 | return kNode; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_62_uniquePaths.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/11/13. 5 | * 62. 不同路径 6 | *

7 | * 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 8 | *

9 | * 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 10 | *

11 | * 问总共有多少条不同的路径? 12 | *

13 | *

14 | *

15 | * 例如,上图是一个7 x 3 的网格。有多少可能的路径? 16 | *

17 | * 说明:m 和 n 的值均不超过 100。 18 | *

19 | * 示例 1: 20 | *

21 | * 输入: m = 3, n = 2 22 | * 输出: 3 23 | * 解释: 24 | * 从左上角开始,总共有 3 条路径可以到达右下角。 25 | * 1. 向右 -> 向右 -> 向下 26 | * 2. 向右 -> 向下 -> 向右 27 | * 3. 向下 -> 向右 -> 向右 28 | * 示例 2: 29 | *

30 | * 输入: m = 7, n = 3 31 | * 输出: 28 32 | * 33 | * @see unique-paths 34 | */ 35 | public class _62_uniquePaths { 36 | public static void main(String[] args) { 37 | System.out.println(uniquePaths(3, 2)); 38 | System.out.println(uniquePaths(7, 3)); 39 | } 40 | 41 | public static int uniquePaths(int m, int n) { 42 | if (m <= 1 || n <= 1) { 43 | return 1; 44 | } 45 | int[][] dp = new int[m][n]; 46 | //初始化 47 | for (int i = 0; i < n; i++) { 48 | dp[0][i] = 1; 49 | } 50 | for (int i = 0; i < m; i++) { 51 | dp[i][0] = 1; 52 | } 53 | //动态规划 54 | for (int i = 1; i < m; i++) { 55 | for (int j = 1; j < n; j++) { 56 | dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; 57 | } 58 | } 59 | 60 | return dp[m - 1][n - 1]; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_63_uniquePathsWithObstacles.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/11/13. 5 | * 63. 不同路径 II 6 | *

7 | * 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 8 | *

9 | * 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 10 | *

11 | * 现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径? 12 | *

13 | *

14 | *

15 | * 网格中的障碍物和空位置分别用 1 和 0 来表示。 16 | *

17 | * 说明:m 和 n 的值均不超过 100。 18 | *

19 | * 示例 1: 20 | *

21 | * 输入: 22 | * [ 23 | * [0,0,0], 24 | * [0,1,0], 25 | * [0,0,0] 26 | * ] 27 | * 输出: 2 28 | * 解释: 29 | * 3x3 网格的正中间有一个障碍物。 30 | * 从左上角到右下角一共有 2 条不同的路径: 31 | * 1. 向右 -> 向右 -> 向下 -> 向下 32 | * 2. 向下 -> 向下 -> 向右 -> 向右 33 | * 34 | * @see unique-paths-ii 35 | */ 36 | public class _63_uniquePathsWithObstacles { 37 | public static void main(String[] args) { 38 | System.out.println(uniquePathsWithObstacles(new int[][]{ 39 | {0,0,0,0,0}, 40 | {0,0,0,0,1}, 41 | {0,0,0,1,0}, 42 | {0,0,0,0,0} 43 | })); 44 | } 45 | 46 | public static int uniquePathsWithObstacles(int[][] obstacleGrid) { 47 | if (obstacleGrid.length == 0) { 48 | return 0; 49 | } 50 | int[][] dp = new int[obstacleGrid.length][obstacleGrid[0].length]; 51 | for (int i = 0; i < obstacleGrid.length; i++) { 52 | for (int j = 0; j < obstacleGrid[i].length; j++) { 53 | if (obstacleGrid[i][j] == 1) { 54 | if (i == 0 && j == 0) { 55 | return 0; 56 | } 57 | dp[i][j] = 0; 58 | } else { 59 | if (i == 0 && j == 0) { 60 | dp[i][j] = 1; 61 | } else if (i == 0) { 62 | dp[i][j] = dp[i][j - 1]; 63 | } else if (j == 0) { 64 | dp[i][j] = dp[i - 1][j]; 65 | } else { 66 | dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; 67 | } 68 | } 69 | } 70 | 71 | } 72 | return dp[obstacleGrid.length - 1][obstacleGrid[0].length - 1]; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_64_minPathSum.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/9/25. 5 | * 64. 最小路径和 6 | *

7 | * 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 8 | *

9 | * 说明:每次只能向下或者向右移动一步。 10 | *

11 | * 示例: 12 | *

13 | * 输入: 14 | * [ 15 | * [1,3,1], 16 | * [1,5,1], 17 | * [4,2,1] 18 | * ] 19 | * 输出: 7 20 | * 解释: 因为路径 1→3→1→1→1 的总和最小。 21 | * 22 | * @see minimum-path-sum 23 | */ 24 | public class _64_minPathSum { 25 | public static void main(String[] args) { 26 | int i = minPathSum(new int[][]{ 27 | {1, 3, 1}, 28 | {1, 5, 1} 29 | }); 30 | System.out.println(i); 31 | } 32 | 33 | public static int minPathSum(int[][] grid) { 34 | if (grid == null || grid.length == 0) { 35 | return 0; 36 | } 37 | int[][] dp = new int[grid.length][grid[0].length]; 38 | dp[0][0] = grid[0][0]; 39 | for (int i = 1; i < grid[0].length; i++) { 40 | dp[0][i] = dp[0][i - 1] + grid[0][i]; 41 | } 42 | for (int i = 1; i < grid.length; i++) { 43 | dp[i][0] = dp[i - 1][0] + grid[i][0]; 44 | for (int j = 1; j < grid[i].length; j++) { 45 | dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]; 46 | } 47 | } 48 | return dp[grid.length - 1][grid[0].length - 1]; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_653_findTarget.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.model.TreeNode; 4 | 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | 8 | /** 9 | * Created by wangpeng on 2019-03-21. 10 | * 653. 两数之和 IV - 输入 BST 11 | *

12 | * 给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。 13 | *

14 | * 案例 1: 15 | *

16 | * 输入: 17 | * 5 18 | * / \ 19 | * 3 6 20 | * / \ \ 21 | * 2 4 7 22 | *

23 | * Target = 9 24 | *

25 | * 输出: True 26 | *

27 | *

28 | * 案例 2: 29 | *

30 | * 输入: 31 | * 5 32 | * / \ 33 | * 3 6 34 | * / \ \ 35 | * 2 4 7 36 | *

37 | * Target = 28 38 | *

39 | * 输出: False 40 | * 41 | * @see two-sum-iv-input-is-a-bst 42 | */ 43 | public class _653_findTarget { 44 | 45 | public static void main(String[] args) { 46 | TreeNode root = new TreeNode(5); 47 | root.left = new TreeNode(3); 48 | root.left.left = new TreeNode(2); 49 | root.left.right = new TreeNode(4); 50 | root.right = new TreeNode(6); 51 | root.right.right = new TreeNode(7); 52 | _653_findTarget findTarget = new _653_findTarget(); 53 | System.out.println(findTarget.findTarget(root, 9)); 54 | System.out.println(findTarget.findTarget(root, 28)); 55 | } 56 | 57 | private Set set = new HashSet<>(); 58 | 59 | public boolean findTarget(TreeNode root, int k) { 60 | if (root == null) return false; 61 | if (set.contains(k - root.val)) return true; 62 | set.add(root.val); 63 | return findTarget(root.left, k) || findTarget(root.right, k); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_66_plusOne.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by wangpeng on 2019-10-19. 10 | * 66. 加一 11 | *

12 | * 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 13 | *

14 | * 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 15 | *

16 | * 你可以假设除了整数 0 之外,这个整数不会以零开头。 17 | *

18 | * 示例 1: 19 | *

20 | * 输入: [1,2,3] 21 | * 输出: [1,2,4] 22 | * 解释: 输入数组表示数字 123。 23 | * 示例 2: 24 | *

25 | * 输入: [4,3,2,1] 26 | * 输出: [4,3,2,2] 27 | * 解释: 输入数组表示数字 4321。 28 | *

29 | * 来源:力扣(LeetCode) 30 | * 链接:https://leetcode-cn.com/problems/plus-one 31 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 32 | */ 33 | public class _66_plusOne { 34 | 35 | public static void main(String[] args) { 36 | _66_plusOne plusOne = new _66_plusOne(); 37 | Util.printArray(plusOne.plusOne(new int[]{1, 2, 3})); 38 | Util.printArray(plusOne.plusOne(new int[]{4, 3, 2, 1})); 39 | Util.printArray(plusOne.plusOne(new int[]{9, 9, 9})); 40 | Util.printArray(plusOne.plusOne(new int[]{0})); 41 | Util.printArray(plusOne.plusOne(new int[]{9})); 42 | } 43 | 44 | /** 45 | * 解题思路: 46 | * 一道算数加法+1,需要注意两种情况: 47 | * 1、低位向高位进位 ==> 从末尾开始遍历 48 | * 2、整数头需要进位 ==> 构建一个新数组保存返回结果 49 | * 50 | * @param digits 51 | * @return 52 | */ 53 | public int[] plusOne(int[] digits) { 54 | List retList = new ArrayList<>(); 55 | int highAdd = 1; //进位 56 | for (int i = digits.length - 1; i >= 0; i--) { 57 | int newDigit = digits[i] + highAdd; 58 | highAdd = newDigit / 10; 59 | newDigit = newDigit % 10; 60 | retList.add(0, newDigit); 61 | } 62 | if (highAdd > 0) retList.add(0, highAdd); 63 | //listToArr 64 | int[] retArr = new int[retList.size()]; 65 | for (int i = 0; i < retList.size(); i++) { 66 | retArr[i] = retList.get(i); 67 | } 68 | 69 | return retArr; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_674_findLengthOfLCIS_e.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-02-23. 5 | * 674. 最长连续递增序列 6 | *

7 | * 给定一个未经排序的整数数组,找到最长且连续的的递增序列。 8 | *

9 | * 示例 1: 10 | *

11 | * 输入: [1,3,5,4,7] 12 | * 输出: 3 13 | * 解释: 最长连续递增序列是 [1,3,5], 长度为3。 14 | * 尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为5和7在原数组里被4隔开。 15 | * 示例 2: 16 | *

17 | * 输入: [2,2,2,2,2] 18 | * 输出: 1 19 | * 解释: 最长连续递增序列是 [2], 长度为1。 20 | * 注意:数组长度不会超过10000。 21 | * 22 | * @see longest-continuous-increasing-subsequence 23 | */ 24 | public class _674_findLengthOfLCIS_e { 25 | public static void main(String[] args) { 26 | System.out.println(findLengthOfLCIS(new int[]{1, 3, 5, 4, 7})); 27 | System.out.println(findLengthOfLCIS(new int[]{2, 2, 2, 2, 2})); 28 | } 29 | 30 | private static int findLengthOfLCIS(int[] nums) { 31 | if (nums.length < 1) return 0; 32 | int max = 1; 33 | int cur = 1; 34 | for (int i = 1; i < nums.length; i++) { 35 | if (nums[i] > nums[i - 1]) { 36 | cur++; 37 | max = Math.max(max, cur); 38 | } else { 39 | cur = 1; 40 | } 41 | } 42 | 43 | return max; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_67_addBinary.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-10-21. 5 | * 67. 二进制求和 6 | *

7 | * 给定两个二进制字符串,返回他们的和(用二进制表示)。 8 | *

9 | * 输入为非空字符串且只包含数字 1 和 0。 10 | *

11 | * 示例 1: 12 | *

13 | * 输入: a = "11", b = "1" 14 | * 输出: "100" 15 | * 示例 2: 16 | *

17 | * 输入: a = "1010", b = "1011" 18 | * 输出: "10101" 19 | *

20 | * 来源:力扣(LeetCode) 21 | * 链接:https://leetcode-cn.com/problems/add-binary 22 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 23 | */ 24 | public class _67_addBinary { 25 | 26 | public static void main(String[] args) { 27 | _67_addBinary addBinary = new _67_addBinary(); 28 | System.out.println(addBinary.addBinary("11", "1")); 29 | System.out.println(addBinary.addBinary("1010", "1011")); 30 | System.out.println(addBinary.addBinary("1111", "1111")); 31 | } 32 | 33 | /** 34 | * 解题思路: 35 | * 从低位开始累加,注意两边字符串不一致,提高执行效率不要使用StringBuilder 36 | * 37 | * 执行用时 :1 ms, 在所有 java 提交中击败了100.00%的用户 38 | * 内存消耗 :36 MB, 在所有 java 提交中击败了55.45%的用户 39 | * 40 | * @param a 41 | * @param b 42 | * @return 43 | */ 44 | public String addBinary(String a, String b) { 45 | int i = a.length() - 1; 46 | int j = b.length() - 1; 47 | int carry = 0; 48 | char[] result = new char[Math.max(i, j) + 1]; 49 | int pos = result.length - 1; 50 | while (i >= 0 || j >= 0) { 51 | int sum = carry; 52 | if (i >= 0) { 53 | sum += a.charAt(i--) - '0'; 54 | } 55 | if (j >= 0) { 56 | sum += b.charAt(j--) - '0'; 57 | } 58 | //>>1 代表 /2,进位 59 | carry = sum >> 1; 60 | //sum & 0x01 ==> 进位后只取低位 61 | result[pos--] = (char) ((sum & 0x01) + '0'); 62 | } 63 | if (carry > 0) { //最后有进位,直接进行数据拼接,防止数组越界 64 | return "1" + String.valueOf(result); 65 | } 66 | return String.valueOf(result); 67 | } 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_69_mySqrt.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-03-15. 5 | * 69. x 的平方根 6 | *

7 | * 实现 int sqrt(int x) 函数。 8 | *

9 | * 计算并返回 x 的平方根,其中 x 是非负整数。 10 | *

11 | * 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 12 | *

13 | * 示例 1: 14 | *

15 | * 输入: 4 16 | * 输出: 2 17 | * 示例 2: 18 | *

19 | * 输入: 8 20 | * 输出: 2 21 | * 说明: 8 的平方根是 2.82842..., 22 | * 由于返回类型是整数,小数部分将被舍去。 23 | * 24 | * @see sqrtx 25 | */ 26 | public class _69_mySqrt { 27 | public static void main(String[] args) { 28 | _69_mySqrt mySqrt = new _69_mySqrt(); 29 | System.out.println(mySqrt.mySqrt(8)); 30 | } 31 | 32 | public int mySqrt(int x) { 33 | double sqrt = Math.sqrt(x); 34 | return (int) sqrt; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_70_climbStairs.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/9/21. 5 | * 70.爬楼梯 6 | * 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 7 | *

8 | * 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 9 | *

10 | * 注意:给定 n 是一个正整数。 11 | *

12 | * 示例 1: 13 | *

14 | * 输入: 2 15 | * 输出: 2 16 | * 解释: 有两种方法可以爬到楼顶。 17 | * 1. 1 阶 + 1 阶 18 | * 2. 2 阶 19 | * 示例 2: 20 | *

21 | * 输入: 3 22 | * 输出: 3 23 | * 解释: 有三种方法可以爬到楼顶。 24 | * 1. 1 阶 + 1 阶 + 1 阶 25 | * 2. 1 阶 + 2 阶 26 | * 3. 2 阶 + 1 阶 27 | * 28 | * @see climbing-stairs 29 | */ 30 | public class _70_climbStairs { 31 | public static void main(String[] args) { 32 | int num = 40; 33 | long start = System.currentTimeMillis(); 34 | int i = climbStairs(num); 35 | System.out.println(i); 36 | long end = System.currentTimeMillis(); 37 | //604ms 38 | System.out.println("time:" + (end - start)); 39 | start = System.currentTimeMillis(); 40 | int i2 = climbStairs2(num); 41 | System.out.println(i2); 42 | end = System.currentTimeMillis(); 43 | //0ms 44 | System.out.println("time2:" + (end - start)); 45 | } 46 | 47 | /** 48 | * 时间太慢了,分析一下: 49 | *

50 | * 时间复杂度:(这里我们假设一下n-1约等于n-2) 51 | * T(n)=2O(n-1) 52 | * =2*2O(n-2) 53 | * ... 54 | * =2^mO(1) 55 | * =2^m 56 | * m = n-2 57 | * =2^n 58 | * 59 | * @param n 60 | * @return 61 | */ 62 | public static int climbStairs(int n) { 63 | if (n == 1 || n == 2) { 64 | return n; 65 | } 66 | return climbStairs(n - 1) + climbStairs(n - 2); 67 | } 68 | 69 | /** 70 | * 动态规划分解问题 71 | * 72 | * @param n 73 | * @return 74 | */ 75 | public static int climbStairs2(int n) { 76 | if (n <= 2) { 77 | return n; 78 | } 79 | int[] count = new int[n]; 80 | count[0] = 1; 81 | count[1] = 2; 82 | for (int i = 2; i < n; i++) { 83 | count[i] = count[i - 1] + count[i - 2]; 84 | } 85 | return count[n - 1]; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_71_simplifyPath.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * Created by wangpeng on 2019-01-02. 7 | * 71. 简化路径 8 | *

9 | * 给定一个文档 (Unix-style) 的完全路径,请进行路径简化。 10 | *

11 | * 例如, 12 | * path = "/home/", => "/home" 13 | * path = "/a/./b/../../c/", => "/c" 14 | *

15 | * 边界情况: 16 | *

17 | * 你是否考虑了 路径 = "/../" 的情况? 18 | * 在这种情况下,你需返回 "/" 。 19 | * 此外,路径中也可能包含多个斜杠 '/' ,如 "/home//foo/" 。 20 | * 在这种情况下,你可忽略多余的斜杠,返回 "/home/foo" 。 21 | * 22 | * @see simplify-path 23 | */ 24 | public class _71_simplifyPath { 25 | public static void main(String[] args) { 26 | long start1 = System.currentTimeMillis(); 27 | for (int i = 0; i < 10000; i++) { 28 | simplifyPath("/home/"); 29 | simplifyPath("/a/./b/../../c/"); 30 | simplifyPath("/../"); 31 | } 32 | long end1 = System.currentTimeMillis(); 33 | System.out.println(end1 - start1); 34 | } 35 | 36 | public static String simplifyPath(String path) { 37 | String[] split = path.split("/"); 38 | Stack stack = new Stack<>(); 39 | for (int i = 0; i < split.length; i++) { 40 | String s = split[i]; 41 | if (s.equals("/") || s.equals(".") || s.length() == 0) { 42 | continue; 43 | } 44 | if (s.equals("..")) { 45 | if (!stack.empty()) stack.pop(); 46 | continue; 47 | } 48 | stack.push(s); 49 | } 50 | StringBuilder builder = new StringBuilder(); 51 | while (!stack.empty()) { 52 | String pop = stack.pop(); 53 | builder.insert(0, pop); 54 | builder.insert(0, "/"); 55 | } 56 | if (builder.length() == 0) builder.append("/"); 57 | return builder.toString(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_746_minCostClimbingStairs.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-04-22. 5 | * 746. 使用最小花费爬楼梯 6 | *

7 | * 数组的每个索引做为一个阶梯,第 i个阶梯对应着一个非负数的体力花费值 cost[i](索引从0开始)。 8 | *

9 | * 每当你爬上一个阶梯你都要花费对应的体力花费值,然后你可以选择继续爬一个阶梯或者爬两个阶梯。 10 | *

11 | * 您需要找到达到楼层顶部的最低花费。在开始时,你可以选择从索引为 0 或 1 的元素作为初始阶梯。 12 | *

13 | * 示例 1: 14 | *

15 | * 输入: cost = [10, 15, 20] 16 | * 输出: 15 17 | * 解释: 最低花费是从cost[1]开始,然后走两步即可到阶梯顶,一共花费15。 18 | * 示例 2: 19 | *

20 | * 输入: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] 21 | * 输出: 6 22 | * 解释: 最低花费方式是从cost[0]开始,逐个经过那些1,跳过cost[3],一共花费6。 23 | * 注意: 24 | *

25 | * cost 的长度将会在 [2, 1000]。 26 | * 每一个 cost[i] 将会是一个Integer类型,范围为 [0, 999]。 27 | * 28 | * @see min-cost-climbing-stairs 29 | */ 30 | public class _746_minCostClimbingStairs { 31 | 32 | public static void main(String[] args) { 33 | _746_minCostClimbingStairs stairs = new _746_minCostClimbingStairs(); 34 | System.out.println(stairs.minCostClimbingStairs(new int[]{10, 15, 20})); 35 | System.out.println(stairs.minCostClimbingStairs(new int[]{1, 100, 1, 1, 1, 100, 1, 1, 100, 1})); 36 | System.out.println(stairs.minCostClimbingStairs(new int[]{2, 1000})); 37 | } 38 | 39 | /** 40 | * 解题思路: 41 | * 动态规划解题四部曲,可供参考 42 | *

43 | * - 确认原问题与子问题=>原问题:走完楼梯花费的最小体力,子问题:第i步花的最小体力 44 | * - 确认状态=>本题的动态规划状态单一,第i个状态即为i阶台阶的所花费的最小体力 45 | * - 确认边界状态的值=>第1步=cost[0],第2步=min(cost[0],cost[1]) 46 | * - 确定状态转移方程=>dp[i] = Math.min(dp[i - 2] + cost[i - 2], dp[i - 1] + cost[i - 1]); 47 | * 48 | * @param cost 49 | * @return 50 | */ 51 | public int minCostClimbingStairs(int[] cost) { 52 | int length = cost.length + 1; 53 | int[] dp = new int[length]; 54 | dp[0] = 0; 55 | dp[1] = 0; 56 | for (int i = 2; i < length; i++) { 57 | dp[i] = Math.min(dp[i - 2] + cost[i - 2], dp[i - 1] + cost[i - 1]); 58 | } 59 | return dp[length - 1]; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_75_sortColors.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | /** 6 | * Created by wangpeng on 2019-07-04. 7 | * 75. 颜色分类 8 | *

9 | * 给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 10 | *

11 | * 此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 12 | *

13 | * 注意: 14 | * 不能使用代码库中的排序函数来解决这道题。 15 | *

16 | * 示例: 17 | *

18 | * 输入: [2,0,2,1,1,0] 19 | * 输出: [0,0,1,1,2,2] 20 | * 进阶: 21 | *

22 | * 一个直观的解决方案是使用计数排序的两趟扫描算法。 23 | * 首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。 24 | * 你能想出一个仅使用常数空间的一趟扫描算法吗? 25 | *

26 | *

27 | * 来源:力扣(LeetCode) 28 | * 链接:https://leetcode-cn.com/problems/sort-colors 29 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 30 | */ 31 | public class _75_sortColors { 32 | 33 | public static void main(String[] args) { 34 | _75_sortColors sortColors = new _75_sortColors(); 35 | int[] nums = {2, 1, 2}; 36 | sortColors.sortColors(nums); 37 | Util.printArray(nums); 38 | } 39 | 40 | /** 41 | * 解题思路: 42 | * 原地排序==>借助常量级的空间做中转,可以参考快排实现? 43 | * 但是题目所需:你能想出一个仅使用常数空间的一趟扫描算法吗?(也就是说时间复杂度最好是O(n)) 44 | * 我们用三个指针(p0, p2 和curr)来分别追踪0的最右边界,2的最左边界和当前考虑的元素 45 | * 此问题称为"荷兰国旗问题" 46 | * 47 | * @param nums 48 | */ 49 | public void sortColors(int[] nums) { 50 | // 对于所有 idx < i : nums[idx < i] = 0 51 | // j是当前考虑元素的下标 52 | int p0 = 0, curr = 0; 53 | // 对于所有 idx > k : nums[idx > k] = 2 54 | int p2 = nums.length - 1; 55 | 56 | int tmp; 57 | while (curr <= p2) { 58 | if (nums[curr] == 0) { 59 | // 交换第 p0个和第curr个元素 60 | // i++,j++ 61 | tmp = nums[p0]; 62 | nums[p0++] = nums[curr]; 63 | nums[curr++] = tmp; 64 | } else if (nums[curr] == 2) { 65 | // 交换第k个和第curr个元素 66 | // p2-- 67 | tmp = nums[curr]; 68 | nums[curr] = nums[p2]; 69 | nums[p2--] = tmp; 70 | } else { 71 | curr++; 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_7_reverse.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/11/1. 5 | * 7. 反转整数 6 | *

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 位有符号整数,其数值范围是 [−2^31, 2^31 − 1]。根据这个假设,如果反转后的整数溢出,则返回 0。 24 | * 25 | * @see reverse-integer 26 | */ 27 | public class _7_reverse { 28 | public static void main(String[] args) { 29 | int reverse = reverse(1534236469); 30 | System.out.println(reverse); 31 | int reverse1 = reverse(-123); 32 | System.out.println(reverse1); 33 | } 34 | 35 | public static int reverse(int x) { 36 | boolean isNegative = false; 37 | if (x < 0) { 38 | isNegative = true; 39 | x = -x; 40 | } 41 | int result = 0; 42 | while (x > 0) { 43 | //注意溢出问题 44 | if (result * 10L + x % 10 > Integer.MAX_VALUE) { 45 | return 0; 46 | } 47 | result = result * 10 + x % 10; 48 | x = x / 10; 49 | } 50 | return isNegative ? -result : result; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_81_search.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-10-25. 5 | * 81. 搜索旋转排序数组 II 6 | * 7 | * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 8 | * 9 | * ( 例如,数组 [0,0,1,2,2,5,6] 可能变为 [2,5,6,0,0,1,2] )。 10 | * 11 | * 编写一个函数来判断给定的目标值是否存在于数组中。若存在返回 true,否则返回 false。 12 | * 13 | * 示例 1: 14 | * 15 | * 输入: nums = [2,5,6,0,0,1,2], target = 0 16 | * 输出: true 17 | * 示例 2: 18 | * 19 | * 输入: nums = [2,5,6,0,0,1,2], target = 3 20 | * 输出: false 21 | * 进阶: 22 | * 23 | * 这是 搜索旋转排序数组 的延伸题目,本题中的 nums  可能包含重复元素。 24 | * 这会影响到程序的时间复杂度吗?会有怎样的影响,为什么? 25 | * 26 | * 来源:力扣(LeetCode) 27 | * 链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii 28 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 29 | */ 30 | public class _81_search { 31 | 32 | public static void main(String[] args) { 33 | _81_search search = new _81_search(); 34 | System.out.println(search.search(new int[]{2, 5, 6, 0, 0, 1, 2}, 0)); 35 | System.out.println(search.search(new int[]{2, 5, 6, 0, 0, 1, 2}, 4)); 36 | System.out.println(search.search(new int[]{1, 1, 3, 1}, 3)); 37 | System.out.println(search.search(new int[]{3, 1, 1}, 3)); 38 | } 39 | 40 | /** 41 | * 解题思路: 42 | * 整体解法类似 {@link _33_search},有序的数组使用二分查找效率最高,注意相同位置的判断 43 | * 44 | * @param nums 45 | * @param target 46 | * @return 47 | */ 48 | public boolean search(int[] nums, int target) { 49 | int left = 0; 50 | int right = nums.length - 1; 51 | while (left <= right) { 52 | int mid = left + (right - left) / 2; 53 | if (nums[mid] == target) return true; 54 | if (nums[left] == nums[mid] && nums[mid] == nums[right]) { 55 | left++; 56 | right--; 57 | } else if (nums[left] <= nums[mid]) { //确定左区间 58 | if (nums[left] <= target && target < nums[mid]) 59 | right = mid - 1; 60 | else 61 | left = mid + 1; 62 | } else { //确定右区间 63 | if (nums[mid] < target && target <= nums[right]) 64 | left = mid + 1; 65 | else 66 | right = mid - 1; 67 | } 68 | } 69 | return false; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_83_deleteDuplicates.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.ListNode; 5 | 6 | /** 7 | * Created by wangpeng on 2019-11-04. 8 | * 83. 删除排序链表中的重复元素 9 | * 10 | * 给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。 11 | * 12 | * 示例 1: 13 | * 14 | * 输入: 1->1->2 15 | * 输出: 1->2 16 | * 示例 2: 17 | * 18 | * 输入: 1->1->2->3->3 19 | * 输出: 1->2->3 20 | * 21 | * 来源:力扣(LeetCode) 22 | * 链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list 23 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 24 | */ 25 | public class _83_deleteDuplicates { 26 | 27 | public static void main(String[] args) { 28 | _83_deleteDuplicates deleteDuplicates = new _83_deleteDuplicates(); 29 | ListNode node = new ListNode(1); 30 | node.next = new ListNode(1); 31 | node.next.next = new ListNode(2); 32 | Util.printListNode(deleteDuplicates.deleteDuplicates(node)); 33 | ListNode node1 = new ListNode(1); 34 | node1.next = new ListNode(1); 35 | node1.next.next = new ListNode(2); 36 | node1.next.next.next = new ListNode(3); 37 | node1.next.next.next.next = new ListNode(3); 38 | Util.printListNode(deleteDuplicates.deleteDuplicates(node1)); 39 | } 40 | 41 | /** 42 | * 解题思路:典型的列表遍历 43 | * 44 | * @param head 45 | * @return 46 | */ 47 | public ListNode deleteDuplicates(ListNode head) { 48 | ListNode dummy = new ListNode(0); 49 | dummy.next = head; 50 | ListNode next = head; 51 | ListNode preEqual; 52 | while (next != null) { 53 | preEqual = next.next; 54 | while (preEqual!=null&&preEqual.val == next.val){ 55 | preEqual = preEqual.next; 56 | } 57 | next.next = preEqual; 58 | next = preEqual; 59 | } 60 | 61 | return dummy.next; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_86_Partition.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.ListNode; 5 | 6 | import java.util.Random; 7 | 8 | /** 9 | * Created by wangpeng on 2018/8/17. 10 | *

11 | * 给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。 12 | * 你应当保留两个分区中每个节点的初始相对位置。 13 | */ 14 | public class _86_Partition { 15 | public static void main(String[] args) { 16 | ListNode node = Util.generateListNodeBySize(10); 17 | Util.printListNode(node); 18 | int x = new Random().nextInt(5); 19 | System.out.println("需要分割的x:" + x); 20 | ListNode partition = partition(node, x); 21 | Util.printListNode(partition); 22 | } 23 | 24 | public static ListNode partition(ListNode head, int x) { 25 | //头段 26 | ListNode preDummyNode = new ListNode(0); 27 | ListNode preNode = preDummyNode; 28 | //尾端 29 | ListNode lastDummyNode = new ListNode(0); 30 | ListNode lastNode = lastDummyNode; 31 | while (head != null) { 32 | if (head.val >= x) { 33 | lastNode.next = head; 34 | lastNode = head; 35 | } else { 36 | preNode.next = head; 37 | preNode = head; 38 | } 39 | head = head.next; 40 | } 41 | lastNode.next = null; 42 | preNode.next = lastDummyNode.next; 43 | 44 | return preDummyNode.next; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_88_merge.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | /** 6 | * Created by wangpeng on 2019-11-07. 7 | * 88. 合并两个有序数组 8 | * 9 | * 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 10 | * 11 | * 说明: 12 | * 13 | * 初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 14 | * 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 15 | * 示例: 16 | * 17 | * 输入: 18 | * nums1 = [1,2,3,0,0,0], m = 3 19 | * nums2 = [2,5,6], n = 3 20 | * 21 | * 输出: [1,2,2,3,5,6] 22 | * 23 | * 来源:力扣(LeetCode) 24 | * 链接:https://leetcode-cn.com/problems/merge-sorted-array 25 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 26 | */ 27 | public class _88_merge { 28 | 29 | public static void main(String[] args) { 30 | _88_merge merge = new _88_merge(); 31 | int[] nums1 = new int[]{1, 2, 3, 0, 0, 0, 0, 0}; 32 | int[] nums2 = new int[]{1, 1, 2, 5, 6}; 33 | merge.merge(nums1, 0, nums2, 5); 34 | Util.printArray(nums1); 35 | } 36 | 37 | /** 38 | * 解题思路: 39 | * 同时遍历两个数组,比较各自的大小,插入到相应的位置,由于nums1有额外的位置,所以从后面开始插入大元素可以减少元素的移动 40 | * 41 | * @param nums1 42 | * @param m 43 | * @param nums2 44 | * @param n 45 | */ 46 | public void merge(int[] nums1, int m, int[] nums2, int n) { 47 | while (m > 0 || n > 0) { 48 | int numM; 49 | int numN; 50 | if (m > 0 && n > 0) { 51 | numM = nums1[m - 1]; 52 | numN = nums2[n - 1]; 53 | if (numM > numN) { 54 | nums1[m + n - 1] = numM; 55 | m--; 56 | } else { 57 | nums1[m + n - 1] = numN; 58 | n--; 59 | } 60 | } else if (m > 0) { 61 | //只剩下nums1,肯定是有序的 62 | break; 63 | } else { 64 | nums1[n - 1] = nums2[n - 1]; 65 | n--; 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_89_grayCode.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by wangpeng on 2019-11-09. 10 | * 89. 格雷编码 11 | *

12 | * 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异。 13 | *

14 | * 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列。格雷编码序列必须以 0 开头。 15 | *

16 | * 示例 1: 17 | *

18 | * 输入: 2 19 | * 输出: [0,1,3,2] 20 | * 解释: 21 | * 00 - 0 22 | * 01 - 1 23 | * 11 - 3 24 | * 10 - 2 25 | *

26 | * 对于给定的 n,其格雷编码序列并不唯一。 27 | * 例如,[0,2,3,1] 也是一个有效的格雷编码序列。 28 | *

29 | * 00 - 0 30 | * 10 - 2 31 | * 11 - 3 32 | * 01 - 1 33 | * 示例 2: 34 | *

35 | * 输入: 0 36 | * 输出: [0] 37 | * 解释: 我们定义格雷编码序列必须以 0 开头。 38 | *   给定编码总位数为 n 的格雷编码序列,其长度为 2^n。当 n = 0 时,长度为 2^0 = 1。 39 | *   因此,当 n = 0 时,其格雷编码序列为 [0]。 40 | *

41 | * 来源:力扣(LeetCode) 42 | * 链接:https://leetcode-cn.com/problems/gray-code 43 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 44 | */ 45 | public class _89_grayCode { 46 | 47 | public static void main(String[] args) { 48 | _89_grayCode grayCode = new _89_grayCode(); 49 | Util.printList(grayCode.grayCode(2)); 50 | } 51 | 52 | /** 53 | * 解题思路: 54 | * 55 | * @param n 56 | * @return 57 | */ 58 | public List grayCode(int n) { 59 | List gray = new ArrayList<>(); 60 | gray.add(0); //初始化 n = 0 的解 61 | for (int i = 0; i < n; i++) { 62 | int add = 1 << i; //要加的数 63 | //倒序遍历,并且加上一个值添加到结果中 64 | for (int j = gray.size() - 1; j >= 0; j--) { 65 | gray.add(gray.get(j) + add); 66 | } 67 | } 68 | return gray; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_91_numDecodings.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2019-04-23. 5 | * 91. 解码方法 6 | *

7 | * 一条包含字母 A-Z 的消息通过以下方式进行了编码: 8 | *

9 | * 'A' -> 1 10 | * 'B' -> 2 11 | * ... 12 | * 'Z' -> 26 13 | * 给定一个只包含数字的非空字符串,请计算解码方法的总数。 14 | *

15 | * 示例 1: 16 | *

17 | * 输入: "12" 18 | * 输出: 2 19 | * 解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。 20 | * 示例 2: 21 | *

22 | * 输入: "226" 23 | * 输出: 3 24 | * 解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。 25 | * 26 | * @see decode-ways 27 | */ 28 | public class _91_numDecodings { 29 | public static void main(String[] args) { 30 | _91_numDecodings numDecodings = new _91_numDecodings(); 31 | System.out.println(numDecodings.numDecodings("100")); 32 | System.out.println(numDecodings.numDecodings("101")); 33 | System.out.println(numDecodings.numDecodings("110")); 34 | System.out.println(numDecodings.numDecodings("230")); 35 | System.out.println(numDecodings.numDecodings("226")); 36 | System.out.println(numDecodings.numDecodings("2261")); 37 | } 38 | 39 | /** 40 | * 解题思路: 41 | * 字符可以1个或者2个对应字母,2个最大是26,一个最小是1 42 | * dp代表当前i可以解码的个数 43 | *

44 | * 题目很坑,注意异常数字(0)非常多 45 | * 理清楚递推逻辑还是很难的。 46 | * 47 | * @param s 48 | * @return 49 | */ 50 | public int numDecodings(String s) { 51 | if (s.length() == 0 || (s.charAt(0) == '0')) return 0; 52 | if (s.length() == 1) return 1; 53 | int[] dp = new int[s.length() + 1]; 54 | dp[0] = 1; 55 | for (int i = 0; i < s.length(); ++i) { 56 | dp[i + 1] = s.charAt(i) == '0' ? 0 : dp[i]; 57 | if (i > 0 && (s.charAt(i - 1) == '1' || (s.charAt(i - 1) == '2' && s.charAt(i) <= '6'))) { 58 | dp[i + 1] += dp[i - 1]; 59 | } 60 | } 61 | return dp[s.length()]; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/pp/arithmetic/leetcode/_9_isPalindrome.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.leetcode; 2 | 3 | /** 4 | * Created by wangpeng on 2018/11/1. 5 | * 9. 回文数 6 | *

7 | * 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。 8 | *

9 | * 示例 1: 10 | *

11 | * 输入: 121 12 | * 输出: true 13 | * 示例 2: 14 | *

15 | * 输入: -121 16 | * 输出: false 17 | * 解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。 18 | * 示例 3: 19 | *

20 | * 输入: 10 21 | * 输出: false 22 | * 解释: 从右向左读, 为 01 。因此它不是一个回文数。 23 | * 进阶: 24 | *

25 | * 你能不将整数转为字符串来解决这个问题吗? 26 | * 27 | * @see palindrome-number 28 | */ 29 | public class _9_isPalindrome { 30 | public static void main(String[] args) { 31 | boolean palindrome = isPalindrome(123); 32 | System.out.println(palindrome); 33 | } 34 | 35 | public static boolean isPalindrome(int x) { 36 | if (x < 0 || (x != 0 && x % 10 == 0)) { //x是10的倍数一定不是回文串 37 | return false; 38 | } 39 | int s = 0; 40 | while (s <= x) { 41 | s = s * 10 + x % 10; 42 | if (s == x || s == x / 10) { //分别处理整数长度是奇数或者偶数的情况 43 | return true; 44 | } 45 | x /= 10; 46 | } 47 | return false; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/pp/arithmetic/medium/BasicCalculateTest.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.medium; 2 | 3 | import java.util.Deque; 4 | import java.util.Stack; 5 | 6 | /** 7 | * 8 | * @author pphdsny 9 | * 10 | * Implement a basic calculator to evaluate a simple expression string. 11 | * The expression string may contain open ( and closing parentheses ), 12 | * the plus + or minus sign -, non-negative integers and empty spaces . 13 | * You may assume that the given expression is always valid. 14 | * 15 | * Some examples: "1 + 1" = 2 " 2-1 + 2 " = 3 "(1+(4+5+2)-3)+(6+8)" = 23 16 | * 17 | * Note: Do not use the eval built-in library function. 18 | * 19 | * @see https://leetcode.com/problems/basic-calculator/ 20 | */ 21 | public class BasicCalculateTest { 22 | 23 | public static void main(String[] args) { 24 | int calculate = calculate("(1+(4+5+2)-32)+(6+8)"); 25 | System.out.println("输出结果:" + calculate); 26 | } 27 | 28 | public static int calculate1(String s){ 29 | //将中缀表达式转换成后缀表达式再进行计算 30 | return 0; 31 | } 32 | 33 | public static int calculate(String s) { 34 | Stack stack = new Stack(); 35 | int result = 0; 36 | int number = 0; 37 | int sign = 1; 38 | for (int i = 0; i < s.length(); i++) { 39 | char c = s.charAt(i); 40 | if (Character.isDigit(c)) { 41 | number = 10 * number + (int) (c - '0'); 42 | } else if (c == '+') { 43 | result += sign * number; 44 | number = 0; 45 | sign = 1; 46 | } else if (c == '-') { 47 | result += sign * number; 48 | number = 0; 49 | sign = -1; 50 | } else if (c == '(') { 51 | // we push the result first, then sign; 52 | stack.push(result); 53 | stack.push(sign); 54 | // reset the sign and result for the value in the parenthesis 55 | sign = 1; 56 | result = 0; 57 | } else if (c == ')') { 58 | result += sign * number; 59 | number = 0; 60 | result *= stack.pop(); // stack.pop() is the sign before the 61 | // parenthesis 62 | result += stack.pop(); // stack.pop() now is the result 63 | // calculated before the parenthesis 64 | 65 | } 66 | } 67 | if (number != 0) 68 | result += sign * number; 69 | return result; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/pp/arithmetic/medium/LegalOrder.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.medium; 2 | 3 | import java.util.Objects; 4 | import java.util.Stack; 5 | 6 | /** 7 | * Created by wangpeng on 2018/8/27. 8 | * 合法出入栈 9 | * 已知从1至n的数字序列,按顺序入栈,每个数字入栈后即可出栈, 10 | * 也可在栈中 停留,等待后面的数字入栈出栈后,该数字再出栈,求该数字序列的某出栈 序列是否合法? 11 | * 12 | * @see 13 | */ 14 | public class LegalOrder { 15 | 16 | public static void main(String[] args) { 17 | Stack order = new Stack<>(); 18 | order.push(4); 19 | order.push(5); 20 | order.push(2); 21 | order.push(1); 22 | order.push(3); 23 | boolean legalOrder = isLegalOrder(order); 24 | System.out.println("legalOrder:" + legalOrder); 25 | } 26 | 27 | public static boolean isLegalOrder(Stack order) { 28 | int n = 5; 29 | Stack stack = new Stack<>(); 30 | for (int i = 1; i <= n; i++) { 31 | stack.push(i); 32 | while (!stack.isEmpty() 33 | && Objects.equals(stack.peek(), order.peek())) { 34 | stack.pop(); 35 | order.pop(); 36 | } 37 | } 38 | if (order.isEmpty()) { 39 | return true; 40 | } 41 | return false; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/pp/arithmetic/model/DisjointSet.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.model; 2 | 3 | /** 4 | * Created by wangpeng on 2018/9/29. 5 | * 并查集实现 6 | */ 7 | public class DisjointSet { 8 | 9 | private int count = 0; 10 | private int[] id; 11 | private int[] size; 12 | 13 | public DisjointSet(int n) { 14 | id = new int[n]; 15 | size = new int[n]; 16 | for (int i = 0; i < n; i++) { 17 | id[i] = i; 18 | size[i] = 1; 19 | } 20 | count = n; 21 | } 22 | 23 | public int find(int n) { 24 | while (n != id[n]) { 25 | id[n] = id[id[n]]; 26 | n = id[n]; 27 | } 28 | return n; 29 | } 30 | 31 | public void union(int p, int q) { 32 | int _p = find(p); 33 | int _q = find(q); 34 | if (_p == _q) { 35 | return; 36 | } 37 | if (size[_p] > size[_q]) { 38 | id[_q] = _p; 39 | size[_p] += size[_q]; 40 | } else { 41 | id[_p] = _q; 42 | size[_q] += size[_p]; 43 | } 44 | count--; 45 | } 46 | 47 | public int count() { 48 | return count; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/pp/arithmetic/model/ListNode.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.model; 2 | 3 | /** 4 | * Created by wangpeng on 2018/7/9. 5 | * 链表 6 | */ 7 | public class ListNode { 8 | 9 | public int val; 10 | public ListNode next; 11 | 12 | public ListNode(int x) { 13 | val = x; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/pp/arithmetic/model/Node.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.model; 2 | 3 | /** 4 | * Created by wangpeng on 2019-12-14. 5 | */ 6 | public class Node { 7 | public int val; 8 | public Node left; 9 | public Node right; 10 | public Node next; 11 | 12 | public Node() {} 13 | 14 | public Node(int _val) { 15 | val = _val; 16 | } 17 | 18 | public Node(int _val, Node _left, Node _right, Node _next) { 19 | val = _val; 20 | left = _left; 21 | right = _right; 22 | next = _next; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/pp/arithmetic/model/RandomListNode.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.model; 2 | 3 | /** 4 | * Created by wangpeng on 2018/8/20. 5 | */ 6 | public class RandomListNode { 7 | public int label; 8 | public RandomListNode next; 9 | public RandomListNode random; 10 | 11 | public RandomListNode(int x) { 12 | this.label = x; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/pp/arithmetic/model/TreeNode.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.model; 2 | 3 | public class TreeNode { 4 | public int val; 5 | public TreeNode left; 6 | public TreeNode right; 7 | 8 | public TreeNode(int x) { 9 | val = x; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/pp/arithmetic/model/TrieTree.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.model; 2 | 3 | /** 4 | * Created by wangpeng on 2018/9/28. 5 | */ 6 | public class TrieTree { 7 | public static final int MAX = 26; 8 | public char val; 9 | public TrieTree[] tries; 10 | public boolean isEnd; 11 | 12 | public TrieTree(char val) { 13 | this.val = val; 14 | tries = new TrieTree[MAX]; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/pp/arithmetic/offer/_05_replaceSpace.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.offer; 2 | 3 | /** 4 | * Created by wangpeng on 2020-07-30. 5 | * 剑指 Offer 05. 替换空格 6 | * 7 | * 请实现一个函数,把字符串 s 中的每个空格替换成"%20"。 8 | * 9 | *   10 | * 11 | * 示例 1: 12 | * 13 | * 输入:s = "We are happy." 14 | * 输出:"We%20are%20happy." 15 | *   16 | * 17 | * 限制: 18 | * 19 | * 0 <= s 的长度 <= 10000 20 | * 21 | * 来源:力扣(LeetCode) 22 | * 链接:https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof 23 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 24 | */ 25 | public class _05_replaceSpace { 26 | 27 | public static void main(String[] args) { 28 | _05_replaceSpace replaceSpace = new _05_replaceSpace(); 29 | System.out.println(replaceSpace.replaceSpace("We are happy.")); 30 | } 31 | 32 | /** 33 | * 解题思路: 34 | * 看到题目最直接的想法就是遍历异常,遇到空格就替换 35 | * 没有清楚这道题到底想考什么? 36 | * @param s 37 | * @return 38 | */ 39 | public String replaceSpace(String s) { 40 | char[] chars = s.toCharArray(); 41 | StringBuilder builder = new StringBuilder(); 42 | for (int i = 0; i < chars.length; i++) { 43 | char aChar = chars[i]; 44 | if (aChar == ' '){ 45 | builder.append("%20"); 46 | }else{ 47 | builder.append(aChar); 48 | } 49 | } 50 | 51 | return builder.toString(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/pp/arithmetic/offer/_06_reversePrint.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.offer; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.ListNode; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * Created by wangpeng on 2020-07-30. 11 | * 剑指 Offer 06. 从尾到头打印链表 12 | * 13 | * 输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。 14 | * 15 | *   16 | * 17 | * 示例 1: 18 | * 19 | * 输入:head = [1,3,2] 20 | * 输出:[2,3,1] 21 | *   22 | * 23 | * 限制: 24 | * 25 | * 0 <= 链表长度 <= 10000 26 | * 27 | * 来源:力扣(LeetCode) 28 | * 链接:https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof 29 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 30 | */ 31 | public class _06_reversePrint { 32 | 33 | public static void main(String[] args) { 34 | ListNode listNode = Util.generateListNodeBySize(10); 35 | Util.printListNode(listNode); 36 | _06_reversePrint reversePrint = new _06_reversePrint(); 37 | int[] arr = reversePrint.reversePrint(listNode); 38 | Util.printArray(arr); 39 | } 40 | 41 | /** 42 | * 解题思路: 43 | * 链表的问题,最直接也只能是遍历+递归,可以借助多指针一起,此题只需要遍历就可以了 44 | * @param head 45 | * @return 46 | */ 47 | public int[] reversePrint(ListNode head) { 48 | List list = new ArrayList<>(); 49 | dfs(head,list); 50 | int[] retArr = new int[list.size()]; 51 | for (int i = 0; i < list.size(); i++) { 52 | retArr[i] = list.get(i); 53 | } 54 | return retArr; 55 | } 56 | 57 | private void dfs(ListNode node,List list){ 58 | if (node == null){ 59 | return; 60 | } 61 | dfs(node.next,list); 62 | list.add(node.val); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/pp/arithmetic/offer/_10_2_numWays.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.offer; 2 | 3 | /** 4 | * Created by wangpeng on 2020-08-05. 5 | * 6 | * 剑指 Offer 10- II. 青蛙跳台阶问题 7 | * 8 | * 9 | * 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。 10 | * 11 | * 答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。 12 | * 13 | * 示例 1: 14 | * 15 | * 输入:n = 2 16 | * 输出:2 17 | * 示例 2: 18 | * 19 | * 输入:n = 7 20 | * 输出:21 21 | * 示例 3: 22 | * 23 | * 输入:n = 0 24 | * 输出:1 25 | * 提示: 26 | * 27 | * 0 <= n <= 100 28 | * 29 | * 来源:力扣(LeetCode) 30 | * 链接:https://leetcode-cn.com/problems/qing-wa-tiao-tai-jie-wen-ti-lcof 31 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 32 | */ 33 | public class _10_2_numWays { 34 | 35 | public static void main(String[] args) { 36 | _10_2_numWays numWays = new _10_2_numWays(); 37 | System.out.println(numWays.numWays(2)); 38 | System.out.println(numWays.numWays(3)); 39 | System.out.println(numWays.numWays(4)); 40 | System.out.println(numWays.numWays(5)); 41 | System.out.println(numWays.numWays(6)); 42 | System.out.println(numWays.numWays(40)); 43 | } 44 | 45 | /** 46 | * 解题思路:借鉴动态规划思路 47 | * 1.dp[0]=1,dp[1]=1,d[2]=dp[0]+d[1] 48 | * 2.dp[n]=dp[n-1]+dp[n-2] 49 | * 50 | * @param n 51 | * @return 52 | */ 53 | public int numWays(int n) { 54 | if (n == 0) return 1; 55 | if (n == 1) return 1; 56 | int[] dp = new int[n+1]; 57 | dp[0] = 1; 58 | dp[1] = 1; 59 | for (int i = 2; i <= n; i++) { 60 | dp[i] = (dp[i-1]+dp[i-2])%1000000007; 61 | } 62 | 63 | return dp[n]; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/pp/arithmetic/offer/_10_fib.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.offer; 2 | 3 | /** 4 | * Created by wangpeng on 2020-08-04. 5 | * 6 | * 剑指 Offer 10- I. 斐波那契数列 7 | * 8 | * 写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下: 9 | * 10 | * F(0) = 0,   F(1) = 1 11 | * F(N) = F(N - 1) + F(N - 2), 其中 N > 1. 12 | * 斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。 13 | * 14 | * 答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。 15 | * 16 | *   17 | * 18 | * 示例 1: 19 | * 20 | * 输入:n = 2 21 | * 输出:1 22 | * 示例 2: 23 | * 24 | * 输入:n = 5 25 | * 输出:5 26 | *   27 | * 28 | * 提示: 29 | * 30 | * 0 <= n <= 100 31 | * 32 | * 来源:力扣(LeetCode) 33 | * 链接:https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof 34 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 35 | */ 36 | public class _10_fib { 37 | 38 | public static void main(String[] args) { 39 | _10_fib fib = new _10_fib(); 40 | System.out.println(fib.fib(2)); 41 | System.out.println(fib.fib(5)); 42 | System.out.println(fib.fib(100)); 43 | } 44 | 45 | /** 46 | * 解题思路: 47 | * 有两个方案: 48 | * 一、是从n开始递归求解f(n)=f(n-1)+f(n-2),这种递归效率较低,当n比较大时候存在大量重复的计算 49 | * 二、从0开始计算,存储下每次计算的结果,逐步计算到n,借助动态规划 50 | * 51 | * @param n 52 | * @return 53 | */ 54 | public int fib(int n) { 55 | if (n == 0) return 0; 56 | if (n == 1) return 1; 57 | int[] dp = new int[n+1]; 58 | dp[0] = 0; 59 | dp[1] = 1; 60 | for (int i = 2; i <= n; i++) { 61 | dp[i] = (dp[i-1]+dp[i-2])%1000000007; 62 | } 63 | return dp[n]; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/pp/arithmetic/offer/_11_minArray.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.offer; 2 | 3 | /** 4 | * Created by wangpeng on 2020-08-05. 5 | * 6 | * 7 | * 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。   8 | * 9 | * 示例 1: 10 | * 11 | * 输入:[3,4,5,1,2] 12 | * 输出:1 13 | * 示例 2: 14 | * 15 | * 输入:[2,2,2,0,1] 16 | * 输出:0 17 | * 18 | * 来源:力扣(LeetCode) 19 | * 链接:https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof 20 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 21 | */ 22 | public class _11_minArray { 23 | 24 | public static void main(String[] args) { 25 | _11_minArray minArray = new _11_minArray(); 26 | System.out.println(minArray.minArray(new int[]{3,4,5,1,2})); 27 | System.out.println(minArray.minArray(new int[]{2,2,2,0,1})); 28 | } 29 | 30 | /** 31 | * 解题思路: 32 | * 递增数组经过一次旋转,从递增到递减的转折点,则是最小的 33 | * @param numbers 34 | * @return 35 | */ 36 | public int minArray(int[] numbers) { 37 | if (numbers == null || numbers.length == 0) return 0; 38 | int retVal = numbers[0]; 39 | int preVal = numbers[0]; 40 | for (int i = 1; i < numbers.length; i++) { 41 | int number = numbers[i]; 42 | if (number >= preVal){ 43 | preVal = number; 44 | }else{ 45 | retVal = number; 46 | break; 47 | } 48 | } 49 | 50 | return retVal; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/pp/arithmetic/offer/_14_1_cuttingRope.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.offer; 2 | 3 | /** 4 | * Created by wangpeng on 2020-08-07. 5 | * 6 | * 剑指 Offer 14- I. 剪绳子 7 | * 8 | * 给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m-1] 。请问 k[0]*k[1]*...*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。 9 | * 10 | * 示例 1: 11 | * 12 | * 输入: 2 13 | * 输出: 1 14 | * 解释: 2 = 1 + 1, 1 × 1 = 1 15 | * 示例 2: 16 | * 17 | * 输入: 10 18 | * 输出: 36 19 | * 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36 20 | * 提示: 21 | * 22 | * 2 <= n <= 58 23 | * 24 | * 来源:力扣(LeetCode) 25 | * 链接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof 26 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 27 | */ 28 | public class _14_1_cuttingRope { 29 | 30 | public static void main(String[] args) { 31 | _14_1_cuttingRope cuttingRope = new _14_1_cuttingRope(); 32 | System.out.println(cuttingRope.cuttingRope(8)); 33 | System.out.println(cuttingRope.cuttingRope(10)); 34 | System.out.println(cuttingRope.cuttingRope(14)); 35 | System.out.println(cuttingRope.cuttingRope(58)); 36 | } 37 | 38 | /** 39 | * 解题思路: 40 | * 手动模拟了从2-10的最大乘积数字拆解,发现了一个现象: 41 | * 对于数字n,n一直除以2到1为止,得到的数字就是最大的乘积,举例如下: 42 | * 数字n 2 3 4 5 6 7 8 9 10 43 | * 乘积 1,1 1,2 2,2 2,3 3,3 3,4(2,2) 4(2,2),4(2,2) 4,5(2,3) 5(2,3),5(2,3) 44 | * 发现到了后面的最大乘积可以利用之前的计算好的结果,从而得出动态规划转移方程 45 | * dp[i]=dp[i/2]*dp[i-i/2](i>3) 46 | * 上面有问题,例如8的最大值不是除以2得到4*4=16,而是3*2*3=18,所以得双重循环取所有情况的最大值 47 | * for (int j = 1; j <= i / 2; j++) { 48 | * dp[i] = Math.max(dp[i], dp[j] * dp[i - j]); 49 | * } 50 | * 51 | * @param n 52 | * @return 53 | */ 54 | public int cuttingRope(int n) { 55 | if (n <= 3) return n - 1; 56 | int[] dp = new int[n + 1]; 57 | //初始化,1,2,3特殊处理 58 | dp[1] = 1; 59 | dp[2] = 2; 60 | dp[3] = 3; 61 | for (int i = 4; i <= n; i++) { 62 | for (int j = 1; j <= i / 2; j++) { 63 | dp[i] = Math.max(dp[i], dp[j] * dp[i - j]); 64 | } 65 | } 66 | return dp[n]; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/pp/arithmetic/offer/_15_hammingWeight.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.offer; 2 | 3 | /** 4 | * Created by wangpeng on 2020-08-10. 5 | * 剑指 Offer 15. 二进制中1的个数 6 | * 7 | * 请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。 8 | * 9 | * 示例 1: 10 | * 11 | * 输入:00000000000000000000000000001011 12 | * 输出:3 13 | * 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 14 | * 示例 2: 15 | * 16 | * 输入:00000000000000000000000010000000 17 | * 输出:1 18 | * 解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。 19 | * 示例 3: 20 | * 21 | * 输入:11111111111111111111111111111101 22 | * 输出:31 23 | * 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。 24 | * 25 | * 来源:力扣(LeetCode) 26 | * 链接:https://leetcode-cn.com/problems/er-jin-zhi-zhong-1de-ge-shu-lcof 27 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 28 | */ 29 | public class _15_hammingWeight { 30 | 31 | public static void main(String[] args) { 32 | _15_hammingWeight hammingWeight = new _15_hammingWeight(); 33 | System.out.println(hammingWeight.hammingWeight(11)); 34 | System.out.println(hammingWeight.hammingWeight(128)); 35 | // System.out.println(hammingWeight.hammingWeight(4294967293)); 36 | } 37 | 38 | 39 | /** 40 | * 解题思路: 41 | * 如果n%2!=0,则1的个数+1,直到n=1 42 | * 43 | * 注意无符号的,对应int会超 右移动使用>>>(无符号右移) 44 | * @param n 45 | * @return 46 | */ 47 | // you need to treat n as an unsigned value 48 | public int hammingWeight(int n) { 49 | int retVal = 0; 50 | while (n != 0) { 51 | retVal += n & 1; 52 | n = n >>> 1; 53 | } 54 | 55 | return retVal; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/pp/arithmetic/offer/_16_myPow.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.offer; 2 | 3 | /** 4 | * Created by wangpeng on 2020-08-11. 5 | * 6 | * 剑指 Offer 16. 数值的整数次方 7 | * 8 | * 实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。 9 | * 10 | *   11 | * 12 | * 示例 1: 13 | * 14 | * 输入: 2.00000, 10 15 | * 输出: 1024.00000 16 | * 示例 2: 17 | * 18 | * 输入: 2.10000, 3 19 | * 输出: 9.26100 20 | * 示例 3: 21 | * 22 | * 输入: 2.00000, -2 23 | * 输出: 0.25000 24 | * 解释: 2-2 = 1/22 = 1/4 = 0.25 25 | *   26 | * 27 | * 说明: 28 | * 29 | * -100.0 < x < 100.0 30 | * n 是 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1] 。 31 | * 32 | * 来源:力扣(LeetCode) 33 | * 链接:https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof 34 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 35 | */ 36 | public class _16_myPow { 37 | 38 | public static void main(String[] args) { 39 | _16_myPow myPow = new _16_myPow(); 40 | System.out.println(myPow.myPow(2.0,10)); 41 | System.out.println(myPow.myPow(2.1,3)); 42 | System.out.println(myPow.myPow(2.0,-2)); 43 | System.out.println(myPow.myPow(0.00001, 2147483647)); 44 | System.out.println(myPow.myPow(2, -2147483648)); 45 | } 46 | 47 | /** 48 | * 解题思路: 49 | * 最简单的方式就是直接循环0-n,将x相乘得出结果,题目中的n范围比较大,这样子效率太低 50 | * 优化:类似2分拆分,一半一半的计算结果,最终相乘 51 | * @param x 52 | * @param n 53 | * @return 54 | */ 55 | public double myPow(double x, int n) { 56 | if (n == 0) return 1; 57 | if (n<0){ 58 | //指数是否负数,负数需要取倒数 59 | x = 1/x; 60 | } 61 | //是否取一半还有剩余一个 62 | boolean isOdd = n % 2 != 0; 63 | double v = myPow(x, Math.abs(n / 2)); 64 | if (isOdd) { 65 | return v * v * x; 66 | } else { 67 | return v * v; 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/pp/arithmetic/offer/_17_printNumbers.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.offer; 2 | 3 | import pp.arithmetic.Util; 4 | 5 | /** 6 | * Created by wangpeng on 2020-08-11. 7 | * 8 | * 剑指 Offer 17. 打印从1到最大的n位数 9 | * 10 | * 输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。 11 | * 12 | * 示例 1: 13 | * 14 | * 输入: n = 1 15 | * 输出: [1,2,3,4,5,6,7,8,9] 16 | *   17 | * 18 | * 说明: 19 | * 20 | * 用返回一个整数列表来代替打印 21 | * n 为正整数 22 | * 23 | * 来源:力扣(LeetCode) 24 | * 链接:https://leetcode-cn.com/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof 25 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 26 | */ 27 | public class _17_printNumbers { 28 | 29 | public static void main(String[] args) { 30 | _17_printNumbers printNumbers = new _17_printNumbers(); 31 | Util.printArray(printNumbers.printNumbers(1)); 32 | Util.printArray(printNumbers.printNumbers(2)); 33 | Util.printArray(printNumbers.printNumbers(3)); 34 | } 35 | 36 | /** 37 | * 解题思路: 38 | * 本题没有什么难度,唯一难的就是咋根据n构建出相应size的数组 39 | * 40 | * @param n 41 | * @return 42 | */ 43 | public int[] printNumbers(int n) { 44 | char[] len = new char[n]; 45 | for (int i = 0; i < n; i++) { 46 | len[i] = '9'; 47 | } 48 | int size = Integer.parseInt(new String(len)); 49 | int[] retVal = new int[size]; 50 | for (int i = 0; i < size; i++) { 51 | retVal[i] = i+1; 52 | } 53 | 54 | return retVal; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/pp/arithmetic/offer/_18_deleteNode.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.offer; 2 | 3 | import pp.arithmetic.Util; 4 | import pp.arithmetic.model.ListNode; 5 | 6 | /** 7 | * Created by wangpeng on 2020-09-09. 8 | * 剑指 Offer 18. 删除链表的节点 9 | * 10 | * 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。 11 | * 12 | * 返回删除后的链表的头节点。 13 | * 14 | * 注意:此题对比原题有改动 15 | * 16 | * 示例 1: 17 | * 18 | * 输入: head = [4,5,1,9], val = 5 19 | * 输出: [4,1,9] 20 | * 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9. 21 | * 示例 2: 22 | * 23 | * 输入: head = [4,5,1,9], val = 1 24 | * 输出: [4,5,9] 25 | * 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9. 26 | *   27 | * 28 | * 说明: 29 | * 30 | * 题目保证链表中节点的值互不相同 31 | * 若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点 32 | * 33 | * 来源:力扣(LeetCode) 34 | * 链接:https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof 35 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 36 | */ 37 | public class _18_deleteNode { 38 | 39 | public static void main(String[] args) { 40 | _18_deleteNode deleteNode = new _18_deleteNode(); 41 | ListNode head = new ListNode(4); 42 | head.next = new ListNode(5); 43 | head.next.next = new ListNode(1); 44 | head.next.next.next = new ListNode(9); 45 | ListNode listNode = deleteNode.deleteNode(head, 4); 46 | Util.printListNode(listNode); 47 | } 48 | 49 | /** 50 | * 解题思路: 51 | * 对于链表的问题,最核心的思想就是遍历,使用一个虚拟节点指向头结点,用来缓存返回结果 52 | * 53 | * @param head 54 | * @param val 55 | * @return 56 | */ 57 | public ListNode deleteNode(ListNode head, int val) { 58 | ListNode dummp = new ListNode(0); 59 | dummp.next = head; 60 | ListNode pre = dummp; 61 | ListNode next = head; 62 | while (next != null) { 63 | if (next.val == val) { 64 | pre.next = next.next; 65 | next.next = null; 66 | return dummp.next; 67 | } 68 | pre = next; 69 | next = next.next; 70 | } 71 | 72 | return null; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/pp/arithmetic/other/Search.java: -------------------------------------------------------------------------------- 1 | package pp.arithmetic.other; 2 | 3 | /** 4 | * Created by wangpeng on 2018/9/12. 5 | * 找元素 6 | */ 7 | public class Search { 8 | 9 | public static void main(String[] args) { 10 | int index = binarySearch(new int[]{1, 2, 3, 4, 12}, 12); 11 | System.out.println(index); 12 | int index2 = binarySearch2(new int[]{1, 2, 3, 4, 5, 6, 7, 8}, 2); 13 | System.out.println(index2); 14 | } 15 | 16 | /** 17 | * 循环实现 18 | * 19 | * @param nums 20 | * @param target 21 | * @return 22 | */ 23 | public static int binarySearch(int[] nums, int target) { 24 | int start = 0; 25 | int end = nums.length - 1; 26 | int middle; 27 | while (start <= end) { 28 | middle = (start + end) / 2; 29 | if (target > nums[middle]) { 30 | start = middle + 1; 31 | } else if (target < nums[middle]) { 32 | end = middle - 1; 33 | } else { 34 | return middle; 35 | } 36 | } 37 | return -1; 38 | } 39 | 40 | /** 41 | * 递归实现 42 | * 43 | * @param nums 44 | * @param target 45 | * @return 46 | */ 47 | public static int binarySearch2(int[] nums, int target) { 48 | return search(nums, 0, nums.length - 1, target); 49 | } 50 | 51 | private static int search(int[] nums, int start, int end, int target) { 52 | if (start > end) { 53 | return -1; 54 | } 55 | int middle = (start + end) / 2; 56 | if (target == nums[middle]) { 57 | return middle; 58 | } 59 | if (target > nums[middle]) { 60 | return search(nums, middle + 1, end, target); 61 | } 62 | if (target < nums[middle]) { 63 | return search(nums, start, middle - 1, target); 64 | } 65 | return -1; 66 | } 67 | } 68 | --------------------------------------------------------------------------------