├── HDU1166_敌兵布阵_BIT.cpp ├── HDU1232_畅通工程_Disjoint Set.cpp ├── HDU1251_统计难题_Trie.cpp ├── HDU1754_I Hate It_Segment Tree.cpp ├── LC1004_Max Consecutive Ones III_Sliding Window.cpp ├── LC1005_Maximize Sum Of Array After K Negations_Greedy Algorithm.cpp ├── LC1006_Clumsy Factorial_Stack.cpp ├── LC100_Same Tree_DFS.c ├── LC100_Same Tree_DFS.cpp ├── LC100_Same Tree_DFS.java ├── LC100_Same Tree_DFS.py ├── LC1018_Binary Prefix Divisible By 5_Math.cpp ├── LC101_Symmetric Tree_Recursion.cpp ├── LC102_Binary Tree Level Order Traversal_BFS.cpp ├── LC102_Binary Tree Level Order Traversal_BFS.java ├── LC102_Binary Tree Level Order Traversal_BFS.py ├── LC1035_Uncrossed Lines_DP.cpp ├── LC1038_Convert BST to Greater Tree_Recursion.cpp ├── LC103_Binary Tree Zigzag Level Order Traversal_BFS.cpp ├── LC1046_Last Stone Weight_Heap.cpp ├── LC1047_Remove All Adjacent Duplicates In String_Stack.cpp ├── LC1047_Remove All Adjacent Duplicates In String_String Manipulation.cpp ├── LC1049_Last Stone Weight II_DP.cpp ├── LC104_Maximum Depth of Binary Tree_Recursion.c ├── LC104_Maximum Depth of Binary Tree_Recursion.cpp ├── LC104_Maximum Depth of Binary Tree_Recursion.java ├── LC104_Maximum Depth of Binary Tree_Recursion.py ├── LC1052_Grumpy Bookstore Owner_Sliding Window.cpp ├── LC105_Construct Binary Tree from Preorder and Inorder Traversal_Recursion.cpp ├── LC106_Construct Binary Tree from Inorder and Postorder Traversal_Recursion.cpp ├── LC107_Binary Tree Level Order Traversal II_BFS.cpp ├── LC107_Binary Tree Level Order Traversal II_BFS.py ├── LC108_Convert Sorted Array to Binary Search Tree_Recursion.cpp ├── LC110_Balanced Binary Tree_Recursion.cpp ├── LC111_Minimum Depth of Binary Tree_BFS.cpp ├── LC1128_Number of Equivalent Domino Pairs_Hash Table.cpp ├── LC112_Path Sum_Recursion.cpp ├── LC1137_N-th Tribonacci Number_DP.cpp ├── LC1143_Longest Common Subsequence_DP.cpp ├── LC1143_longestCommonSubsequence.py ├── LC1143_longestCommonSubsequence_DP.py ├── LC114_Flatten Binary Tree to Linked List_DFS.cpp ├── LC115_Distinct Subsequences_DP.cpp ├── LC116_Populating Next Right Pointers in Each Node_BFS.cpp ├── LC1178_Number of Valid Words for Each Puzzle_Trie.cpp ├── LC117_Populating Next Right Pointers in Each Node II_BFS.cpp ├── LC118_Pascal's Triangle_Math.cpp ├── LC119_Pascal's Triangle II_Math.cpp ├── LC11_Max Area_Naive Algorithm.cpp ├── LC11_Max Area_Naive Algorithm.py ├── LC1208_Get Equal Substrings Within Budget_Sliding Window.cpp ├── LC121_Best Time to Buy and Sell Stock_DP(Rolling Array).cpp ├── LC121_Best Time to Buy and Sell Stock_DP.cpp ├── LC121_Best Time to Buy and Sell Stock_Naive Algorithm.py ├── LC122_Best Time to Buy and Sell Stock II_DP(Rolling Array).cpp ├── LC122_Best Time to Buy and Sell Stock II_DP.cpp ├── LC122_Best Time to Buy and Sell Stock II_Greedy Algorithm.cpp ├── LC1232_Check If It Is a Straight Line_Math.cpp ├── LC123_Best Time to Buy and Sell Stock III_DP.cpp ├── LC1319_Number of Operations to Make Network Connected_Disjoint Set.cpp ├── LC131_Palindrome Partitioning_Backtracking.cpp ├── LC132_Palindrome Partitioning II_DP.py ├── LC1337_The K Weakest Rows in a Matrix_Naive Algorithm.cpp ├── LC133_Clone Graph_BFS.cpp ├── LC133_Clone Graph_Graph.py ├── LC134_Gas Station_Naive Algorithm.cpp ├── LC134_Gas Station_Naive Algorithm.py ├── LC135_Candy_Greedy Algorithm.cpp ├── LC136_Single Number_Bit Operation.cpp ├── LC136_Single Number_Math.cpp ├── LC139_Word Break v2_DP.cpp ├── LC139_Word Break_DP.cpp ├── LC139_Word Break_DP.py ├── LC141_Linked List Cycle_Double Pointer.cpp ├── LC1423_Maximum Points You Can Obtain from Cards_Sliding Window.cpp ├── LC142_Linked List Cycle II_Double Pointer.cpp ├── LC144_Binary Tree Preorder Traversal_Recursion.py ├── LC145_Binary Tree Postorder Traversal_Recursion.py ├── LC1486_XOR Operation in an Array_Naive Algorithm.cpp ├── LC148_Sort List_Merge Sort.py ├── LC14_Longest Common Prefix_String Manipulation.java ├── LC1502_Can Make Arithmetic Progression From Sequence_Math.cpp ├── LC150_Evaluate Reverse Polish Notation_Stack.cpp ├── LC151_Reverse Words in a String_Double Pointer.cpp ├── LC152_Maximum Product Subarray_DP.cpp ├── LC153_Find Minimum in Rotated Sorted Array_Binary Search.c ├── LC153_Find Minimum in Rotated Sorted Array_Binary Search.cpp ├── LC154_Find Minimum in Rotated Sorted Array II_Binary Search.cpp ├── LC1584_Min Cost to Connect All Points_Graph.cpp ├── LC15_Three Sum_AC.py ├── LC15_Three Sum_Break Time Limit.py ├── LC1603_Design Parking System_Naive Algorithm.cpp ├── LC160_Intersection of Two Linked Lists_Double Pointer.cpp ├── LC160_Intersection of Two Linked Lists_Double Pointer.java ├── LC162_Find Peak Element_BinarySearch.java ├── LC1631_Path With Minimum Effort_Disjoint Set.cpp ├── LC169_Majority Element_Boyer–Moore Majority Vote Algorithm.cpp ├── LC169_Majority Element_Hash Table.cpp ├── LC169_Majority Element_Hash Table.py ├── LC173_Binary Search Tree Iterator_Recursion.cpp ├── LC179_Largest Number_String Manipulation.cpp ├── LC17_Letter Combinations of a Phone Number_Backtracking.cpp ├── LC1818_Minimum Absolute Sum Difference_BinarySearch.java ├── LC188_Best Time to Buy and Sell Stock IV_DP.cpp ├── LC189_Rotate Array_Brain Teaser.cpp ├── LC18_4Sum_Double Pointer.cpp ├── LC190_Reverse Bits_Math.cpp ├── LC191_Number of 1 Bits_Bit Operation.cpp ├── LC198_House Robber_DP.cpp ├── LC198_House Robber_DP.java ├── LC198_House Robber_DP.py ├── LC199_Binary Tree Right Side View_BFS.cpp ├── LC19_Remove Nth Node From End of List_Double Pointer.cpp ├── LC1_Two Sum_Hash Table.py ├── LC200_Num Islands_Disjoint Set.py ├── LC203_Remove Linked List Elements_Linked List.cpp ├── LC204_Count Primes_Sieve of Eratosthenes.cpp ├── LC206_Reverse List.py ├── LC207_Course Schedule_BFS.cpp ├── LC208_Implement Trie (Prefix Tree) v2_Trie.cpp ├── LC208_Implement Trie (Prefix Tree)_Trie.cpp ├── LC20_Check Brackets_Queue.py ├── LC20_Check Brackets_Stack.py ├── LC210_Course Schedule II_BFS.cpp ├── LC213_House Robber II_DP.cpp ├── LC215_Kth Largest Element in an Array_Heap.cpp ├── LC216_Combination Sum III_Backtracking.cpp ├── LC217_Contains Duplicate_Set.cpp ├── LC21_Merge Two Sorted Lists_Double Pointer.py ├── LC21_Merge Two Sorted Lists_Recursion.cpp ├── LC21_Merge Two Sorted Lists_Recursion.java ├── LC21_Merge Two Sorted Lists_Recursion.py ├── LC221_Maximal Square_DP.cpp ├── LC221_Maximal Square_DP.java ├── LC221_Maximal Square_DP.py ├── LC222_Count Complete Tree Nodes_BFS.cpp ├── LC224_Basic Calculator_Stack.cpp ├── LC226_Invert Binary Tree_Recursion.java ├── LC226_Invert Binary Tree_Recursion.py ├── LC227_Basic Calculator II_Stack.cpp ├── LC228_Summary Ranges_Naive Algorithm.cpp ├── LC229_Majority Element II_Boyer–Moore Majority Vote Algorithm.cpp ├── LC229_Majority Element II_Hash Table.cpp ├── LC22_Generate Parentheses_DP.cpp ├── LC232_Implement Queue using Stacks_Stack.cpp ├── LC234_Palindrome Linked List_Linked List.cpp ├── LC235_Lowest Common Ancestor of a Binary Search Tree_Recursion.cpp ├── LC236_Lowest Common Ancestor of a Binary Tree_Recursion.cpp ├── LC238_Product of Array Except Self_Math.py ├── LC239_Sliding Window Maximum_Heap.cpp ├── LC239_Sliding Window Maximum_Queue.cpp ├── LC240_Search a 2D Matrix II_Naive Algorithm.cpp ├── LC257_Binary Tree Paths_Recursion.cpp ├── LC263_Ugly Number_Naive Algorithm.cpp ├── LC263_Ugly Number_Naive Algorithm.java ├── LC264_Ugly Number II_DP.py ├── LC264_Ugly Number II_Math.cpp ├── LC268_Missing Number_Bit Operation.cpp ├── LC26_Remove Duplicates from Sorted Array_Double Pointer.cpp ├── LC26_Remove Duplicates from Sorted Array_Double Pointer.java ├── LC279_Perfect Squares_DP.cc ├── LC279_Perfect Squares_DP.py ├── LC27_Remove Element_Double Pointer.cpp ├── LC283_Move Zeroes_Double Pointer.cpp ├── LC287_Find the Duplicate Number_Set.java ├── LC28_Implement strStr()_KMP.cpp ├── LC2_Add Two Numbers.py ├── LC300_Longest Increasing Subsequence_DP.cpp ├── LC303_Range Sum Query - Immutable_Math.py ├── LC304_Range Sum Query 2D - Immutable_Math.py ├── LC307_Range Sum Query - Mutable_BIT.java ├── LC309_Best Time to Buy and Sell Stock with Cooldown_DP.cpp ├── LC319_Bulb Switcher_Brain Teaser.cpp ├── LC322_Coin Change.py ├── LC327_Count of Range Sum_Segment Tree.cpp ├── LC331_Verify Preorder Serialization of a Binary Tree_Brain Teaser.py ├── LC332_Reconstruct Itinerary_Backtracking.cpp ├── LC337_House Robber III_DP.cpp ├── LC338_Counting Bits_DP.cpp ├── LC33_Search in Rotated Sorted Array_Binary Search.cpp ├── LC33_Search in Rotated Sorted Array_Binary Search.java ├── LC343_Integer Break_DP.cpp ├── LC343_Integer Break_Math.py ├── LC344_Reverse String_Naive Algorithm.cpp ├── LC344_Reverse String_Naive Algorithm.py ├── LC347_Top K Frequent Elements_Heap.cpp ├── LC34_Find First and Last Position of Element in Sorted Array_Binary Search.cpp ├── LC354_Russian Doll Envelopes_DP.cpp ├── LC35_Search Insert Position_Binary Search.cpp ├── LC376_Wiggle Subsequence_Greedy Algorithm.cpp ├── LC377_Combination Sum IV_DP.cpp ├── LC37_Sudoku Solver_Backtracking.cpp ├── LC389_Find the Difference_ASCII.cpp ├── LC389_Find the Difference_Bit Operation.cpp ├── LC392_Is Subsequence_DP.cpp ├── LC39_Combination Sum_Backtracking.cpp ├── LC3_Length Of Longest Substring_Sliding Window.py ├── LC404_Sum of Left Leaves_BFS.cpp ├── LC406_Queue Reconstruction by Height_Greedy Algorithm.cpp ├── LC407_Trap Rain Water II_Heap Sort.py ├── LC40_Combination Sum II_Backtracking.cpp ├── LC412_Fizz Buzz_Naive Algorithm.py ├── LC416_Partition Equal Subset Sum.py ├── LC416_Partition Equal Subset Sum_DP.cpp ├── LC421_Maximum XOR of Two Numbers in an Array_Trie.cpp ├── LC424_Longest Repeating Character Replacement_Double Pointer.cpp ├── LC429_N-ary Tree Level Order Traversal_BFS.cpp ├── LC42_Trapping Rain Water I_Double Pointer.py ├── LC42_Trapping Rain Water I_Naive Algorithm_Break Time Limit.java ├── LC435_Non-overlapping Intervals_Greedy Algorithm.cpp ├── LC447_Number of Boomerangs_Naive Algorithm.cpp ├── LC448_Find All Numbers Disappeared in an Array_Brain Teaser.cpp ├── LC448_Find All Numbers Disappeared in an Array_Brain Teaser.java ├── LC450_Delete Node in a BST_Recursion.cpp ├── LC452_Minimum Number of Arrows to Burst Balloons_Greedy Algorithm.cpp ├── LC454_4Sum II_Hash Table.cpp ├── LC455_Assign Cookies_Greedy Algorithm.cpp ├── LC456_132 Pattern_Stack.py ├── LC459_Repeated Substring Pattern_KMP.cpp ├── LC45_Jump Game II_Greedy Algorithm.cpp ├── LC461_Hamming Distance_Bit Operation.cpp ├── LC46_Permutations_Backtracking.cpp ├── LC474_Ones and Zeroes_DP.cpp ├── LC477_Total Hamming Distance_Bit Operation.cpp ├── LC477_Total Hamming Distance_Bit Operation.py ├── LC47_Permutations II_Backtracking.cpp ├── LC480_Sliding Window Median_Sliding Window.cpp ├── LC485_Max Consecutive Ones_Naive Algorithm.cpp ├── LC485_Max Consecutive Ones_Naive Algorithm.py ├── LC48_Rotate Image_Math.cpp ├── LC491_Increasing Subsequences_Backtracking I.cpp ├── LC491_Increasing Subsequences_Backtracking II.cpp ├── LC494_Target Sum_DP.cpp ├── LC4_Find Median Sorted Arrays_Quick Sort.py ├── LC501_Find Mode in Binary Search Tree_Hash Table.cpp ├── LC503_Next Greater Element II_Stack.cpp ├── LC509_Fibonacci Number_DP.py ├── LC50_Pow(x, n)_Math.py ├── LC513_Find Bottom Left Tree Value_BFS.cpp ├── LC515_Find Largest Value in Each Tree Row_BFS.cpp ├── LC516_Longest Palindromic Subsequence_DP.cpp ├── LC518_Coin Change 2_DP.cpp ├── LC518_Coin ChangeII_DP.py ├── LC51_N-Queens_Backtracking.cpp ├── LC530_Minimum Absolute Difference in BST_Recursion.cpp ├── LC538_Convert BST to Greater Tree_Recursion.cpp ├── LC53_Maximum Subarray v2_DP.cpp ├── LC53_Maximum Subarray_DP.cpp ├── LC541_Reverse String II_Naive Algorithm.cpp ├── LC543_Diameter of Binary Tree_Recursion.cpp ├── LC547_Number of Provinces_Disjoint Set.cpp ├── LC547_Social Circle.py ├── LC54_Spiral Matrix_Naive Algorithm.java ├── LC559_Maximum Depth of N-ary Tree_BFS.cpp ├── LC55_Jump Game_Greedy Algorithm.cpp ├── LC561_Array Partition I_Brain Teaser.cpp ├── LC561_Array Partition I_Brain Teaser.py ├── LC566_Reshape the Matrix_Naive Algorithm.cpp ├── LC56_Merge Intervals_Greedy Algorithm.cpp ├── LC583_Delete Operation for Two Strings_DP.cpp ├── LC589_N-ary Tree Preorder Traversal_Recursion.cpp ├── LC589_N-ary Tree Preorder Traversal_Recursion.py ├── LC590_N-ary Tree Postorder Traversal_BFS.cpp ├── LC59_Spiral Matrix II_Naive Algorithm.py ├── LC5_Longest Palindrome_DP.py ├── LC605_Can Place Flowers_Greedy Algorithm.cpp ├── LC611_Valid Triangle Number_Double Pointer.cpp ├── LC611_Valid Triangle Number_Double Pointer.java ├── LC617_Merge Two Binary Trees_Recursion.cpp ├── LC61_Ans1.png ├── LC61_Ans2.png ├── LC61_Rotate List_Double Pointer.cpp ├── LC628_Maximum Product of Three Numbers_Math.cpp ├── LC62_Unique Paths_Math.cpp ├── LC62_Unique Paths_Math.py ├── LC637_Average of Levels in Binary Tree_BFS.cpp ├── LC63_Unique Paths II_DP.cpp ├── LC643_Maximum Average Subarray I_Sliding Window.cpp ├── LC647_Palindromic Substrings_Center Expansion.c ├── LC647_Palindromic Substrings_Center Expansion.cpp ├── LC647_Palindromic Substrings_Center Expansion.java ├── LC647_Palindromic Substrings_Center Expansion.py ├── LC647_Palindromic Substrings_DP.cpp ├── LC647_Palindromic Substrings_Double Pointer.cpp ├── LC648_Replace Words_String Manipulation.cpp ├── LC64_Minimum Path Sum_DP.cpp ├── LC64_Minimum Path Sum_DP.java ├── LC64_Minimum Path Sum_DP.py ├── LC654_Maximum Binary Tree_Recursion.cpp ├── LC665_Non-decreasing Array_Naive Algorithm.cpp ├── LC669_Trim a Binary Search Tree_Recursion.cpp ├── LC66_Plus One_Math.java ├── LC674_Longest Continuous Increasing Subsequence_DP.cpp ├── LC674_Longest Continuous Increasing Subsequence_Naive Algorithm.py ├── LC67_Add Binary_Bit Operation.py ├── LC684_Redundant Connection_Disjoint Set.cpp ├── LC697_Degree of an Array_Hash Table.cpp ├── LC69_Sqrt(x)_Math.cpp ├── LC700_Search in a Binary Search Tree_Recursion.cpp ├── LC701_Insert into a Binary Search Tree_Recursion.cpp ├── LC705_Design HashSet_HashTable.java ├── LC706_Design HashMap_HashTable.java ├── LC707_Design Linked List_Linked List.cpp ├── LC714_Ans.jpg ├── LC714_Best Time to Buy and Sell Stock with Transaction Fee_DP.cpp ├── LC714_Best Time to Buy and Sell Stock with Transaction Fee_DP.java ├── LC718_Maximum Length of Repeated Subarray_DP.cpp ├── LC724_Find Pivot Index_Math.cpp ├── LC72_Edit Distance.py ├── LC72_Edit Distance_DP.cpp ├── LC738_Monotone Increasing Digits_Greedy Algorithm.cpp ├── LC739_Daily Temperatures_Stack.cpp ├── LC73_Set Matrix Zeroes_Naive Algorithm.cpp ├── LC746_Min Cost Climbing Stairs_DP.cpp ├── LC74_Search a 2D Matrix_Binary Search.cpp ├── LC74_Search a 2D Matrix_Naive Algorithm.cpp ├── LC75_Sort Colors_Double Pointer.cpp ├── LC763_Partition Labels_Greedy Algorithm.cpp ├── LC765_Couples Holding Hands_Bit Operation.cpp ├── LC765_Couples Holding Hands_Bit Operation.py ├── LC766_Toeplitz Matrix_Naive Algorithm.cpp ├── LC778_Swim in Rising Water_Disjoint Set.cpp ├── LC77_Combinations_Backtracking.cpp ├── LC781_Rabbits in Forest_Greedy Algorithm.cpp ├── LC783_Minimum Distance Between BST Nodes v2_Recursion.cpp ├── LC783_Minimum Distance Between BST Nodes v3_Recursion.cpp ├── LC783_Minimum Distance Between BST Nodes_Recursion.cpp ├── LC78_Subsets_Backtracking.cpp ├── LC79_Word Search_Backtracking.py ├── LC7_Reverse Integer_Math.cpp ├── LC80_Remove Duplicates from Sorted Array II_Brain Teaser.cpp ├── LC80_Remove Duplicates from Sorted Array II_Double Pointer.cpp ├── LC812_Largest Triangle Area_Math.java ├── LC81_Search in Rotated Sorted Array II_Binary Search.cpp ├── LC82_Remove Duplicates from Sorted List II_Linked List.cpp ├── LC830_Positions of Large Groups_Naive Algorithm.cpp ├── LC83_Remove Duplicates from Sorted List_Linked List.cpp ├── LC84_Largest Rectangle in Histogram_Stack.py ├── LC85_Maximal Rectangle_Stack.py ├── LC860_Lemonade Change_Greedy Algorithm.cpp ├── LC867_Transpose Matrix_Math.cpp ├── LC885_Spiral Matrix III_Naive Algorithm.py ├── LC888_Fair Candy Swap_Math.cpp ├── LC88_Merge Sorted Array_Double Pointer.py ├── LC896_Monotonic Array (API)_Naive Algorithm.cpp ├── LC896_Monotonic Array_Naive Algorithm.cpp ├── LC90_ClimbStairs.py ├── LC90_Subsets II_Backtracking.cpp ├── LC912_Sort an Array_Heap Sort.cpp ├── LC912_Sort an Array_Quick Sort.cpp ├── LC912_Sort an Array_Quick Sort.py ├── LC91_Decode Ways_DP.cpp ├── LC92_Reverse Linked List II_Linked List.cpp ├── LC93_Restore IP Addresses_Backtracking.cpp ├── LC941_Valid Mountain Array_Double Pointer.cpp ├── LC947_Most Stones Removed with Same Row or Column_Disjoint Set.cpp ├── LC94_Binary Tree Inorder Traversal_Recursion.cpp ├── LC94_Binary Tree Inorder Traversal_Recursion.py ├── LC968_Binary Tree Cameras_Greedy Algorithm.cpp ├── LC96_Unique Binary Search Trees_Math.cpp ├── LC96_Unique Binary Search Trees_Math.java ├── LC976_Largest Perimeter Triangle_Math.cpp ├── LC989_Add to Array-Form of Integer_Math.cpp ├── LC98_Validate Binary Search Tree_Recursion.cpp ├── LC995_Minimum Number of K Consecutive Bit Flips_Sliding Window.cpp ├── LC9_Palindrome Number_Math.cpp ├── POJ1000_A+B Problem_Naive Algorithm.cpp ├── POJ1004_Financial Management_Naive Algorithm.cpp ├── POJ3264_Balanced Lineup_Segment Tree.cpp ├── README.md ├── Solution ├── LC1004_Ans.jpg ├── LC11.jpg ├── LC134.jpg ├── LC134_Ans.jpg ├── LC15_Solution.md ├── LC204_Ans.jpg ├── LC21_Ans.jpg ├── LC238_Ans.jpg ├── LC304_Ans1.jpg ├── LC304_Ans2.jpg ├── LC392_Ans1.jpg ├── LC392_Ans2.jpg ├── LC406_Ans.jpg ├── LC459_Ans.jpg ├── LC47解题思路.png ├── LC50_Ans1.jpg ├── LC50_Ans2.jpg ├── LC543_Ans_1.jpg ├── LC543_Ans_2.jpg ├── LC5_Ans.jpg ├── LC61_Ans1.png ├── LC61_Ans2.png ├── LC647.jpg ├── LC647_Ans.jpg ├── LC669_Ans.jpg ├── LC714_Ans.jpg ├── LC778_Ans.gif ├── LC91_Ans.png ├── LC92_Ans.gif ├── LC947_Ans1.png ├── LC947_Ans2.png ├── LC947_Ans3.png ├── LC947_Ans4.png ├── LC947_Ans5.png ├── LC96_Ans.jpg ├── LC995.jpg ├── 二叉树所有遍历模板及知识点总结.py ├── 动态规划-问题思考方向.png └── 递归的调用过程.jpg ├── Sort.md ├── Subdocument ├── Backtracking.md ├── Dynamic Programming.md ├── Graph Theory.md ├── Interesting Stuff.md ├── Math Theory.md ├── Sort.md └── Tree.md ├── 剑指 Offer 10- II_青蛙跳台阶问题_DP.cpp ├── 剑指 Offer 10- II_青蛙跳台阶问题_DP.py ├── 剑指 Offer 10- II_青蛙跳台阶问题_Recursion_Break Time Limit.py ├── 剑指 Offer 49_Ugly Number_DP.py ├── 剑指 Offer 58 - II_左旋转字符串_脑筋急转弯.cpp ├── 剑指Offer 05_替换空格_Double Pointer.cpp ├── 剑指Offer_03_数组中重复的数字_Hash Table.cpp ├── 剑指Offer_04_二维数组中的查找_Math.cpp ├── 剑指Offer_06_从尾到头打印链表_Linked List.cpp ├── 剑指Offer_09_用两个栈实现队列_Stack.py ├── 剑指Offer_10-I_斐波那契数列_DP.py ├── 剑指Offer_11_旋转数组的最小数字_Binary Search.cpp ├── 剑指Offer_12_矩阵中的路径_Backtracking.cpp ├── 剑指Offer_14 - I_剪绳子_Math.py ├── 剑指Offer_15_Number of 1 Bits_Bit Operation.cpp ├── 剑指Offer_17_打印从1到最大的n位数_Math.cpp ├── 剑指Offer_18_删除链表的节点_Linked List.cpp ├── 剑指Offer_21_调整数组顺序使奇数位于偶数前面_Double Pointer.cpp ├── 剑指Offer_22_链表中倒数第k个节点_Double Pointer.cpp ├── 剑指Offer_24_反转链表_Stack.py ├── 剑指Offer_28_对称的二叉树_Recursion.cpp ├── 剑指Offer_29_顺时针打印矩阵_Naive Algorithm.py ├── 剑指Offer_32 - II_从上到下打印二叉树 II_BFS.cpp ├── 剑指Offer_32 - I_从上到下打印二叉树_BFS.cpp ├── 剑指Offer_39_数组中出现次数超过一半的数字_Boyer–Moore Majority Vote Algorithm.cpp ├── 剑指Offer_40_最小的k个数_Sort.cpp ├── 剑指Offer_42_Maximum Subarray_DP.cpp ├── 剑指Offer_45_把数组排成最小的数_String Manipulation.cpp ├── 剑指Offer_50_第一个只出现一次的字符_Hash Table.cpp ├── 剑指Offer_53 - I_在排序数组中查找数字 I_Hash Table.cpp ├── 剑指Offer_53-II_0~n-1中缺失的数字_Naive Algorithm.cpp ├── 剑指Offer_54_二叉搜索树的第k大节点_Recursion.cpp ├── 剑指Offer_55-II_平衡二叉树_Recursion.py ├── 剑指Offer_56 - I_数组中数字出现的次数_Bit Operation.cpp ├── 剑指Offer_57_和为s的两个数字_Double Pointer.py ├── 剑指Offer_59 - I_滑动窗口的最大值_Queue.cpp ├── 剑指Offer_63_股票的最大利润_DP.cpp ├── 剑指Offer_64_求1+2+…+n_Math.cpp ├── 剑指Offer_64_求1+2+…+n_Math.py ├── 剑指Offer_65_不用加减乘除做加法_Bit Operation.cpp ├── 剑指Offer_66_构建乘积数组_Math.py ├── 剑指offer_25_Merge Two Sorted Lists_Double Pointer.py ├── 剑指offer_68 - II_Lowest Common Ancestor of a Binary Tree_Recursion.cpp ├── 剑指offer_68 - I_Lowest Common Ancestor of a Binary Search Tree_Iteration.cpp ├── 程序员面试金典17.04_Missing Number_Bit Operation.cpp ├── 程序员面试金典17.21_直方图的水量_Double Pointer.c ├── 程序员面试金典17.21_直方图的水量_Double Pointer.cpp ├── 程序员面试金典17.21_直方图的水量_Double Pointer.java └── 程序员面试金典17.21_直方图的水量_Double Pointer.py /LC1004_Max Consecutive Ones III_Sliding Window.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int longestOnes(vector& A, int K) { // 滑动窗口 4 | int result = 0, left = 0, zeros = 0; // 初始化 5 | for (int right = 0; right < A.size(); right++) { // 右指针移动 6 | if (A[right] == 0) zeros++; // 遇到0,0的数量加1 7 | while (zeros > K) { // 当零的数量大于K的时候 8 | if (A[left] == 0) { // 如果左指针对应的是0 9 | zeros--; // 0的数量减一 10 | } 11 | left++; // 左指针“被迫”右移 12 | } 13 | result = max(result, right - left + 1); // 维护最大值即可 14 | } 15 | return result; 16 | } 17 | }; 18 | 19 | // 思路详见Solution中的截图 -------------------------------------------------------------------------------- /LC1005_Maximize Sum Of Array After K Negations_Greedy Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | static bool cmp(int a, int b) { // 注意是abs比较 3 | return abs(a) > abs(b); 4 | } 5 | public: 6 | int largestSumAfterKNegations(vector& A, int K) { 7 | sort(A.begin(), A.end(), cmp); // 排序,从大到小 8 | for (int i = 0; i < A.size(); i++) { 9 | if (A[i] < 0 && K > 0) { // 有负数并且还有翻转的机会时 10 | A[i] *= -1; // 从大到小对负数进行翻转 11 | K--; // 机会-1 12 | } 13 | } 14 | while (K--) A[A.size() - 1] *= -1; // 当机会比需求更多时,那就不停地在最小数处翻转,反正损失也最小 15 | int result = 0; 16 | for (int a : A) result += a; // 收集最后的各个数字,求和即可 17 | return result; 18 | } 19 | }; 20 | 21 | // reference https://mp.weixin.qq.com/s/dMTzBBVllRm_Z0aaWvYazA -------------------------------------------------------------------------------- /LC1006_Clumsy Factorial_Stack.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int clumsy(int N) { 4 | vector st; // 可以使用vector来模拟栈,后面可以使用accumulate函数求和 5 | st.push_back(N); // 第一个元素入栈 6 | N--; // 变成第二个元素 7 | int count = 0; // 计数器,用来判断加减乘除运算 8 | while (N > 0) { // 下面判断各个数之间应该进行何种运算 9 | if (count % 4 == 0) { // 乘法,栈顶元素和新元素相乘, 10 | // 之后覆盖原本栈顶元素即可,即为“入栈” 11 | st.back() *= N; 12 | } else if (count % 4 == 1) { // 除法,操作同乘法 13 | st.back() /= N; 14 | } else if (count % 4 == 2) { // 加法,此时元素入栈 15 | st.push_back(N); 16 | } else { 17 | st.push_back(-N); // 减法,此时元素取相反数入栈 18 | } 19 | count++; 20 | N--; // 得到下一个元素 21 | } 22 | return accumulate(st.begin(), st.end(), 0); // 最后,对栈中元素求和 23 | } 24 | }; 25 | 26 | // reference https://leetcode-cn.com/problems/clumsy-factorial/solution/ben-jie-cheng-by-leetcode-solution-deh2/ -------------------------------------------------------------------------------- /LC100_Same Tree_DFS.c: -------------------------------------------------------------------------------- 1 | bool isSameTree(struct TreeNode* p, struct TreeNode* q) { 2 | if (p == NULL && q == NULL) { 3 | return true; 4 | } else if (p == NULL || q == NULL) { 5 | return false; 6 | } else if (p->val != q->val) { 7 | return false; 8 | } else { 9 | return isSameTree(p->left, q->left) && isSameTree(p->right, q->right); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /LC100_Same Tree_DFS.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode() : val(0), left(nullptr), right(nullptr) {} 8 | * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 9 | * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} 10 | * }; 11 | */ 12 | class Solution { 13 | public: 14 | bool isSameTree(TreeNode* p, TreeNode* q) { 15 | if(p==nullptr && q==nullptr){ 16 | return true; 17 | } 18 | else if(p==nullptr || q==nullptr){ 19 | return false; 20 | } 21 | else if(p->val!=q->val){ 22 | return false; 23 | } 24 | else{ 25 | return isSameTree(p->left,q->left) && isSameTree(p->right,q->right); 26 | } 27 | } 28 | }; -------------------------------------------------------------------------------- /LC100_Same Tree_DFS.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public boolean isSameTree(TreeNode p, TreeNode q) { 3 | if (p == null && q == null) { 4 | return true; 5 | } else if (p == null || q == null) { 6 | return false; 7 | } else if (p.val != q.val) { 8 | return false; 9 | } else { 10 | return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /LC100_Same Tree_DFS.py: -------------------------------------------------------------------------------- 1 | # Definition for a binary tree node. 2 | # class TreeNode: 3 | # def __init__(self, val=0, left=None, right=None): 4 | # self.val = val 5 | # self.left = left 6 | # self.right = right 7 | class Solution: 8 | def isSameTree(self, p: TreeNode, q: TreeNode) -> bool: 9 | if p is None and q is None: 10 | return True 11 | elif p is None or q is None: 12 | return False 13 | elif p.val!=q.val: 14 | return False 15 | else: 16 | return self.isSameTree(p.left,q.left) and self.isSameTree(p.right,q.right) -------------------------------------------------------------------------------- /LC1018_Binary Prefix Divisible By 5_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector prefixesDivBy5(vector& A) { // 数学题 4 | vector result; 5 | long long val = 0; // int就可以了 6 | for (int i = 0; i < A.size(); i++) { 7 | val = ((val << 1) + A[i]) % 5; // 其实我们只关心余数,所以取余再进行后续运算即可。 8 | // 本题的难点就在于此,如果不这么操作,即使是long long类型的数据,也会溢出。这样做可以 9 | // 保证结果依然正确,因为我们只关心余数。结论的证明见链接中内容。 10 | result.push_back(val == 0); 11 | } 12 | return result; 13 | } 14 | }; 15 | 16 | // reference https://leetcode-cn.com/problems/binary-prefix-divisible-by-5/solution/ke-bei-5-zheng-chu-de-er-jin-zhi-qian-zh-asih/ -------------------------------------------------------------------------------- /LC101_Symmetric Tree_Recursion.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | bool check(TreeNode* p,TreeNode* q) { 13 | if(!p && !q) return true; 14 | if(!p || !q) return false; 15 | return (p->val) == (q->val) && check(p->left,q->right) && check(p->right,q->left); 16 | } 17 | public: 18 | bool isSymmetric(TreeNode* root){ 19 | return check(root,root); 20 | } 21 | }; 22 | 23 | // reference https://leetcode-cn.com/problems/symmetric-tree/solution/dui-cheng-er-cha-shu-by-leetcode-solution/ 24 | // 我们可以实现这样一个递归函数,通过「同步移动」两个指针的方法来遍历这棵树,pp 指针和 qq 指针一开始都指向这棵树的根,随后 pp 右移时, 25 | // qq 左移,pp 左移时,qq 右移。每次检查当前 pp 和 qq 节点的值是否相等,如果相等再判断左右子树是否对称。 26 | // 用镜像对称方法,假装是两棵树,用两个指针移动实现比较。 27 | -------------------------------------------------------------------------------- /LC102_Binary Tree Level Order Traversal_BFS.py: -------------------------------------------------------------------------------- 1 | # Definition for a binary tree node. 2 | class TreeNode: 3 | def __init__(self, x): 4 | self.val = x 5 | self.left = None 6 | self.right = None 7 | 8 | class Solution: 9 | def levelOrder(self, root): 10 | if not root: return [] 11 | cur,res = [root],[] 12 | while cur: 13 | lay,layval = [],[] 14 | for node in cur: 15 | layval.append(node.val) 16 | if node.left: lay.append(node.left) 17 | if node.right: lay.append(node.right) 18 | cur = lay 19 | res.append(layval) 20 | return res 21 | root = TreeNode(10) 22 | root.left = TreeNode(5) 23 | root.right = TreeNode(2) 24 | root.left.left = TreeNode(6) 25 | res = Solution() 26 | print(res.levelOrder(root)) 27 | 28 | # reference https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/python3-er-cha-shu-suo-you-bian-li-mo-ban-ji-zhi-s/ 29 | 30 | -------------------------------------------------------------------------------- /LC1035_Uncrossed Lines_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxUncrossedLines(vector& A, vector& B) { // 本题虽然看上去很抽象,但其实仔细分析,就是求最长公共子串 4 | vector> dp(A.size() + 1, vector(B.size() + 1, 0)); // 初始化 dp含义见LC1143或LC718 5 | for (int i = 1; i <= A.size(); i++) { 6 | for (int j = 1; j <= B.size(); j++) { 7 | if (A[i - 1] == B[j - 1]) { // 同LC1143 8 | dp[i][j] = dp[i - 1][j - 1] + 1; 9 | } else { 10 | dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); 11 | } 12 | } 13 | } 14 | return dp[A.size()][B.size()]; 15 | } 16 | }; 17 | 18 | // reference https://mp.weixin.qq.com/s/krfYzSYEO8jIoVfyHzR0rw 19 | // 本题基本和LC1143一致 -------------------------------------------------------------------------------- /LC1038_Convert BST to Greater Tree_Recursion.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode() : val(0), left(nullptr), right(nullptr) {} 8 | * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 9 | * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} 10 | * }; 11 | */ 12 | class Solution { 13 | private: 14 | int pre = 0; 15 | void traversal(TreeNode* root) { 16 | if (root == nullptr) return; 17 | traversal(root->right); 18 | root->val += pre; 19 | pre = root->val; 20 | traversal(root->left); 21 | } 22 | public: 23 | TreeNode* bstToGst(TreeNode* root) { 24 | if (root == nullptr) return nullptr; 25 | traversal(root); 26 | return root; 27 | } 28 | }; 29 | 30 | // 和LC538相同 -------------------------------------------------------------------------------- /LC1046_Last Stone Weight_Heap.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int lastStoneWeight(vector& stones) { 4 | priority_queue maxheap; 5 | for (int s : stones) { 6 | maxheap.push(s); 7 | } 8 | while (maxheap.size() > 1) { 9 | int p = maxheap.top(); 10 | maxheap.pop(); 11 | int q = maxheap.top(); 12 | maxheap.pop(); 13 | if (p > q) maxheap.push(p - q); 14 | } 15 | return maxheap.empty() ? 0 : maxheap.top(); 16 | } 17 | }; 18 | 19 | // 大顶堆的使用 20 | /* 21 | 如何想到这题是堆? 22 | 首先,堆有排序的作用;再者,这边的石块可能粉碎之后要继续进入数组,也就是说,如果单单是排序,一直调用sort函数也不是个办法。 23 | 那有什么东西可以拿出来就能用,用完了就丢进去?只能是堆了,所以用大顶堆。 24 | */ -------------------------------------------------------------------------------- /LC1047_Remove All Adjacent Duplicates In String_Stack.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string removeDuplicates(string S) { // 本题用栈实现 4 | stack st; // 是char类型! 5 | for(char s : S){ // 类Python语法 6 | if(st.empty() || s != st.top()){ // 待输入元素和栈顶元素比较,如果相同,直接让栈顶元素出栈。反之,让待入栈元素入栈。 7 | st.push(s); 8 | }else{ 9 | st.pop(); 10 | } 11 | } 12 | string result; 13 | while(!st.empty()){ 14 | result += st.top(); // 类Python语法,char字符相加 15 | st.pop(); 16 | } 17 | reverse(result.begin(),result.end()); // 反转,因为栈是FILO 18 | return result; 19 | } 20 | }; 21 | 22 | // reference https://mp.weixin.qq.com/s/eynAEbUbZoAWrk0ZlEugqg -------------------------------------------------------------------------------- /LC1047_Remove All Adjacent Duplicates In String_String Manipulation.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string removeDuplicates(string S) { // C++中,string有类似于队列的性质。 4 | string stack; // 用普通的string来模拟stack的操作 5 | for (char ch : S) { 6 | if (!stack.empty() && stack.back() == ch) { // 如果顶层元素和要加入的元素相等 7 | stack.pop_back(); // 那么把顶部的元素弹出,并且不让当前元素进入string。这样一来,可以删去两个重复的元素,比如aa 8 | } else { 9 | stack.push_back(ch); // 和顶层元素不相等,那么入栈 10 | } 11 | } 12 | return stack; 13 | } 14 | }; 15 | 16 | // https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/solution/shan-chu-zi-fu-chuan-zhong-de-suo-you-xi-4ohr/ -------------------------------------------------------------------------------- /LC104_Maximum Depth of Binary Tree_Recursion.c: -------------------------------------------------------------------------------- 1 | int maxDepth(struct TreeNode *root) { 2 | if (root == NULL) return 0; 3 | return fmax(maxDepth(root->left), maxDepth(root->right)) + 1; 4 | } 5 | /** 6 | * Definition for a binary tree node. 7 | * struct TreeNode { 8 | * int val; 9 | * struct TreeNode *left; 10 | * struct TreeNode *right; 11 | * }; 12 | */ 13 | -------------------------------------------------------------------------------- /LC104_Maximum Depth of Binary Tree_Recursion.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxDepth(TreeNode* root) { 4 | if (root == nullptr) return 0; 5 | return max(maxDepth(root->left), maxDepth(root->right)) + 1; 6 | } 7 | }; 8 | 9 | /** 10 | * Definition for a binary tree node. 11 | * struct TreeNode { 12 | * int val; 13 | * TreeNode *left; 14 | * TreeNode *right; 15 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 16 | * }; 17 | */ -------------------------------------------------------------------------------- /LC104_Maximum Depth of Binary Tree_Recursion.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int maxDepth(TreeNode root) { 3 | if (root == null) { 4 | return 0; 5 | } else { 6 | int leftHeight = maxDepth(root.left); 7 | int rightHeight = maxDepth(root.right); 8 | return Math.max(leftHeight, rightHeight) + 1; 9 | } 10 | } 11 | } 12 | 13 | /** 14 | * Definition for a binary tree node. 15 | * public class TreeNode { 16 | * int val; 17 | * TreeNode left; 18 | * TreeNode right; 19 | * TreeNode(int x) { val = x; } 20 | * } 21 | */ -------------------------------------------------------------------------------- /LC104_Maximum Depth of Binary Tree_Recursion.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Wed Nov 4 13:33:17 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | # Definition for a binary tree node. 9 | class TreeNode: 10 | def __init__(self, x): 11 | self.val = x 12 | self.left = None 13 | self.right = None 14 | 15 | 16 | class Solution: 17 | def maxDepth(self, root): 18 | if root is None: 19 | return 0 20 | return max(self.maxDepth(root.left),self.maxDepth(root.right)) + 1 21 | 22 | root = TreeNode(3) 23 | root.left = TreeNode(10) 24 | res = Solution() 25 | print(res.maxDepth(root)) 26 | -------------------------------------------------------------------------------- /LC107_Binary Tree Level Order Traversal II_BFS.py: -------------------------------------------------------------------------------- 1 | # Definition for a binary tree node. 2 | # class TreeNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.left = None 6 | # self.right = None 7 | 8 | class Solution: 9 | def levelOrderBottom(self, root: TreeNode) -> List[List[int]]: 10 | 11 | if not root: return [] 12 | cur,res = [root],[] 13 | while cur: 14 | lay,layval = [],[] 15 | for node in cur: 16 | layval.append(node.val) 17 | if node.left: lay.append(node.left) 18 | if node.right: lay.append(node.right) 19 | cur = lay 20 | res.append(layval) 21 | return list(reversed(res)) 22 | # 相较于102,加一个 list(reversed(res)) 的Python内置方法即可。这个方法就是用于反转list的。 -------------------------------------------------------------------------------- /LC1128_Number of Equivalent Domino Pairs_Hash Table.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int numEquivDominoPairs(vector>& dominoes) { // 哈希表加数学 4 | vector freq(100, 0); // 把数组当做哈希表,key是索引值,value是数组索引对应的数值。 5 | // 把数组当做哈希表的做法并不少见。此处key是多米诺骨牌有序数对中两个数从小到大排序下的十进制数 6 | // 比如[1,2]变成1*10 + 2 = 12;[2,1]变成[1,2]再变成1 * 10 + 2 = 12;此时判定是一对骨牌。因为对应数值大小相同 7 | // value就是上面的val(比如12)出现的频次。用result把各个次数加在一起,可以得到总的对数。 8 | int result = 0; 9 | int val; 10 | for (auto& it : dominoes) { 11 | val = it[0] < it[1] ? 10 * it[0] + it[1] : 10 * it[1] + it[0]; 12 | result += freq[val]; // 即使有三个多米诺骨牌可以互相成对,也可以有1 + 2 = 3对,也是成立的。 13 | freq[val]++; 14 | } 15 | return result; 16 | } 17 | }; 18 | 19 | // reference https://leetcode-cn.com/problems/number-of-equivalent-domino-pairs/solution/deng-jie-duo-mi-nuo-gu-pai-dui-de-shu-li-yjlz/ -------------------------------------------------------------------------------- /LC112_Path Sum_Recursion.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { // 递归 11 | public: 12 | bool hasPathSum(TreeNode* root, int sum) { 13 | if(root == nullptr) return false; 14 | if(root->left == nullptr && root->right == nullptr) return sum == root->val; 15 | return hasPathSum(root->left, sum - root->val) || hasPathSum(root->right, sum - root->val); 16 | 17 | } 18 | }; 19 | 20 | // reference https://leetcode-cn.com/problems/path-sum/solution/lu-jing-zong-he-by-leetcode-solution/ -------------------------------------------------------------------------------- /LC1137_N-th Tribonacci Number_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int tribonacci(int n) { // 滚动数组 4 | if (n == 0) return 0; 5 | if (n == 1) return 1; 6 | if (n == 2) return 1; 7 | vector dp(3, 1); 8 | dp[0] = 0; 9 | int result = 2; 10 | for (int i = 3; i < n; i++) { 11 | dp[i % 3] = result; 12 | result = accumulate(dp.begin(), dp.end(), 0); // 注意accumulate的使用!最后需要加一个0 13 | } 14 | return result; 15 | } 16 | }; -------------------------------------------------------------------------------- /LC1143_Longest Common Subsequence_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int longestCommonSubsequence(string text1, string text2) { // 动态规划 最长公共子序列 4 | vector> dp(text1.size() + 1, vector(text2.size() + 1, 0)); // 初始化 5 | // dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]。这样的定义有助于下面的递推公式 6 | for (int i = 1; i <= text1.size(); i++) { // 从1开始 7 | for (int j = 1; j <= text2.size(); j++) { 8 | if (text1[i - 1] == text2[j - 1]) { // 如果当前字符相同 9 | dp[i][j] = dp[i - 1][j - 1] + 1; // 长度加1 10 | } else { 11 | dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); // 否则找一个max值即可。这里需要好好理解添加一个新的字符之后,变化的情况 12 | } 13 | } 14 | } 15 | return dp[text1.size()][text2.size()]; 16 | } 17 | }; 18 | 19 | // reference https://mp.weixin.qq.com/s/Qq0q4HaE4TyasCTj2WGFOg 20 | // 总的来说,本题和LC718很像,可以一起写 -------------------------------------------------------------------------------- /LC1143_longestCommonSubsequence.py: -------------------------------------------------------------------------------- 1 | def longestCommonSubsequence(text1, text2, m, n): 2 | 3 | if m==0 or n==0: 4 | return 0 5 | elif text1[m-1] == text2[n-1]: 6 | return 1 + longestCommonSubsequence(text1, text2, m-1, n-1) 7 | else: 8 | return max(longestCommonSubsequence(text1, text2, m-1, n),longestCommonSubsequence(text1, text2, m, n-1)) 9 | 10 | m = int(input()) 11 | text1 = [int(x) for x in input().split()] 12 | n = int(input()) 13 | text2 = [int(x) for x in input().split()] 14 | #text1 = "abcde" 15 | #text2 = "ace" 16 | 17 | print(longestCommonSubsequence(text1, text2, len(text1), len(text2))) -------------------------------------------------------------------------------- /LC1143_longestCommonSubsequence_DP.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sun Aug 23 01:03:52 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | def longestCommonSubsequence(text1, text2): 9 | m = len(text1) 10 | n = len(text2) 11 | dp = [[0]*(n+1) for _ in range(m+1)] 12 | 13 | for i in range(1,m+1): 14 | for j in range(1,n+1): 15 | if text1[i-1] == text2[j-1]: 16 | dp[i][j] = 1 + dp[i-1][j-1] 17 | else: 18 | dp[i][j] = max(dp[i-1][j],dp[i][j-1]) 19 | return dp[m][n] 20 | m = int(input()) 21 | text1 = [int(x) for x in input().split()] 22 | n = int(input()) 23 | text2 = [int(x) for x in input().split()] 24 | print(longestCommonSubsequence(text1, text2)) 25 | 26 | -------------------------------------------------------------------------------- /LC118_Pascal's Triangle_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> generate(int numRows) { 4 | vector> triYangHui(numRows); // 先定义好杨辉三角的行数,此时还没有对应列数 5 | for (int i = 0; i < numRows; i++) { 6 | triYangHui[i].resize(i + 1); // 针对每一行,让其对应不同的列数。这时候三角形成型。所以构建这种结构,可以用两个vector实现 7 | triYangHui[i][0] = triYangHui[i][i] = 1; 8 | for (int j = 1; j < i; j++) triYangHui[i][j] = triYangHui[i - 1][j - 1] + triYangHui[i - 1][j]; 9 | } 10 | return triYangHui; 11 | } 12 | }; 13 | 14 | // reference https://leetcode-cn.com/problems/pascals-triangle/solution/yang-hui-san-jiao-by-leetcode-solution-lew9/ 15 | // 每个数字等于上一行的左右两个数字之和,可用此性质写出整个杨辉三角。即第 n 行的第 i 个数等于第 n-1 行的第 i-1 个数和第 i 个数之和。 16 | -------------------------------------------------------------------------------- /LC119_Pascal's Triangle II_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { // 数学题 2 | public: 3 | vector getRow(int rowIndex) { // 根据杨辉三角上下两行元素数值之间的递推关系,可以写出代码 4 | vector> C(rowIndex + 1); 5 | for (int i = 0; i <= rowIndex; ++i) { // 对每一行处理 6 | C[i].resize(i + 1); // 改大小 7 | C[i][0] = C[i][i] = 1; // 赋初值,显然杨辉三角每一行最左侧和右侧为1 8 | for (int j = 1; j < i; ++j) { 9 | C[i][j] = C[i - 1][j - 1] + C[i - 1][j]; // 递推公式 10 | } 11 | } 12 | return C[rowIndex]; 13 | } 14 | }; 15 | 16 | 17 | // reference https://leetcode-cn.com/problems/pascals-triangle-ii/solution/yang-hui-san-jiao-ii-by-leetcode-solutio-shuk/ 18 | -------------------------------------------------------------------------------- /LC11_Max Area_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxArea(vector& height) { 4 | int size = height.size(); 5 | int left=0, right=size-1; 6 | int ans = 0; 7 | while(left < right){ 8 | ans = max(ans, (right-left)*min(height[left], height[right])); 9 | if(height[left] > height[right]) --right; 10 | else ++left; 11 | } 12 | return ans; 13 | 14 | } 15 | }; 16 | 17 | // 解题思路和Python中相同,详见Python代码的注释。 18 | -------------------------------------------------------------------------------- /LC11_Max Area_Naive Algorithm.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Oct 30 22:45:38 2020 4 | 5 | @author: Three 6 | """ 7 | class Solution: 8 | def maxArea(self, height): 9 | size = len(height) 10 | max = 0 11 | l = 0 12 | r = size - 1 13 | while l < r: 14 | area = (r-l)*min(height[l],height[r]) 15 | if area >= max: 16 | max = area 17 | if height[l] > height[r]: 18 | r -= 1 19 | else: 20 | l += 1 21 | return max 22 | 23 | res = Solution() 24 | print(res.maxArea([1,8,6,2,5,4,8,3,7])) 25 | 26 | """ 27 | 对O(n)的算法写一下自己的理解,一开始两个指针一个指向开头一个指向结尾,此时容器的底是最大的, 28 | 接下来随着指针向内移动,会造成容器的底变小,在这种情况下想要让容器盛水变多,就只有在容器的高上下功夫。 29 | 那我们该如何决策哪个指针移动呢?我们能够发现不管是左指针向右移动一位,还是右指针向左移动一位, 30 | 容器的底都是一样的,都比原来减少了 1。这种情况下我们想要让指针移动后的容器面积增大, 31 | 就要使移动后的容器的高尽量大,所以我们选择指针所指的高较小的那个指针进行移动, 32 | 这样我们就保留了容器较高的那条边,放弃了较小的那条边,以获得有更高的边的机会。 33 | """ 34 | -------------------------------------------------------------------------------- /LC1208_Get Equal Substrings Within Budget_Sliding Window.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int equalSubstring(string s, string t, int maxCost) { // 双指针法,滑动窗口 4 | int left = 0; // 左边指针 5 | int cost = 0; // 开销 6 | for (int i = 0; i < s.size(); i++) { // 这里i的数值当做是右指针进行移动 7 | cost += abs(s[i] - t[i]); // 直接进行字母的ASCII码运算 8 | if (cost > maxCost) { // 滑窗的维护 9 | cost -= abs(s[left] - t[left]); 10 | left++; // 左指针移动 11 | } 12 | } 13 | return s.size() - left; // 输出长度即可。注意::这里不需要进行maxLen的维护。因为在移动过程中,最大长度会被保存下来。 14 | } 15 | }; 16 | 17 | // reference https://leetcode-cn.com/problems/get-equal-substrings-within-budget/solution/jin-ke-neng-shi-zi-fu-chuan-xiang-deng-b-higz/ 18 | // 关于不需要维护maxLen,可以详见链接中内容。 -------------------------------------------------------------------------------- /LC121_Best Time to Buy and Sell Stock_DP(Rolling Array).cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProfit(vector& prices) { // 滚动数组 这里可以使用滚动数组,是因为DP过程中,依赖的前序状态只是前一天的操作,所以%2处理即可,用这种方法不用浪费多余空间 4 | int len = prices.size(); 5 | vector> dp(2, vector(2)); // 注意这里只开辟了一个2 * 2大小的二维数组 6 | dp[0][0] -= prices[0]; 7 | dp[0][1] = 0; 8 | for (int i = 1; i < len; i++) { // DP思路和另一个关于本题的题解相同 9 | dp[i % 2][0] = max(dp[(i - 1) % 2][0], -prices[i]); 10 | dp[i % 2][1] = max(dp[(i - 1) % 2][1], prices[i] + dp[(i - 1) % 2][0]); 11 | } 12 | return dp[(len - 1) % 2][1]; 13 | } 14 | }; 15 | 16 | // 总结:滚动数组是一个DP中常用的trick,用于节省空间。因为DP是一个用空间换时间的方法。 -------------------------------------------------------------------------------- /LC121_Best Time to Buy and Sell Stock_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProfit(vector& prices) { // 动态规划 针对股票,无非就是买卖两种操作。所以dp在设置的时候需要设置成二维数组,分别对应第i天的买(0)或卖(1)操作。 4 | int len = prices.size(); 5 | vector> dp(len, vector(2)); 6 | dp[0][0] -= prices[0]; // 第一天买入 7 | dp[0][1] = 0; // 第一天没有持仓,所以就没有赎回 8 | for (int i = 1; i < len; i++) { 9 | dp[i][0] = max(dp[i - 1][0], -prices[i]); // 代表第i天买或者保持原有状态 10 | dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]); // 赎回或者是保持原状 11 | } 12 | return dp[len - 1][1]; // 值得注意的是,最后肯定是要出售,才可以接近最佳利润。最后不能烂在手里! 13 | } 14 | }; 15 | 16 | // reference https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ -------------------------------------------------------------------------------- /LC121_Best Time to Buy and Sell Stock_Naive Algorithm.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def maxProfit(self, prices: List[int]) -> int: 3 | MAX = 0 # 一种很常见的MAX与MIN的赋值方法 4 | MIN = int(1e9) # 取一个很大的值 5 | for price in prices: 6 | MAX = max(MAX,price - MIN) # 最大利润 7 | MIN = min(price,MIN) # 最小购入 8 | return MAX 9 | # https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/121-mai-mai-gu-piao-de-zui-jia-shi-ji-by-leetcode-/ -------------------------------------------------------------------------------- /LC122_Best Time to Buy and Sell Stock II_DP(Rolling Array).cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProfit(vector& prices) { // 滚动数组优化 4 | int len = prices.size(); 5 | vector> dp(2, vector(2)); // 注意这里只开辟了一个2 * 2大小的二维数组 6 | dp[0][0] -= prices[0]; 7 | dp[0][1] = 0; 8 | for (int i = 1; i < len; i++) { 9 | dp[i % 2][0] = max(dp[(i - 1) % 2][0], dp[(i - 1) % 2][1] - prices[i]); 10 | dp[i % 2][1] = max(dp[(i - 1) % 2][1], prices[i] + dp[(i - 1) % 2][0]); 11 | } 12 | return dp[(len - 1) % 2][1]; 13 | } 14 | }; -------------------------------------------------------------------------------- /LC122_Best Time to Buy and Sell Stock II_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProfit(vector& prices) { // 动态规划 本题和LC121基本一致,唯一不同在于“可以多次交易”,但每次交易只能一笔股票。 4 | int len = prices.size(); 5 | vector> dp(len, vector(2, 0)); 6 | dp[0][0] -= prices[0]; // 关于动归的思路完全是一致的 7 | dp[0][1] = 0; 8 | for (int i = 1; i < len; i++) { 9 | dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]); // 注意这里是和121. 买卖股票的最佳时机唯一不同的地方。不同的原因在于可以多次交易 10 | dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]); 11 | } 12 | return dp[len - 1][1]; 13 | } 14 | }; 15 | 16 | // reference https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w -------------------------------------------------------------------------------- /LC122_Best Time to Buy and Sell Stock II_Greedy Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProfit(vector& prices) { // 贪心算法,将股票赚钱变成每两天进行交易的行为,贪心地加上所有为正值的利润,就是max profit 4 | int result = 0; 5 | for (int i = 1; i < prices.size(); i++){ 6 | result += max(prices[i] - prices[i - 1], 0); 7 | } 8 | return result; 9 | } 10 | }; 11 | 12 | // reference https://mp.weixin.qq.com/s/VsTFA6U96l18Wntjcg3fcg -------------------------------------------------------------------------------- /LC1232_Check If It Is a Straight Line_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool checkStraightLine(vector>& coordinates) { // 运用斜率解决,很简单,但有些小细节 4 | int n = coordinates.size(); 5 | for (int i = 1; i + 1 < n; i++) { // 细节1:相乘之后,数据会不会变得很大?别的题可能需要讨论,因为乘法需要考虑数据类型的大小范围;但是本题很幸运,不需要这么做。 6 | // 细节2:为什么是相乘不用相除? 两个原因:1.int类型除法运算怕出现地板除,我一般我不怎么用除法; 2.运用斜率,最大的问题是斜率等于无穷大的直线。在这根直线上, 7 | // 也是题目的范畴。所以如果是相除的方法,需要分类讨论。但如果是相乘,就不需要分类了,反正如果是垂直于x轴的直线,delta_x也等于0。 8 | if ((coordinates[i][1] - coordinates[i - 1][1]) * (coordinates[i + 1][0] - coordinates[i][0]) != (coordinates[i][0] - coordinates[i - 1][0]) * (coordinates[i + 1][1] - coordinates[i][1])) { 9 | return false; 10 | } 11 | } 12 | return true; 13 | } 14 | }; -------------------------------------------------------------------------------- /LC123_Best Time to Buy and Sell Stock III_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProfit(vector& prices) { 4 | if (prices.size() == 0) return 0; // 特判 5 | vector> dp(prices.size(), vector(5, 0)); // 这就是初始化了一个二维数组 6 | dp[0][0] = 0; // 初始化 7 | dp[0][1] = -prices[0]; 8 | dp[0][3] = -prices[0]; 9 | for (int i = 1; i < prices.size(); i++) { // 一天一共有五种状态 10 | dp[i][0] = dp[i - 1][0]; 11 | dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]); 12 | dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] + prices[i]); 13 | dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i]); 14 | dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]); 15 | } 16 | return dp[prices.size() - 1][4]; 17 | } 18 | }; 19 | 20 | // reference https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/solution/123-mai-mai-gu-piao-de-zui-jia-shi-ji-ii-zfh9/ 21 | // 参考链接中的内容非常清晰,建议去链接中查看题解 -------------------------------------------------------------------------------- /LC133_Clone Graph_Graph.py: -------------------------------------------------------------------------------- 1 | """ 2 | # Definition for a Node. 3 | class Node: 4 | def __init__(self, val = 0, neighbors = None): 5 | self.val = val 6 | self.neighbors = neighbors if neighbors is not None else [] 7 | """ 8 | 9 | class Solution: 10 | def cloneGraph(self, node: 'Node') -> 'Node': 11 | return deepcopy(node) -------------------------------------------------------------------------------- /LC134_Gas Station_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int canCompleteCircuit(vector& gas, vector& cost) { 4 | int rest = 0, run = 0, start = 0; 5 | for (int i = 0; i < gas.size(); ++i){ 6 | run += (gas[i] - cost[i]); 7 | rest += (gas[i] - cost[i]); 8 | if (run < 0){ 9 | start = i + 1; 10 | run = 0; 11 | } 12 | } 13 | return rest < 0 ? -1: start; 14 | } 15 | }; -------------------------------------------------------------------------------- /LC134_Gas Station_Naive Algorithm.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Nov 3 14:16:02 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | class Solution: 9 | def canCompleteCircuit(self, gas, cost): 10 | 11 | if not gas or not cost: # 特例判断 12 | return -1 13 | start = 0 14 | run = 0 15 | if(sum(gas)-sum(cost))<0: # 如果油量全部值没有消耗多,那肯定跑不完 16 | return -1 17 | else: 18 | for i in range(len(cost)): 19 | run += gas[i] - cost[i] 20 | if run < 0: # 进入这里油总量大于等于消耗,如果前半部分消耗小于0,后半部分一定要大于0才可以平衡 21 | start = i + 1 # 所以可以确定,加油站一定要在i的右边。油要储备足,才可以跑 22 | run = 0 # 每次run要更新为0,不然加油站右偏了 23 | return start 24 | 25 | res = Solution() 26 | print(res.canCompleteCircuit([1,2,3,4,5],[3,4,5,1,2])) 27 | 28 | # reference https://leetcode-cn.com/problems/gas-station/comments/ -------------------------------------------------------------------------------- /LC135_Candy_Greedy Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int candy(vector& ratings) { // 贪心算法 4 | vector candy(ratings.size(), 1); // 一开始,每个小孩手里都要有糖 5 | for (int i = 1; i < ratings.size(); i++) { // 从左到右,如果右边小孩得分高,右边小孩就要比左边小孩多一个糖 6 | if (ratings[i] > ratings[i - 1]) candy[i] = candy[i - 1] + 1; 7 | } 8 | for (int j = ratings.size() - 2; j >= 0; j--) { // 从右到左,如果左边小孩比右边小孩得分高,就应该比右边小孩多一个糖。但这是已经从左到右过的结果,因此, 9 | // 为了真正满足题目要求,此时糖果的更新要将从右到左的数量和本身从左到右的进行比较,较大者胜出。说明这个数值可以满足题目要求,同时也是最小满足要求的数值。 10 | if (ratings[j] > ratings[j + 1]) candy[j] = max(candy[j], candy[j + 1] + 1); // 注意:这是从右到左的处理。再次从左到右会更麻烦,先左到右,再从右返回到左比较符合逻辑。 11 | } 12 | int result = 0; // 统计糖果数 13 | for (int c : candy) { 14 | result += c; 15 | } 16 | return result; 17 | } 18 | }; 19 | 20 | // reference https://mp.weixin.qq.com/s/8MwlgFfvaNYmjGwjuMlETQ -------------------------------------------------------------------------------- /LC136_Single Number_Bit Operation.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int singleNumber(vector& nums) { // 异或运算,对所有进行异或运算,最终得到的就是结果。 4 | int ret = 0; 5 | for (auto e: nums) ret ^= e; 6 | return ret; 7 | } 8 | }; 9 | 10 | // reference https://leetcode-cn.com/problems/single-number/solution/zhi-chu-xian-yi-ci-de-shu-zi-by-leetcode-solution/ 11 | 12 | 13 | -------------------------------------------------------------------------------- /LC136_Single Number_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int singleNumber(vector& nums) { 4 | sort(nums.begin(), nums.end()); 5 | if (nums.size() == 1) return nums[0]; 6 | if (nums.size() == 2) return 0; 7 | int i = 1; 8 | while (i < nums.size()){ // 根据题目的要求,第一个出现落单的数字肯定是在排序后,两两比较不相等时前一个数字,所以取nums[i - 1],return即可。 9 | if (nums[i] != nums[i - 1]){ 10 | break; 11 | } 12 | i += 2; 13 | } 14 | return nums[i - 1]; 15 | } 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /LC139_Word Break v2_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool wordBreak(string s, vector& wordDict) { // 完全背包问题 4 | // 本题可以建模成完全背包问题,其中背包是string,物品是单词集合中的单词 5 | unordered_set wordSet(wordDict.begin(), wordDict.end()); // 得到单词集合 6 | vector dp(s.size() + 1, false); 7 | dp[0] = true; 8 | for (int i = 1; i <= s.size(); i++) { // 完全背包 因为本题不在乎排列还是组合,所以for循环的顺序正常就好。 9 | for (int j = 0; j < i; j++) { 10 | string wordSearch = s.substr(j, i - j); // 得到要搜寻的单词 11 | if (wordSet.find(wordSearch) != wordSet.end() && dp[j]) { // 如果单词可以找到,并且本身的dp[j]就是true,那么可知dp[i]也是true 12 | dp[i] = true; // 递推公式 尽管这样的递推不是很直观 13 | } 14 | } 15 | } 16 | return dp[s.size()]; 17 | } 18 | }; 19 | 20 | // reference https://mp.weixin.qq.com/s/3Spx1B6MbIYjS8YkVbByzA 21 | 22 | /* 23 | 注: 24 | 1. substr的用法:substr(起始位置,截取的个数) 25 | 2. wordSet.find(word) != wordSet.end() 的意思是:在wordset中找不到word这个单词 26 | */ -------------------------------------------------------------------------------- /LC139_Word Break_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool wordBreak(string s, vector& wordDict) { // 动态规划 本题思路和Python版相同 4 | vector dp(s.size() + 1, false); // 初始化 5 | dp[0] = true; 6 | for (int i = 0; i < s.size(); i++) { 7 | if (!dp[i]) continue; // 遇到没办法找到的,直接跳过 8 | for (auto& word : wordDict) { // 这里说明一个问题:加不加&有什么区别? 加上&就是引用(reference),可以加大效率,不是拷贝(copy)。 9 | if (i + word.size() <= s.size() && s.substr(i, word.size()) == word) { // substr的使用是: string.substr(position, length) 意思是截取从pos开始长为len的一段字符串 10 | dp[i + word.size()] = true; 11 | } 12 | } 13 | } 14 | return dp[s.size()]; 15 | } 16 | }; 17 | 18 | // reference https://leetcode-cn.com/problems/word-break/solution/dong-tai-gui-hua-ji-yi-hua-hui-su-zhu-xing-jie-shi/ -------------------------------------------------------------------------------- /LC139_Word Break_DP.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def wordBreak(self, s: str, wordDict: List[str]) -> bool: # 动态规划 3 | dp = [False] * (len(s) + 1) # 初始化为false,dp[i]表示前i个字母在单词表中是否存在 4 | dp[0] = True # 空的时候是true 5 | for i in range(len(s)): 6 | for j in range(i + 1, len(s) + 1): # 这个是在当下dp[i]的基础上,对之后的单词进行展望。 7 | if (dp[i] and (s[i : j] in wordDict)): # 要注意,这里有两个判断。从0开始时,对之后的第一个出现的dp[i]进行了踩坑。下一次进行这个语句 8 | # 就是那个第一个被踩坑的dp[i]。再者,这个语句第二个是对这个dp[i]之后的展望。找寻下一个踩坑位置。这种一个个找寻的方式就像是给单词加空格。 9 | # 这里的s[i:j],从i开始。具体原因可以从i=0时思考,这边确实要从0开始而不是i+1。此外,Python的切片处理不包含尾端的值。所以i:j实际是i到j-1 10 | # 所以j的循环要到len(s)+1而不是len(s) 11 | dp[j] = True 12 | return dp[-1] 13 | 14 | # reference https://leetcode-cn.com/problems/word-break/solution/dong-tai-gui-hua-ji-yi-hua-hui-su-zhu-xing-jie-shi/ -------------------------------------------------------------------------------- /LC141_Linked List Cycle_Double Pointer.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | bool hasCycle(ListNode *head) { 12 | ListNode* fast = head; 13 | ListNode* slow = head; 14 | while(fast != NULL && fast->next != NULL){ 15 | fast = fast->next->next; 16 | slow = slow->next; 17 | if(fast == slow){ 18 | return true; 19 | } 20 | } 21 | return false; 22 | } 23 | }; 24 | 25 | // 和LC142类似,比LC142简单。此处只用判断是否有环即可。有环就说明fast指针可以等于slow指针。 -------------------------------------------------------------------------------- /LC144_Binary Tree Preorder Traversal_Recursion.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Wed Nov 4 13:56:22 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | # Definition for a binary tree node. 9 | # class TreeNode: 10 | # def __init__(self, val=0, left=None, right=None): 11 | # self.val = val 12 | # self.left = left 13 | # self.right = right 14 | class Solution: 15 | def preorderTraversal(self, root: TreeNode) -> List[int]: 16 | 17 | if root is None: return [] 18 | 19 | return [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right) -------------------------------------------------------------------------------- /LC145_Binary Tree Postorder Traversal_Recursion.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Wed Nov 4 13:58:28 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | # Definition for a binary tree node. 9 | # class TreeNode: 10 | # def __init__(self, val=0, left=None, right=None): 11 | # self.val = val 12 | # self.left = left 13 | # self.right = right 14 | class Solution: 15 | def postorderTraversal(self, root: TreeNode) -> List[int]: 16 | if root is None: return [] 17 | return self.postorderTraversal(root.left) + self.postorderTraversal(root.right) + [root.val] -------------------------------------------------------------------------------- /LC1486_XOR Operation in an Array_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int xorOperation(int n, int start) { // 直接模拟 4 | int ans = 0; 5 | for (int i = 0; i < n; i++) { 6 | ans ^= (start + 2 * i); 7 | } 8 | return ans; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /LC14_Longest Common Prefix_String Manipulation.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public String longestCommonPrefix(String[] strs) { // 字符串处理 3 | // 思路简单:将第一个string设置成公共前缀,然后逐一和其他string比较,逐步减小公共子串的长度, 4 | // 如果最后还有公共部分,代表有公共前缀;反之则无,可以提前break 5 | if(strs.length == 0) 6 | return ""; 7 | String ans = strs[0]; 8 | for(int i = 1; i < strs.length; i++) { 9 | int j = 0; 10 | for(; j < ans.length() && j < strs[i].length(); j++) { 11 | if(ans.charAt(j) != strs[i].charAt(j)) 12 | break; 13 | } 14 | ans = ans.substring(0, j); 15 | if(ans.equals("")) 16 | return ans; 17 | } 18 | return ans; 19 | } 20 | } 21 | 22 | // reference https://leetcode-cn.com/problems/longest-common-prefix/solution/hua-jie-suan-fa-14-zui-chang-gong-gong-qian-zhui-b/ -------------------------------------------------------------------------------- /LC1502_Can Make Arithmetic Progression From Sequence_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool canMakeArithmeticProgression(vector& arr) { // 数学 4 | sort(arr.begin(), arr.end()); 5 | for (int i = 1; i < arr.size() - 1; ++i) { 6 | if (arr[i] * 2 != arr[i - 1] + arr[i + 1]) { 7 | return false; 8 | } 9 | } 10 | return true; 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /LC152_Maximum Product Subarray_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProduct(vector& nums) { // 动态规划 4 | int max1 = INT_MIN, max2 = 1, min2 = 1; // 初始化 max1用在最后的max中,防止0的中间插入;max2和min2用于DP,一步步查找min与max,这种表达式也是防止了0的出现的干扰 5 | for (int i = 0; i < nums.size(); i++) { 6 | if (nums[i] < 0 ) swap(max2, min2); // 这一点非常关键! 其实我们要求的是max,但是min也在一步步求值中保留下来。这是防止负数。一旦有负数,min与max就要翻转。 7 | max2 = max(nums[i], nums[i] * max2); // DP求max 8 | min2 = min(nums[i], nums[i] * min2); // 同时为防止负数,也要保留DP求min 9 | max1 = max(max1, max2); // 防止中间插0.这样做可以得到最终的最大值 10 | } 11 | return max1; 12 | } 13 | }; 14 | 15 | // reference https://leetcode-cn.com/problems/maximum-product-subarray/solution/hua-jie-suan-fa-152-cheng-ji-zui-da-zi-xu-lie-by-g/ -------------------------------------------------------------------------------- /LC153_Find Minimum in Rotated Sorted Array_Binary Search.c: -------------------------------------------------------------------------------- 1 | int findMin(int* nums, int numsSize){ // 二分搜索 2 | int left = 0; 3 | int right = numsSize - 1; 4 | while (right > left) { 5 | int mid = left + (right - left) / 2; 6 | if (nums[mid] > nums[right]) // 注意题目对于数组的递增要求与性质 7 | left = mid + 1; 8 | else 9 | right = mid; 10 | } 11 | return nums[left]; 12 | } -------------------------------------------------------------------------------- /LC153_Find Minimum in Rotated Sorted Array_Binary Search.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findMin(vector& nums) { // 二分搜索,本题是力扣154的简化版 4 | int left = 0; 5 | int right = nums.size() - 1; 6 | while (left < right) { 7 | int mid = left + (right - left) / 2; 8 | if (nums[mid] > nums[right]) // 注意数组原本是递增,后来在某节点断开重接而已! 9 | left = mid + 1; 10 | else 11 | right = mid; 12 | } 13 | return nums[left]; 14 | } 15 | }; -------------------------------------------------------------------------------- /LC154_Find Minimum in Rotated Sorted Array II_Binary Search.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findMin(vector& nums) { 4 | int left = 0, right = nums.size() - 1; 5 | while (left < right) { // 不取等号的二分法 6 | int mid = left + (right - left) / 2; 7 | if (nums[mid] < nums[right]) right = mid; 8 | else if (nums[mid] > nums[right]) left = mid + 1; 9 | else right--; // 这一步是为了去除重复出现的元素 10 | } 11 | return nums[left]; // right也可以,这时候left == right 12 | } 13 | }; 14 | 15 | // reference https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/solution/mian-shi-ti-11-xuan-zhuan-shu-zu-de-zui-xiao-shu-3/ 16 | // 具体的分类讨论见链接,是比较复杂的。本题是非典型的二分搜索,这样做比较“胆大”,需要仔细分析不同情况。 17 | // 本题和剑指offer_11一样 -------------------------------------------------------------------------------- /LC15_Three Sum_Break Time Limit.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sun Oct 25 22:50:38 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | def threeSum(nums): 9 | 10 | hashmap = {} 11 | visited = [] 12 | obj = [0] * len(nums) 13 | 14 | for i in range(len(nums)): 15 | obj[i] = 0 - nums[i] 16 | 17 | for i,j in enumerate(nums): 18 | hashmap[j] = i 19 | 20 | for i in range(len(obj)): 21 | for j in range(len(nums)): 22 | if j == i: 23 | continue 24 | index = hashmap.get(obj[i] - nums[j]) 25 | if index is not None and index!=j and index!=i: 26 | res = [nums[i],nums[j],nums[index]] 27 | res.sort() 28 | if res not in visited: 29 | visited.append(res) 30 | 31 | return visited 32 | 33 | nums = [-1,0,1,2,-1,-4] 34 | #nums = [-1] 35 | print(threeSum(nums)) -------------------------------------------------------------------------------- /LC1603_Design Parking System_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class ParkingSystem { // 模拟法 2 | public: 3 | int b, m, s; 4 | ParkingSystem(int big, int medium, int small): b(big), m(medium), s(small) {} 5 | 6 | bool addCar(int carType) { 7 | if (carType == 1) { 8 | if (b > 0) { 9 | b--; 10 | return true; 11 | } 12 | } else if (carType == 2) { 13 | if (m > 0) { 14 | m--; 15 | return true; 16 | } 17 | } else if (carType == 3) { 18 | if (s > 0) { 19 | s--; 20 | return true; 21 | } 22 | } 23 | return false; 24 | } 25 | }; 26 | 27 | // 本题用模拟法就可以求解,是一道使用C++ class的模板题 -------------------------------------------------------------------------------- /LC160_Intersection of Two Linked Lists_Double Pointer.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { // 双指针法 10 | public: 11 | ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { 12 | if (headA == nullptr || headB == nullptr) return nullptr; // 特判 13 | ListNode* pa = headA; // 双指针从A,B两个链表开头出发 14 | ListNode* pb = headB; 15 | while(pa != pb){ // 如果两个链表有交点,那么二者相等的位置就是交点;如果没有,那么就是NULL的位置,就是链表的末尾。 16 | pa = pa == nullptr ? headB : pa->next; // 这是因为两个指针的移动速度相同,分别让两个指针在A+B的范围上移动,如果有交点,那就是相等的时候。因为路程和速度相同。 17 | pb = pb == nullptr ? headA : pb->next; // 本题将指针在链表上的移动过程建模成“追及问题”,很巧妙。 18 | } 19 | return pa; 20 | } 21 | }; 22 | 23 | // reference https://leetcode-cn.com/problems/intersection-of-two-linked-lists/solution/tu-jie-xiang-jiao-lian-biao-by-user7208t/ 详见链接 -------------------------------------------------------------------------------- /LC160_Intersection of Two Linked Lists_Double Pointer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * public class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode(int x) { 7 | * val = x; 8 | * next = null; 9 | * } 10 | * } 11 | */ 12 | public class Solution { 13 | public ListNode getIntersectionNode(ListNode headA, ListNode headB) { 14 | if (headA == null || headB == null) return null; 15 | ListNode pA = headA, pB = headB; 16 | while (pA != pB) { 17 | pA = pA == null ? headB : pA.next; 18 | pB = pB == null ? headA : pB.next; 19 | } 20 | return pA; 21 | } 22 | } 23 | 24 | // reference https://leetcode-cn.com/problems/intersection-of-two-linked-lists/solution/tu-jie-xiang-jiao-lian-biao-by-user7208t/ -------------------------------------------------------------------------------- /LC162_Find Peak Element_BinarySearch.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int findPeakElement(int[] nums) { // 二分搜索 3 | int left = 0, right = nums.length - 1; 4 | while (left < right) { 5 | int mid = left + (right - left) / 2; 6 | if (nums[mid] > nums[mid + 1]) { 7 | right = mid; 8 | } else { 9 | left = mid + 1; 10 | } 11 | } 12 | return left; 13 | } 14 | } 15 | 16 | // 本题是非典型的二分搜索,尽管数组是无序的,但不影响搜索结果 17 | // 当看到时间复杂度的要求是O(logn)时,就应该想到二分搜索 18 | 19 | // reference https://leetcode-cn.com/problems/find-peak-element/solution/hua-jie-suan-fa-162-xun-zhao-feng-zhi-by-guanpengc/ -------------------------------------------------------------------------------- /LC169_Majority Element_Boyer–Moore Majority Vote Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution{ 2 | public: 3 | int majorityElement(vector& nums) { // 本方法叫做摩尔投票法 4 | int res = 0, moleVote = 0; 5 | for(int i : nums){ 6 | if(moleVote == 0){ // 如果票数为0,那么换一个元素 7 | res = i; 8 | } 9 | moleVote += i == res ? 1 : -1; // 进行投票,如果有一个元素是绝大多数,那么它经得起这样投票 10 | } 11 | return res; 12 | } 13 | }; 14 | 15 | // reference https://leetcode-cn.com/problems/majority-element/solution/zi-jie-ti-ku-169-jian-dan-duo-shu-yuan-su-1shua-by/ -------------------------------------------------------------------------------- /LC169_Majority Element_Hash Table.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int majorityElement(vector& nums) { 4 | unordered_map map; 5 | int result; 6 | for(int i = 0; i < nums.size(); i++){ // 这一步是hash表常用方法,很经典 7 | map[nums[i]]++; 8 | if(map[nums[i]] > nums.size() / 2){ // 如果已经判断是最多元素,那么直接不用比,输出结果就好 9 | result = nums[i]; 10 | break; 11 | } 12 | } 13 | return result; 14 | } 15 | }; 16 | 17 | // reference https://leetcode-cn.com/problems/majority-element/solution/zi-jie-ti-ku-169-jian-dan-duo-shu-yuan-su-1shua-by/ 18 | 19 | // 注意:C/C++中,/如果前后是int类型,代表地板除。如果要更明确一些,可以用函数:floor()不大于自变量的最大整数,ceil()不小于自变量的最大整数,round()四舍五入到最邻近的整数 。 -------------------------------------------------------------------------------- /LC169_Majority Element_Hash Table.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def majorityElement(self, nums: List[int]) -> int: 3 | hashmap = {} 4 | for i in range(len(nums)): # 如果不这么赋初值,那么接下来的统计会报错。不同语言特点不同。如果用这样的方式统计,还是用C++较好 5 | hashmap[nums[i]] = 0 6 | for i in range(len(nums)): 7 | hashmap[nums[i]] = hashmap[nums[i]] + 1 8 | if hashmap[nums[i]] > len(nums) // 2: 9 | result = nums[i] 10 | break 11 | return result 12 | 13 | -------------------------------------------------------------------------------- /LC179_Largest Number_String Manipulation.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string largestNumber(vector& nums) { // 字符串处理,自定义排序 4 | if(nums.empty()) return ""; 5 | if(nums.size() == 1) return to_string(nums[0]); 6 | vector result; 7 | for(int i : nums) result.push_back(to_string(i)); // 数值变成字符串 8 | sort(result.begin(), result.end(), comparison); // 排序 9 | string ans = ""; // 用于放置最终结果。最终结果是排序后的内容拼接在一起 10 | for (int i = 0; i < result.size(); i++) ans += result[i]; 11 | if(ans[0] == '0') return "0"; // 0的时候应该输出0而不是000...,需要特殊判断!! 12 | return ans; 13 | } 14 | static bool comparison(string& a, string& b) // 本题的比较应该是字符串拼接之后的比较,原因详见链接 15 | { 16 | return a + b > b + a; 17 | } 18 | }; 19 | 20 | 21 | // reference https://leetcode-cn.com/problems/largest-number/solution/ju-yi-fan-er-bu-guang-you-zui-da-shu-hua-uykb/ 22 | -------------------------------------------------------------------------------- /LC189_Rotate Array_Brain Teaser.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void rotate(vector& nums, int k) { // 脑筋急转弯,找到移动和翻转间的关系 4 | k %= nums.size(); 5 | reverse(nums.begin(), nums.end()); 6 | reverse(nums.begin(),nums.begin() + k); 7 | reverse(nums.begin() + k, nums.end()); 8 | } 9 | }; -------------------------------------------------------------------------------- /LC190_Reverse Bits_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | uint32_t reverseBits(uint32_t n) { 4 | long res = 0; // 要用long,int会溢出 5 | for (int i = 0; i < 32; i++) { // 这一步和LC7——整数翻转的思路相同 6 | res = res * 2 + n % 2; 7 | n = n / 2; 8 | } 9 | return res; 10 | } 11 | }; 12 | 13 | // 这里特别强调!:这题跟整数翻转很像,所以好像代码可以直接复制。但是有一点特别不同,就是这里的二进制要求是32bit,翻转之后会把前面的零 14 | // 加在翻转后数字的末尾。也就是说,在十进制的时候,我们遇到第一个不为零的数开始翻转就好;但在这里,二进制都是32位,有的数并不是从非0数值开始 15 | // 而是要把前面的0都包括进去。所以在写循环的时候,要用for循环(如上),不要用LC7中的 while(y != 0) 的循环判断!! -------------------------------------------------------------------------------- /LC191_Number of 1 Bits_Bit Operation.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int hammingWeight(uint32_t n) { // 注意:是相与&!不是异或! 4 | if (n == 0) return 0; 5 | int count = 0; 6 | while (n != 0) { 7 | n &= n - 1; 8 | count++; 9 | } 10 | return count; 11 | } 12 | }; 13 | 14 | // 本题和汉明距离很像,可以一起写。解题思路详见hamming距离 -------------------------------------------------------------------------------- /LC198_House Robber_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int rob(vector& nums) { 4 | if (nums.size() == 0) return 0; // 特判 5 | if (nums.size() == 1) return nums[0]; 6 | vector dp(nums.size()); 7 | dp[0] = nums[0]; 8 | dp[1] = max(nums[0], nums[1]); // 第一次进行选择地偷盗 9 | for (int i = 2; i < nums.size(); i++) { 10 | dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]); // 状态转移 11 | } 12 | return dp[nums.size() - 1]; 13 | } 14 | }; 15 | 16 | // reference https://mp.weixin.qq.com/s/UZ31WdLEEFmBegdgLkJ8Dw 17 | -------------------------------------------------------------------------------- /LC198_House Robber_DP.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int rob(int[] nums) { 3 | if (nums.length == 0) { 4 | return 0; 5 | } 6 | 7 | int N = nums.length; 8 | int[] dp = new int[N+1]; 9 | dp[0] = 0; 10 | dp[1] = nums[0]; 11 | for (int k = 2; k <= N; k++) { 12 | dp[k] = Math.max(dp[k-1], nums[k-1] + dp[k-2]); 13 | } 14 | return dp[N]; 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /LC198_House Robber_DP.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def rob(self, nums: List[int]) -> int: 3 | if not nums: return 0 4 | dp = [0]*(len(nums)+1) 5 | dp[1] = nums[0] 6 | 7 | for i in range(2,len(nums)+1): 8 | dp[i] = max(dp[i-1],dp[i-2]+nums[i-1]) # 数组索引分清,nums取i-1纯粹是索引要求 9 | 10 | return dp[len(nums)] 11 | 12 | # reference https://leetcode-cn.com/problems/house-robber/solution/dong-tai-gui-hua-jie-ti-si-bu-zou-xiang-jie-cjavap/ 13 | # dp用的是二维还是一维应分清 -------------------------------------------------------------------------------- /LC199_Binary Tree Right Side View_BFS.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | vector rightSideView(TreeNode* root) { 13 | queue q; 14 | vector res; 15 | if(root != NULL){ 16 | q.push(root); 17 | } 18 | while(!q.empty()){ 19 | int size = q.size(); 20 | for(int i=0;ileft) q.push(node->left); 24 | if(node->right) q.push(node->right); 25 | if(i==size-1) res.push_back(node->val); 26 | } 27 | } 28 | return res; 29 | } 30 | }; -------------------------------------------------------------------------------- /LC1_Two Sum_Hash Table.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Aug 29 14:22:20 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | def twoSum(target,nums): 9 | hashmap = {} 10 | for i,num in enumerate(nums): 11 | hashmap[num] = i 12 | for i,num in enumerate(nums): 13 | j = hashmap.get(target-num) 14 | if j is not None and j!=i: 15 | return [i,j] 16 | return "Failure" 17 | 18 | 19 | # nums = [2, 7, 11, 15], target = 9 20 | nums = [2, 7, 11, 15] 21 | target = 10 22 | print(twoSum(target,nums)) -------------------------------------------------------------------------------- /LC203_Remove Linked List Elements_Linked List.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* removeElements(ListNode* head, int val) { // 制作一个虚拟头结点,之后进行删除。因为怕删除的是头结点,所以在头结点之上设计一个虚拟节点 12 | ListNode* dummyHead = new ListNode(0); // 创建虚拟头结点 13 | dummyHead->next = head; // 要记得把虚拟头结点和真实头结点连上 14 | ListNode* cur = dummyHead; 15 | while(cur->next != NULL){ 16 | if(cur->next->val == val){ 17 | ListNode* temp = cur->next; 18 | cur->next = cur->next->next; 19 | delete temp; 20 | }else{ 21 | cur = cur->next; 22 | } 23 | } 24 | return dummyHead->next; // 设计了虚拟头结点,要记得return虚拟头结点的next 25 | } 26 | }; 27 | // reference https://mp.weixin.qq.com/s/slM1CH5Ew9XzK93YOQYSjA -------------------------------------------------------------------------------- /LC204_Count Primes_Sieve of Eratosthenes.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int countPrimes(int n) { // 厄拉多塞筛法,简称埃氏筛,也称素数筛 4 | vector nums(n, true); // 先默认都是质数 5 | int count = 0; // 统计质数个数 6 | for (int i = 2; i < n; i++) { // 从2开始,因为1不是质数也不是合数,此外,2是第一个质数,所以下面count直接++ 7 | if (nums[i] == true) { 8 | count++; 9 | for (int j = i + i; j < n; j += i) { // 代表以这个数为倍数的,小于n的所有数都被排除出质数序列,变成false 10 | nums[j] = false; // 变为false之后,也没有再处理的必要了 11 | } 12 | } 13 | } 14 | return count; // 返回质数个数 15 | } 16 | }; 17 | 18 | // reference https://leetcode-cn.com/problems/count-primes/solution/ji-shu-zhi-shu-bao-li-fa-ji-you-hua-shai-fa-ji-you/ 图解见链接或Solution -------------------------------------------------------------------------------- /LC20_Check Brackets_Queue.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Aug 29 01:50:44 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | # Python3 code to Check for 9 | # balanced parentheses in an expression 10 | def check(expression): 11 | 12 | open_tup = tuple('({[') 13 | close_tup = tuple(')}]') 14 | map = dict(zip(open_tup, close_tup)) 15 | queue = [] 16 | 17 | for i in expression: 18 | if i in open_tup: 19 | queue.append(map[i]) 20 | elif i in close_tup: 21 | if not queue or i != queue.pop(): 22 | return "Unbalanced" 23 | if not queue: 24 | return "Balanced" 25 | else: 26 | return "Unbalanced" 27 | 28 | # Driver code 29 | string = "{[]{()}}" 30 | print(string, "-", check(string)) 31 | 32 | string = "((()" 33 | print(string,"-",check(string)) -------------------------------------------------------------------------------- /LC20_Check Brackets_Stack.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Aug 22 02:05:30 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | def isValid(s) -> bool: 9 | #数据结构:栈 10 | stack = [] 11 | left = ['(','[','{'] 12 | right = [')',']','}'] 13 | for letter in s: 14 | if letter in left: 15 | stack.append(letter) 16 | if letter in right: 17 | pos = right.index(letter) 18 | #if后面的判断逻辑是有先后之分的,有时候这很重要!! 19 | if (len(stack)>0) and (left[pos] == stack[-1]): 20 | stack.pop() 21 | else: 22 | return False 23 | if len(stack) == 0: 24 | return True 25 | else: 26 | return False 27 | 28 | s = input() 29 | print(isValid(s)) -------------------------------------------------------------------------------- /LC215_Kth Largest Element in an Array_Heap.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | class myComparison { 3 | public: 4 | bool operator()(int left, int right) { 5 | return left > right; 6 | } 7 | }; 8 | public: 9 | int findKthLargest(vector& nums, int k) { // 堆 10 | priority_queue, myComparison> heap; // 小顶堆 11 | for (int num : nums) { 12 | heap.push(num); 13 | if (heap.size() > k) heap.pop(); 14 | } 15 | int result = heap.top(); 16 | return result; 17 | } 18 | }; -------------------------------------------------------------------------------- /LC216_Combination Sum III_Backtracking.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | private: 3 | vector> result; 4 | vector path; 5 | void backtracking(int k,int n,int index,int sum){ 6 | if(sum > n){ // 提前判断sum与n的关系,早做决断,剪枝 7 | return; 8 | } 9 | if(path.size()==k){ 10 | if(sum==n) result.push_back(path); 11 | return; 12 | } 13 | for(int i=index;i<=9-(k-path.size())+1;i++){ // 9-(k-path.size())+1 是剪枝,写9也可以 14 | sum += i; 15 | path.push_back(i); 16 | backtracking(k,n,i+1,sum); // 这里是i,不是index!这样可以保证没有重复 17 | sum -= i; 18 | path.pop_back(); 19 | } 20 | } 21 | public: 22 | vector> combinationSum3(int k, int n) { 23 | result.clear(); 24 | path.clear(); 25 | backtracking(k,n,1,0); 26 | return result; 27 | } 28 | }; 29 | 30 | // reference https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w 31 | -------------------------------------------------------------------------------- /LC217_Contains Duplicate_Set.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool containsDuplicate(vector& nums) { 4 | set nums2(nums.begin(), nums.end()); // set去重 5 | if (nums2.size() != nums.size()) return true; 6 | return false; 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /LC21_Merge Two Sorted Lists_Double Pointer.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.next = None 6 | 7 | class Solution: 8 | def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode: # 双指针法 9 | dummyHaed = cur = ListNode(0) # 先制作一个dummyHead,可以用于标记开头 10 | while l1 and l2: # 都不空的时候 11 | if l1.val < l2.val: # 哪个数字小,就把这个数字先放进新的链表中 12 | cur.next, l1 = l1, l1.next 13 | else: 14 | cur.next, l2 = l2, l2.next 15 | cur = cur.next 16 | cur.next = l1 if l1 else l2 # 这一行代表,当有一个链表结束了,那么因为各个链表是有序的,所以 17 | # 最终结果就把某个链表的剩余部分全部接下来就好了 18 | return dummyHaed.next 19 | -------------------------------------------------------------------------------- /LC21_Merge Two Sorted Lists_Recursion.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * public class ListNode { 4 | * int val; 5 | * ListNode next; 6 | * ListNode() {} 7 | * ListNode(int val) { this.val = val; } 8 | * ListNode(int val, ListNode next) { this.val = val; this.next = next; } 9 | * } 10 | */ 11 | class Solution { 12 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 13 | if (l1 == null) { 14 | return l2; 15 | } else if (l2 == null) { 16 | return l1; 17 | } else if (l1.val < l2.val) { 18 | l1.next = mergeTwoLists(l1.next, l2); 19 | return l1; 20 | } else { 21 | l2.next = mergeTwoLists(l1, l2.next); 22 | return l2; 23 | } 24 | 25 | } 26 | } -------------------------------------------------------------------------------- /LC21_Merge Two Sorted Lists_Recursion.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, val=0, next=None): 4 | # self.val = val 5 | # self.next = next 6 | class Solution: 7 | def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode: 8 | if l1 is None: 9 | return l2 10 | elif l2 is None: 11 | return l1 12 | elif l1.val>& matrix) { 4 | if (matrix.size() == 0 || matrix[0].size() == 0) { 5 | return 0; 6 | } 7 | int maxSide = 0; 8 | int rows = matrix.size(), columns = matrix[0].size(); 9 | vector> dp(rows, vector(columns)); 10 | for (int i = 0; i < rows; i++) { 11 | for (int j = 0; j < columns; j++) { 12 | if (matrix[i][j] == '1') { 13 | if (i == 0 || j == 0) { 14 | dp[i][j] = 1; 15 | } else { 16 | dp[i][j] = min(min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1; 17 | } 18 | maxSide = max(maxSide, dp[i][j]); 19 | } 20 | } 21 | } 22 | int maxSquare = maxSide * maxSide; 23 | return maxSquare; 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /LC221_Maximal Square_DP.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int maximalSquare(char[][] matrix) { 3 | int maxSide = 0; 4 | if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { 5 | return maxSide; 6 | } 7 | int rows = matrix.length, columns = matrix[0].length; 8 | int[][] dp = new int[rows][columns]; 9 | for (int i = 0; i < rows; i++) { 10 | for (int j = 0; j < columns; j++) { 11 | if (matrix[i][j] == '1') { 12 | if (i == 0 || j == 0) { 13 | dp[i][j] = 1; 14 | } else { 15 | dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1; 16 | } 17 | maxSide = Math.max(maxSide, dp[i][j]); 18 | } 19 | } 20 | } 21 | int maxSquare = maxSide * maxSide; 22 | return maxSquare; 23 | } 24 | } -------------------------------------------------------------------------------- /LC222_Count Complete Tree Nodes_BFS.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | int countNodes(TreeNode* root) { 13 | queue q; 14 | int result = 0; // 记得赋初值 15 | if(root != NULL){ 16 | q.push(root); 17 | } 18 | while(!q.empty()){ 19 | int size = q.size(); 20 | result += size; 21 | for(int i = 0; i < size; ++i){ 22 | TreeNode* node = q.front(); 23 | q.pop(); 24 | if(node->left) q.push(node->left); 25 | if(node->right) q.push(node->right); 26 | } 27 | } 28 | return result; 29 | } 30 | }; -------------------------------------------------------------------------------- /LC226_Invert Binary Tree_Recursion.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * public class TreeNode { 4 | * int val; 5 | * TreeNode left; 6 | * TreeNode right; 7 | * TreeNode(int x) { val = x; } 8 | * } 9 | */ 10 | class Solution { 11 | public TreeNode invertTree(TreeNode root) { 12 | //递归函数的终止条件,节点为空时返回 13 | if(root==null) { 14 | return null; 15 | } 16 | //下面三句是将当前节点的左右子树交换 17 | TreeNode tmp = root.right; 18 | root.right = root.left; 19 | root.left = tmp; 20 | //递归交换当前节点的 左子树 21 | invertTree(root.left); 22 | //递归交换当前节点的 右子树 23 | invertTree(root.right); 24 | //函数返回时就表示当前这个节点,以及它的左右子树 25 | //都已经交换完了 26 | return root; 27 | } 28 | } 29 | // reference https://leetcode-cn.com/problems/invert-binary-tree/solution/dong-hua-yan-shi-liang-chong-shi-xian-226-fan-zhua/ -------------------------------------------------------------------------------- /LC226_Invert Binary Tree_Recursion.py: -------------------------------------------------------------------------------- 1 | # Definition for a binary tree node. 2 | # class TreeNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.left = None 6 | # self.right = None 7 | 8 | class Solution: 9 | def invertTree(self, root: TreeNode) -> TreeNode: 10 | if not root: return None 11 | root.left,root.right = root.right,root.left 12 | self.invertTree(root.left) 13 | self.invertTree(root.right) 14 | return root 15 | # reference https://leetcode-cn.com/problems/invert-binary-tree/solution/dong-hua-yan-shi-liang-chong-shi-xian-226-fan-zhua/ -------------------------------------------------------------------------------- /LC228_Summary Ranges_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector summaryRanges(vector& nums) { // 模拟法,一次遍历 4 | vector result; 5 | int i = 0; 6 | int n = nums.size(); 7 | while (i < n) { 8 | int low = i; 9 | i++; 10 | while (i < n && nums[i] == nums[i - 1] + 1) { 11 | i++; 12 | } 13 | int high = i - 1; 14 | string temp = to_string(nums[low]); // to_string使用 15 | if (low < high) { 16 | temp.append("->"); // append方法使用 17 | temp.append(to_string(nums[high])); 18 | } 19 | result.push_back(temp); 20 | } 21 | return result; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /LC22_Generate Parentheses_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector generateParenthesis(int n) { // 动态规划 4 | if (n == 0) return {}; 5 | if (n == 1) return {"()"}; 6 | vector> dp(n + 1); 7 | dp[0] = {""}; // 注意,这里返回空的时候也要有"",因为函数是vector类型的 8 | dp[1] = {"()"}; // 特殊情况先写出来 9 | for (int i = 2; i <= n; i++) { 10 | for (int j = 0; j < i; j++) { // 以下就是各种情况的尝试。新增的括号从广义上说,只能是这两个位置 11 | for (string p : dp[j]) { 12 | for (string q : dp[i - 1 - j]) { 13 | string str = "(" + p + ")" + q; // 类Python语法 14 | dp[i].push_back(str); 15 | } 16 | } 17 | } 18 | } 19 | return dp[n]; 20 | } 21 | }; 22 | 23 | // reference https://leetcode-cn.com/problems/generate-parentheses/solution/zui-jian-dan-yi-dong-de-dong-tai-gui-hua-bu-lun-da/ 24 | // 详解见Solution中的LC22_Ans截图 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /LC234_Palindrome Linked List_Linked List.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { // 将链表变成数组,然后进行数组的回文判断即可。 10 | public: 11 | bool isPalindrome(ListNode* head) { 12 | vector vec; 13 | ListNode* cur = head; 14 | while (cur != NULL){ // 变数组 15 | vec.push_back(cur->val); 16 | cur = cur->next; 17 | } 18 | for (int i = 0, j = vec.size() - 1; i < j; i++, j--){ // 数组回文判断,i List[int]: 3 | res = [1] # 初始的1是很关键的,在后续理解索引值上很重要 4 | p = q = 1 5 | for i in range(len(nums) - 1): # 下三角矩阵,注意,这里取不到len(nums) - 1,只能到len(nums) - 2 6 | p *= nums[i] 7 | res.append(p) # 存入下三角数值的乘积 8 | for j in range(len(nums) - 1, 0, -1): # 上三角矩阵,取不到0 9 | q *= nums[j] 10 | res[j - 1] *= q # 合于一处就是乘积结果 11 | return res 12 | 13 | # reference https://leetcode-cn.com/problems/product-of-array-except-self/solution/product-of-array-except-self-shang-san-jiao-xia-sa/ 14 | # 具体解释见Solution中LC238_Ans的截图 -------------------------------------------------------------------------------- /LC240_Search a 2D Matrix II_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool searchMatrix(vector>& matrix, int target) { // 模拟法,从矩阵右上角元素开始。 4 | 5 | int column = matrix[0].size() - 1; // 列 6 | int row = 0; // 行 7 | while (row <= matrix.size() - 1 && column >= 0) { 8 | if (target == matrix[row][column]) { 9 | // 找到就直接返回 10 | return true; 11 | } else if (target < matrix[row][column]) { 12 | // 如果目标值小,那么下一步往左找 13 | column--; 14 | } else if (target > matrix[row][column]) { 15 | // 如果目标值大,那么下一步往下找 16 | row++; 17 | } 18 | } 19 | return false; // 没找到 20 | } 21 | }; 22 | 23 | // reference https://leetcode-cn.com/problems/search-a-2d-matrix-ii/solution/3chong-jie-fa-zui-hao-de-ji-bai-liao-100-5ozh/ -------------------------------------------------------------------------------- /LC263_Ugly Number_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isUgly(int num) { 4 | if(num==0) return false; 5 | while(1){ 6 | if(num==1) return true; 7 | if(num%2==0) num /= 2; 8 | else if(num%3==0) num /= 3; 9 | else if(num%5==0) num /= 5; 10 | else return false; 11 | } 12 | } 13 | }; -------------------------------------------------------------------------------- /LC263_Ugly Number_Naive Algorithm.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public boolean isUgly(int num) { 3 | if(num==0) return false; 4 | while(true){ 5 | if(num==1) return true; 6 | if(num%2==0) num/=2; 7 | else if(num%3==0) num/=3; 8 | else if(num%5==0) num/=5; 9 | else return false; 10 | } 11 | 12 | } 13 | } -------------------------------------------------------------------------------- /LC264_Ugly Number II_DP.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def nthUglyNumber(self, n: int) -> int: 3 | nums = [1] 4 | i2 = 0 5 | i3 = 0 6 | i5 = 0 7 | for i in range(1,1690): # 算出所有丑数(既然已经给出了范围) 8 | ugly = min(nums[i2] * 2,nums[i3] * 3,nums[i5] * 5) 9 | nums.append(ugly) 10 | if(nums[i] == nums[i2] * 2): i2 += 1 11 | if(nums[i] == nums[i3] * 3): i3 += 1 12 | if(nums[i] == nums[i5] * 5): i5 += 1 13 | return nums[n-1] 14 | # reference https://leetcode-cn.com/problems/ugly-number-ii/solution/chou-shu-ii-by-leetcode/ -------------------------------------------------------------------------------- /LC264_Ugly Number II_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int nthUglyNumber(int n) { // 数学,三指针 4 | vector nums; 5 | nums.push_back(1); 6 | int i2 = 0, i3 = 0, i5 = 0; 7 | for (int i = 1; i < n; i++) { // 算出所有丑数,直到所需的第n个为止 8 | int ugly = min(nums[i2] * 2, min(nums[i3] * 3,nums[i5] * 5)); // 从小到大,按照丑数定义收集丑数 9 | nums.push_back(ugly); // 将丑数放进结果数组中 10 | if(nums[i] == nums[i2] * 2) i2++; // 指针移动,从小到大地寻找丑数 11 | if(nums[i] == nums[i3] * 3) i3++; 12 | if(nums[i] == nums[i5] * 5) i5++; 13 | } 14 | return nums[n-1]; // 返回第n个丑数 15 | } 16 | }; 17 | 18 | 19 | // reference https://leetcode-cn.com/problems/ugly-number/solution/ti-yi-lei-jie-yi-wen-dai-ni-shua-san-dao-p0pm/ 20 | -------------------------------------------------------------------------------- /LC268_Missing Number_Bit Operation.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int missingNumber(vector& nums) { // 异或运算 这里对于异或的理解要从配对入手 能配对代表为0.并且任何数和0异或都是本身,这一点也很关键。 4 | int result = nums.size(); 5 | for (int i = 0; i < nums.size(); i++) { // 这里的意思是,将所有nums里面的index和value异或。此外,特别要注意的是,result一开始赋值要为n 6 | // 不然会出问题。 经过这样的计算,相同的数值都被配对,变成0. 0和那个孤立的数异或,又是得到它本身。这样一来,缺失的数可以从index或result 7 | // 等于n的初值得到。 8 | result ^= nums[i]; 9 | result ^= i; 10 | } 11 | return result; 12 | } 13 | }; 14 | 15 | // 对位运算可以从不同方面理解,能够从多方面理解,就可以更好地利用位运算得到精妙的答案。 -------------------------------------------------------------------------------- /LC26_Remove Duplicates from Sorted Array_Double Pointer.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int removeDuplicates(vector& nums) { 4 | int i = 0; 5 | for (int num : nums) { 6 | if (i < 1 || nums[i - 1] < num) nums[i++] = num; 7 | } 8 | return i; 9 | } 10 | }; 11 | 12 | 13 | // reference https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii/solution/ju-yi-fan-er-ni-zhen-de-zhen-de-zhi-de-x-eicz/ 14 | -------------------------------------------------------------------------------- /LC26_Remove Duplicates from Sorted Array_Double Pointer.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int removeDuplicates(int[] nums) { // 双指针法 3 | if (nums.length == 0) return 0; 4 | int i = 0; 5 | for (int j = 1; j < nums.length; j++) { 6 | if (nums[j] != nums[i]) { 7 | i++; 8 | nums[i] = nums[j]; 9 | } 10 | } 11 | return i + 1; // 统计个数并输出 12 | } 13 | } -------------------------------------------------------------------------------- /LC279_Perfect Squares_DP.cc: -------------------------------------------------------------------------------- 1 | // # -*- coding: utf-8 -*- 2 | // """ 3 | // Created on Mon Nov 2 13:35:02 2020 4 | 5 | // @author: Three 6 | // """ 7 | #include 8 | #include 9 | class Solution { 10 | public: 11 | int numSquares(int n) { 12 | vector v(n+1,INT_MAX); 13 | v[0] = 0; 14 | v[1] = 1; 15 | for(int i=2;i<=n;i++){ 16 | for(int j=1;i-j*j>=0;j++){ 17 | v[i] = min(v[i],v[i-j*j]+1); 18 | } 19 | } 20 | return v[n]; 21 | } 22 | }; 23 | 24 | Solution res; 25 | cout << res.numSquares(13); 26 | -------------------------------------------------------------------------------- /LC279_Perfect Squares_DP.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Nov 2 13:55:02 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | class Solution: 9 | def numSquares(self, n: int) -> int: 10 | inf = float("inf") 11 | dp = [inf]*(n+1) 12 | dp[0] = 0 13 | dp[1] = 1 14 | for i in range(2,n+1): 15 | j = 1 16 | while(i-j*j>=0): 17 | dp[i] = min(dp[i],dp[i-j*j]+1) # 动态规划 经典状态转移方程 类比找零钱 爬楼梯 18 | j += 1 19 | return dp[n] 20 | 21 | res = Solution() 22 | print(res.numSquares(12)) 23 | 24 | # reference https://leetcode-cn.com/problems/perfect-squares/comments/ -------------------------------------------------------------------------------- /LC283_Move Zeroes_Double Pointer.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void moveZeroes(vector& nums) { // 双指针法 4 | int len=nums.size(); 5 | int left = 0,right = 0; 6 | while(right seen = new HashSet(); 4 | for (int num : nums) { 5 | if (seen.contains(num)) { // lookup num 6 | return num; 7 | } 8 | seen.add(num); // insert 9 | } 10 | return -1; 11 | } 12 | } 13 | 14 | 15 | // reference https://leetcode-cn.com/problems/find-the-duplicate-number/solution/287-6chong-jie-fa-si-lu-xiang-xi-fen-xi-zong-jie-b/ -------------------------------------------------------------------------------- /LC300_Longest Increasing Subsequence_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int lengthOfLIS(vector& nums) { // 动态规划 dp[i]表示以nums[i]结尾的最长子序列长度 4 | if (nums.size() == 0) return 0; // 特判 5 | vector dp(nums.size(), 1); // dp初始化,每个数字自己都可以成为一个序列,所以长度为1 6 | for (int i = 0; i < nums.size(); i++) { 7 | for (int j = 0; j < i; j++) { 8 | if (nums[j] < nums[i]) dp[i] = max(dp[i], dp[j] + 1); // 如果小于,则可以加进序列中 9 | } 10 | } 11 | return *max_element(dp.begin(), dp.end()); // 返回vector里面的最大数值 12 | } 13 | }; 14 | 15 | // reference https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/zui-chang-shang-sheng-zi-xu-lie-dong-tai-gui-hua-2/ -------------------------------------------------------------------------------- /LC303_Range Sum Query - Immutable_Math.py: -------------------------------------------------------------------------------- 1 | class NumArray: # 前缀和 2 | 3 | def __init__(self, nums: List[int]): 4 | N = len(nums) 5 | self.preSum = [0] * (N + 1) 6 | for i in range(N): 7 | self.preSum[i + 1] = self.preSum[i] + nums[i] # 前缀和就是各项数值的累加,有点像GRE中的百分位数(percentile)的定义 8 | 9 | def sumRange(self, i: int, j: int) -> int: 10 | return self.preSum[j + 1] - self.preSum[i] # 基于前缀和的定义,可以用这种尾端和值减去前端和值的方法得到中间从i到j覆盖范围内的和值 11 | 12 | 13 | # Your NumArray object will be instantiated and called as such: 14 | # obj = NumArray(nums) 15 | # param_1 = obj.sumRange(i,j) 16 | 17 | -------------------------------------------------------------------------------- /LC319_Bulb Switcher_Brain Teaser.cpp: -------------------------------------------------------------------------------- 1 | class Solution { // 脑筋急转弯 2 | public: 3 | int bulbSwitch(int n) { 4 | return sqrt(n); // C++内置的sqrt函数就是向下取整的 5 | } 6 | }; 7 | 8 | // reference https://leetcode-cn.com/problems/bulb-switcher/solution/ru-guo-bu-shi-mo-ni-guo-cheng-bu-neng-tong-guo-shu/ 9 | /* 10 | 拿到题目首先想模拟n次开关过程,结果数据量太大超时了,27/35,n=99999. 11 | 12 | 于是转而观察某个位置,看看某个位置是怎样变化的,什么条件下会翻转 13 | 14 | 第18个灯泡会在1,2,3,6,9,18轮翻转。 15 | 第36个灯泡会在1,2,3,4,6,9,12,18,36轮翻转。 16 | 17 | 规律显而易见,只有在轮数是该位置因数的时候才会执行翻转操作。 18 | 19 | 于是我们回答了那个问题:只要找到该位置的所有因数个数,我们就知道该位置翻转了多少次。 20 | 21 | 更进一步的,除了完全平方数,因数都是成对出现的,这意味着实际起到翻转作用(0->1)的,只有 22 | 完全平方数而已。 23 | 24 | 此时任务已经大大简化,因为n个灯泡翻转n轮,我们只要看看到n位置,一共有多少个完全平方数即可。 25 | 26 | 注意:考察完全平方数有多少个,就求它的根号并向下取整即可。比如37,有6个。因为6*6都比它小,所以1*1,2*2,3*3...不在话下 27 | 因此是6个,即根号37向下取整。(0应该不算) 28 | */ -------------------------------------------------------------------------------- /LC322_Coin Change.py: -------------------------------------------------------------------------------- 1 | def CoinChange(amount,coins): 2 | dp = [float("inf")]*(amount+1) 3 | dp[0] = 0 4 | for i in range(amount+1): 5 | for j in range(len(coins)): 6 | dp[i] = min(dp[i],dp[i-coins[j]]+1) 7 | return dp[amount] if dp[amount] <= amount else -1 8 | 9 | 10 | amount = int(input()) 11 | coins = [int(x) for x in input().split()] 12 | 13 | print(CoinChange(amount,coins)) -------------------------------------------------------------------------------- /LC331_Verify Preorder Serialization of a Binary Tree_Brain Teaser.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def isValidSerialization(self, preorder: str) -> bool: # 脑筋急转弯 善于发现前序遍历的规律 3 | stack = [] 4 | for node in preorder.split(',') : 5 | stack.append(node) 6 | while (len(stack) >= 3 and stack[-1] == stack[-2] == '#' and stack[-3] != '#') : 7 | for i in range(3) : 8 | stack.pop() 9 | stack.append('#') 10 | return len(stack) == 1 and stack.pop() == '#' 11 | # reference https://leetcode-cn.com/problems/verify-preorder-serialization-of-a-binary-tree/solution/pai-an-jiao-jue-de-liang-chong-jie-fa-zh-66nt/ 12 | # 思路: 13 | # 具体操作流程示例如下: 14 | 15 | # 如输入: "9,3,4,#,#,1,#,#,2,#,6,#,#" ,当遇到 x # # 的时候,就把它变为 #。 16 | 17 | # 模拟一遍过程: 18 | 19 | # 9,3,4,#,# => 9,3,#,继续 20 | # 9,3,#,1,#,# => 9,3,#,# => 9,# ,继续 21 | # 9,#2,#,6,#,# => 9,#,2,#,# => 9,#,# => #,结束 22 | 23 | # 为什么这么做?这是根据题目给定的数据结构定义相关。可以画出树形结构,根据题目要求,再进行前序遍历。发现如果满足上面的说法,那就是 24 | # true的遍历,反之遍历是错误的。 25 | -------------------------------------------------------------------------------- /LC338_Counting Bits_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector countBits(int num) { // 布赖恩·克尼根算法 + DP,其实本身计算1的个数不难,但是加上DP就比较巧妙 4 | vector result(num + 1, 0); 5 | for (int i = 1; i <= num; i++) { 6 | result[i] = result[i & (i - 1)] + 1; // result存储的就是对应数字的1的个数,DP的使用很巧妙 7 | } 8 | return result; 9 | } 10 | }; 11 | 12 | // reference https://leetcode-cn.com/problems/counting-bits/solution/bi-te-wei-ji-shu-by-leetcode/ -------------------------------------------------------------------------------- /LC343_Integer Break_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int integerBreak(int n) { // 动态规划,这里dp[i]代表拆分数字i,可以得到的最大乘积dp[i] 4 | vector dp(n + 1, 0); // 初始化 5 | dp[2] = 1; // 这里从dp[2]开始赋初值(边界),因为从2开始,dp才有意义,前面的0和1是没有意义的,所以不用管它们的初值 6 | // 更何况,它们的初值其实用不上 7 | for (int i = 3; i <= n; i++) { 8 | for (int j = 1; j <= i - 2; j++) { // 呼应上面dp[0] dp[1]初值用不上,因为按照这样的i和j的循环,最早也是从dp[2]开始 9 | dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j)); // 状态转移方程,无非这三类。详见链接中题解 10 | } 11 | } 12 | return dp[n]; 13 | } 14 | }; 15 | 16 | // reference https://mp.weixin.qq.com/s/cVbyHrsWH_Rfzlj-ESr01A -------------------------------------------------------------------------------- /LC343_Integer Break_Math.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def integerBreak(self, n: int) -> int: 3 | if n <= 3: return n - 1 4 | a, b = n // 3, n % 3 5 | if b == 0: return int(math.pow(3, a)) 6 | if b == 1: return int(math.pow(3, a - 1) * 4) 7 | return int(math.pow(3, a) * 2) 8 | 9 | # 解答详见剑指offer14-I,两题一致。 -------------------------------------------------------------------------------- /LC344_Reverse String_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | // class Solution { 2 | // public: 3 | // void reverseString(vector& s) { 4 | // reverse(s.begin(),s.end()); 5 | // } 6 | // }; 7 | class Solution{ 8 | public: 9 | void reverseString(vector& s){ 10 | int i=0; 11 | int j=s.size()-1; 12 | while(i None: 3 | """ 4 | Do not return anything, modify s in-place instead. 5 | """ 6 | s.reverse() -------------------------------------------------------------------------------- /LC35_Search Insert Position_Binary Search.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int searchInsert(vector& nums, int target) { // 二分搜索 4 | int left = 0, right = nums.size() - 1; 5 | int mid; 6 | while (left <= right) { // 这是典型的二分搜索的代码,需要非常注意的是取边界的问题 7 | mid = left + (right - left) / 2; // 防溢出 8 | if (nums[mid] == target) return mid; 9 | else if (nums[mid] > target) right = mid - 1; 10 | else left = mid + 1; 11 | } 12 | return right + 1; // right + 1 其实包含了本题的多种情况。比如,元素要插在一开头,此时right本来是-1,会变成-1+1=0;如果元素插在最后,那本就是right+1;如果元素 13 | // 插在不曾出现的地方,因为此时left==right,所以还是放置在right+1的地方。总之,放置位置会偏右。 14 | } 15 | }; 16 | 17 | // reference https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q -------------------------------------------------------------------------------- /LC376_Wiggle Subsequence_Greedy Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int wiggleMaxLength(vector& nums) { 4 | int curDiff = 0; 5 | int preDiff = 0; // preDiff初值赋为0,有把长度为2的nums拉长的作用 6 | int result = 1; // 初值要从1开始,不然长度少一个 7 | if (nums.size() <= 1) return nums.size(); 8 | for (int i = 1; i < nums.size(); ++i){ // i从1开始,因为后续要用到 nums[i - 1] 9 | curDiff = nums[i] - nums[i - 1]; 10 | if ((preDiff >= 0 && curDiff < 0) || (preDiff <= 0 && curDiff > 0)){ // 寻找抖动的宗旨是找寻前后坡度不同导致的极值点个数,所以前一个大于零,后一个小于零 11 | result++; // 但是一开始,preDiff初值为0,所以判断条件中要有 preDiff >= 0 和 preDiff <= 0 的情况。后续preDiff由curDiff赋值,因此不会再用到等于0的条件 12 | preDiff = curDiff; 13 | } 14 | } 15 | return result; 16 | } 17 | }; 18 | 19 | // reference https://mp.weixin.qq.com/s/Xytl05kX8LZZ1iWWqjMoHA -------------------------------------------------------------------------------- /LC377_Combination Sum IV_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int combinationSum4(vector& nums, int target) { // 动态规划 4 | vector dp(target + 1, 0); // 初始化 5 | dp[0] = 1; // 这是没有意义的,纯粹是为了推导递推公式。 6 | for (int j = 0; j <= target; j++) { // 遍历背包 7 | for (int i = 0; i < nums.size(); i++) { // 遍历物品 8 | if ((j - nums[i] >= 0) && (dp[j] < INT_MAX - dp[j - nums[i]])) { // 加上第二个判断的原因是怕数据太大,超过范围 9 | dp[j] += dp[j - nums[i]]; // 这个过程求的是排列数 10 | } 11 | } 12 | } 13 | return dp[target]; 14 | } 15 | }; 16 | 17 | // reference https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA 18 | 19 | // 关于使用dp解决排列数和组合数的问题,会专门探讨。 -------------------------------------------------------------------------------- /LC389_Find the Difference_ASCII.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | char findTheDifference(string s, string t) { // ASCII码的应用 4 | int sumS = 0, sumT = 0; 5 | for (char c : s) sumS += c; 6 | for (char c : t) sumT += c; 7 | return sumT - sumS; 8 | } 9 | }; 10 | 11 | // reference https://leetcode-cn.com/problems/find-the-difference/solution/zhao-bu-tong-by-leetcode-solution-mtqf/ -------------------------------------------------------------------------------- /LC389_Find the Difference_Bit Operation.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | char findTheDifference(string s, string t) { // 位运算 异或 4 | char res = 0; // 注意,这里 int res = 0; 也可以通过,也就是说,char或int型都可以 5 | for (char c : s + t) { 6 | res ^= c; // 异或。个人理解应该是广义的异或,在一次次异或的过程中,相同为0,不同则完整保留。最终得到不同的那一个字母 7 | } 8 | return res; 9 | } 10 | }; 11 | 12 | // reference https://leetcode-cn.com/problems/find-the-difference/solution/zhao-bu-tong-by-leetcode-solution-mtqf/ -------------------------------------------------------------------------------- /LC392_Is Subsequence_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isSubsequence(string s, string t) { // 动态规划 4 | vector> dp(s.size() + 1, vector(t.size() + 1, 0)); // 初始化 5 | for (int i = 1; i <= s.size(); i++) { // 双循环 6 | for (int j = 1; j <= t.size(); j++) { 7 | if (s[i - 1] == t[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1; // 如果当前字符相等,那么dp + 1 8 | else dp[i][j] = dp[i][j - 1]; // 否则这样处理,关于状态转移的细节,可以见Solution中的dp表格截图,就会明白 9 | // 对于状态转移的过程和dp表格的内容,应该有一个全局观 10 | } 11 | } 12 | if (dp[s.size()][t.size()] == s.size()) return true; // 如果最后子串能够完全匹配,那么dp数值等于子串长度 13 | return false; 14 | } 15 | }; 16 | 17 | // reference https://mp.weixin.qq.com/s/2pjT4B4fjfOx5iB6N6xyng 18 | 19 | // 本题可以使用指针求解,更简单。实际上,本题是简单题,所以应该使用指针求解。 20 | 21 | // 使用DP求解可以更好地理解dp的精髓,也为后续的编辑距离打下基础。如果从编辑距离的角度看这题,那么仅仅涉及删除而已。 -------------------------------------------------------------------------------- /LC412_Fizz Buzz_Naive Algorithm.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Nov 3 14:39:26 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | class Solution: 9 | def fizzBuzz(self, n): 10 | res = [] 11 | for i in range(1,n+1): 12 | if i%3==0 and i%5==0: 13 | res.append("FizzBuzz") 14 | elif i%3==0: 15 | res.append("Fizz") 16 | elif i%5==0: 17 | res.append("Buzz") 18 | else: 19 | res.append(str(i)) 20 | return res 21 | 22 | ans = Solution() 23 | print(ans.fizzBuzz(15)) -------------------------------------------------------------------------------- /LC416_Partition Equal Subset Sum_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool canPartition(vector& nums) { 0-1背包问题,套用模板即可 4 | int sum = 0; 5 | for (int num : nums) { 6 | sum += num; 7 | } 8 | if (sum % 2 != 0) return false; 9 | int weight = sum / 2; 10 | vector dp(weight + 1, 0); 11 | for (int i = 0; i < nums.size(); i++) { 12 | for (int j = weight; j >= nums[i]; j--) { 13 | dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]); 14 | } 15 | } 16 | if (dp[weight] == weight) return true; 17 | else return false; 18 | } 19 | }; -------------------------------------------------------------------------------- /LC447_Number of Boomerangs_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int numberOfBoomerangs(vector> &points) { 4 | int ans = 0; 5 | for (auto &p : points) { 6 | unordered_map cnt; // 哈希表 7 | for (auto &q : points) { 8 | int dis = (p[0] - q[0]) * (p[0] - q[0]) + (p[1] - q[1]) * (p[1] - q[1]); 9 | ++cnt[dis]; 10 | } 11 | for (auto &[_, m] : cnt) { // 注意这种语法格式!! 12 | ans += m * (m - 1); 13 | } 14 | } 15 | return ans; 16 | } 17 | }; 18 | 19 | // reference https://leetcode-cn.com/problems/number-of-boomerangs/submissions/ -------------------------------------------------------------------------------- /LC448_Find All Numbers Disappeared in an Array_Brain Teaser.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector findDisappearedNumbers(vector& nums) { // Brain Teaser 脑筋急转弯 4 | for (int num : nums) { // 数组的索引是0-N-1,数组里面数的范围是1-N。正好是对应的。让出现的数对应数组中以这个数为索引的值为负数,代表这个数值出现过。相当于立一个flag。 5 | // 最后算索引对应值为正数的num,那么这些num就是1-N中缺失的数字。 6 | if (nums[abs(num) - 1] > 0) nums[abs(num) - 1] *= -1; // 因为flag的原因,所以num可能变成负值了,因此要用abs。 注意要-1! 7 | } 8 | vector result; 9 | for (int i = 0; i < nums.size(); i++) { 10 | if (nums[i] > 0) result.push_back(i + 1); // 记录结果,注意i+1,因为数值和索引差1 11 | } 12 | return result; 13 | } 14 | }; 15 | 16 | // reference https://leetcode-cn.com/problems/find-all-numbers-disappeared-in-an-array/solution/bu-xu-yao-e-wai-kong-jian-si-lu-chao-ji-qing-xi-bu/ -------------------------------------------------------------------------------- /LC448_Find All Numbers Disappeared in an Array_Brain Teaser.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public List findDisappearedNumbers(int[] nums) { 3 | //用来存放结果 4 | List res = new ArrayList<>(); 5 | //1. 遍历下数组的元素,对对应的索引位置的元素作标记 6 | int len = nums.length; 7 | for(int i = 0; i < len; i++){ 8 | int num = Math.abs(nums[i]); //由于数组的元素有可能被*-1,所以取绝对值 9 | int index = num - 1; 10 | if(nums[index] > 0){ 11 | nums[index] *= -1; 12 | } 13 | } 14 | // 寻找没有标记的索引位置 15 | for(int i = 0; i < len; i++){ 16 | if(nums[i] > 0){ 17 | int num = i + 1; //将索引转化为对应的元素 18 | res.add(num); 19 | } 20 | } 21 | return res; 22 | } 23 | } 24 | 25 | // reference https://leetcode-cn.com/problems/find-all-numbers-disappeared-in-an-array/solution/bu-xu-yao-e-wai-kong-jian-si-lu-chao-ji-qing-xi-bu/ 26 | -------------------------------------------------------------------------------- /LC452_Minimum Number of Arrows to Burst Balloons_Greedy Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | static bool cmp(const vector& a, const vector& b) { // 比较,从小到大排序 4 | return a[0] < b[0]; 5 | } 6 | int findMinArrowShots(vector>& points) { 7 | if (points.size() == 0) return 0; // 特判 8 | sort(points.begin(), points.end(), cmp); 9 | int result = 1; // 已经过了特判,说明一定有气球,那么result初始值为1 10 | for (int i = 1; i < points.size(); i++) { 11 | if (points[i][0] > points[i - 1][1]) result++; // 如果下一个气球的左边界在上一个气球的右边界之内,那么可以一箭穿多。注意!这里不能取等,因为题目要求,取等可以穿过。 12 | // 反之,如果左边界在右边界之外,那么要多一支箭。 13 | else points[i][1] = min(points[i][1], points[i - 1][1]); // 这是比较巧妙的地方。每次取的都是最小右边界。这样便于判断可不可以一箭穿多。 14 | } 15 | return result; 16 | } 17 | }; 18 | 19 | // reference https://mp.weixin.qq.com/s/HxVAJ6INMfNKiGwI88-RFw -------------------------------------------------------------------------------- /LC455_Assign Cookies_Greedy Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findContentChildren(vector& g, vector& s) { // 贪心算法 4 | sort(g.begin(),g.end()); // 先排序 5 | sort(s.begin(),s.end()); 6 | int index = s.size(); 7 | int count = 0; 8 | for(int i = g.size() - 1; i >= 0; i--){ // 从大到小进行比较,如果饼干可以比孩子需求尺寸大,就给孩子。因为是从大到小一步步比较,所以给的过程不会浪费 9 | if(index >= 1 && s[index - 1] >= g[i]){ // 大于孩子需求 这里注意:index >= 1 ! 这是由s[index - 1]而定。在利用数组索引时,要关注索引值大于等于0的隐性条件 10 | count++; 11 | index--; // 这里本来是两层for循环,但由于本题要求,所以可以改成单层for循环,降低了运算复杂度。这种index--的方法是值得学习的。但注意index--的底线是什么。 12 | } 13 | } 14 | return count; 15 | } 16 | }; 17 | 18 | // reference https://mp.weixin.qq.com/s/YSuLIAYyRGlyxbp9BNC1uw 具体实现的动图见链接 -------------------------------------------------------------------------------- /LC459_Repeated Substring Pattern_KMP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void getNext(int* next,const string& s){ // 构建KMP的next数组 4 | int j=-1; 5 | next[0] = j; 6 | for(int i=1;i=0 && s[j+1]!=s[i]){ // 记得j>=0要有,不然无路可退,会报错 8 | j = next[j]; 9 | } 10 | if(s[j+1]==s[i]){ 11 | j++; 12 | } 13 | next[i] = j; 14 | } 15 | } 16 | bool repeatedSubstringPattern(string s) { 17 | int len = s.size(); 18 | if(len==0){ 19 | return false; 20 | } 21 | int next[len]; 22 | getNext(next,s); 23 | if(next[len-1]!=-1 && len%(len-(next[len-1]+1))==0){ // 构成子串的条件 这一点需要观察能被子串构成的数组的next规律 见reference内容 24 | return true; 25 | } 26 | return false; 27 | } 28 | }; 29 | // reference https://mp.weixin.qq.com/s/lR2JPtsQSR2I_9yHbBmBuQ KMP算法 -------------------------------------------------------------------------------- /LC45_Jump Game II_Greedy Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int jump(vector& nums) { // 贪心算法,贪的是最远覆盖距离,看是否可以盖住终点。这个思路和LC55类似,我们注重的是结果(覆盖大小),而不是过程(怎么跳)。 4 | int ans = 0; // 跳跃次数 5 | int curDistance = 0; // 目前能覆盖到的最远位置 6 | int nextDistance = 0; // 下一个能覆盖到的最远位置 7 | for (int i = 0; i < nums.size() - 1; i++){ // 遍历,注意,这里终止条件是nums.size()-1。我们其实不需要看是否到了终点,如果distance盖住了终点,那么i够不着distance,ans不会++ 8 | // 如果distance没有盖住终点,因为题目要求一定可以到达最后一个位置,所以不用管最后一步是怎么跳的,总可以跳到终点,只是ans需要++,多一步来完成。 具体图解见链接 9 | nextDistance = max(nextDistance, nums[i] + i); // 贪心,找寻最大可覆盖范围 10 | if (i == curDistance){ // i移动到了目前覆盖范围的边界,那么覆盖范围更新成最新最大的范围,进行后续操作(distance更新&跳跃++) 11 | curDistance = nextDistance; 12 | ans++; 13 | } 14 | } 15 | return ans; 16 | } 17 | }; 18 | 19 | // reference https://mp.weixin.qq.com/s/kJBcsJ46DKCSjT19pxrNYg 20 | // 代码中最巧妙的地方在于对题目中一定可以到达终点的理解,然后简化了判断条件。 -------------------------------------------------------------------------------- /LC461_Hamming Distance_Bit Operation.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int hammingDistance(int x, int y) { // 布赖恩·克尼根算法,简而言之就是:一个数和这个数减1进行相与,结果就是消去最右边的1.这样一步步消去,看能消几次,代表有几个1. 4 | int distance = 0; 5 | int res = x ^ y; // 先进行异或,得到不同位置为1的数 6 | while (res) { // 计算1的个数,用算法 7 | res &= (res - 1); 8 | distance++; 9 | } 10 | return distance; 11 | } 12 | }; 13 | 14 | 15 | // reference https://leetcode-cn.com/problems/hamming-distance/solution/yi-ming-ju-chi-by-leetcode/ 16 | -------------------------------------------------------------------------------- /LC474_Ones and Zeroes_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findMaxForm(vector& strs, int m, int n) { // 本题比较特殊,是二维的0-1背包问题 4 | vector> dp(m + 1, vector(n + 1, 0)); // 本行和下面一行等价 5 | // int dp[101][101] = {0}; // 像这种数组直接 = {0}的,就是把所有初值全部赋为0 6 | for (string str : strs) { 7 | int oneNum = 0; // 统计0的个数 8 | int zeroNum = 0; // 统计1的个数 9 | for (char c : str) { 10 | if (c == '0') zeroNum++; 11 | else oneNum++; 12 | } 13 | for (int i = m; i >= zeroNum; i--) { // 二维DP 14 | for (int j = n; j >= oneNum; j--) { 15 | dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1); 16 | } 17 | } 18 | } 19 | return dp[m][n]; 20 | } 21 | }; 22 | 23 | // reference https://leetcode-cn.com/problems/ones-and-zeroes/solution/474-yi-he-ling-01bei-bao-xiang-jie-by-ca-s9vr/ 24 | // 除了DP,本题对于字符串的处理也很值得学习 -------------------------------------------------------------------------------- /LC480_Sliding Window Median_Sliding Window.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector medianSlidingWindow(vector& nums, int k) { 4 | vector res; 5 | multiset st; 6 | for (int i = 0; i < nums.size(); ++i) { 7 | if (st.size() >= k) st.erase(st.find(nums[i - k])); 8 | st.insert(nums[i]); 9 | if (i >= k - 1) { 10 | auto mid = st.begin(); 11 | std::advance(mid, k / 2); 12 | res.push_back((*mid + *prev(mid, (1 - k % 2))) / 2); 13 | } 14 | } 15 | return res; 16 | } 17 | }; 18 | 19 | // reference https://leetcode-cn.com/problems/sliding-window-median/solution/xuan-ze-he-gua-de-shu-ju-jie-gou-zhe-ti-muyt4/ -------------------------------------------------------------------------------- /LC485_Max Consecutive Ones_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findMaxConsecutiveOnes(vector& nums) { // 模拟法 4 | if (nums.size() == 0) return 0; // 特判 5 | int maxNum = 0; 6 | int count = 0; 7 | for (int i = 0; i < nums.size(); i++) { // 遍历一遍 8 | if (nums[i] == 1) { // 遇到1,就计数+1 9 | count++; 10 | } 11 | if (nums[i] == 0 || i == nums.size() - 1) { // 遇到0或者是最后一位了 12 | maxNum = max(maxNum, count); // 找到最大的数值,仅关注最大count即可 13 | count = 0; // 清零 14 | } 15 | } 16 | return maxNum; 17 | } 18 | }; -------------------------------------------------------------------------------- /LC485_Max Consecutive Ones_Naive Algorithm.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def findMaxConsecutiveOnes(self, nums: List[int]) -> int: # 模拟法 3 | if (len(nums) == 0): return 0 # 特判 4 | count = 0 5 | maxNum = 0 6 | for i in range(0, len(nums)) : 7 | if (nums[i] == 1): # 遇到1 8 | count += 1 # 计数+1 9 | if ((nums[i] == 0) or (i == len(nums) - 1)): # 遇到0或者最后一位 10 | maxNum = max(maxNum, count) # 记录最大值 11 | count = 0 # 清零 12 | return maxNum 13 | -------------------------------------------------------------------------------- /LC48_Rotate Image_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { // 顺时针90°旋转一个矩阵,两步走: 1. 转置 2. 矩阵每一行顺序取反 2 | public: 3 | void rotate(vector>& matrix) { 4 | for (int i = 0; i < matrix.size(); i++) { // 转置 5 | for (int j = i; j < matrix[0].size(); j++) { 6 | swap(matrix[i][j], matrix[j][i]); 7 | } 8 | } 9 | for (int i = 0; i < matrix.size(); i++) reverse(matrix[i].begin(), matrix[i].end()); // 每一行取反 10 | } 11 | }; 12 | 13 | -------------------------------------------------------------------------------- /LC4_Find Median Sorted Arrays_Quick Sort.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Oct 30 15:00:35 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | class Solution: 9 | def findMedianSortedArrays(self, nums1, nums2): 10 | for i in range(len(nums1)): # 把数据放在一起 11 | nums2.append(nums1[i]) 12 | nums2.sort() # 对所有数据排序 快排 13 | size = len(nums2) 14 | if size%2 == 0: # 输出数据的中位数即可 15 | return float((nums2[size//2-1]+nums2[size//2])/2.0) 16 | else: 17 | return float(nums2[size//2]) 18 | 19 | ans = Solution() 20 | nums1 = [1,3] 21 | nums2 = [2] 22 | print(ans.findMedianSortedArrays(nums1,nums2)) -------------------------------------------------------------------------------- /LC509_Fibonacci Number_DP.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def fib(self, n: int) -> int: # 动态规划 3 | if n == 0: return 0 4 | if n == 1: return 1 5 | dp = [0] * (n + 1) 6 | dp[0] = 0 7 | dp[1] = 1 8 | for i in range(2, n + 1): 9 | dp[i] = dp[i - 1] + dp[i - 2] 10 | return dp[-1] -------------------------------------------------------------------------------- /LC50_Pow(x, n)_Math.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def myPow(self, x: float, n: int) -> float: # 快速幂算法 数学 3 | result = 1 4 | if (x == 0.0) : return 0.0 # 注意float型的输出 5 | if (n < 0) : x, n = 1 / x, -n # 负数次幂的处理,易忘易错 6 | while n: 7 | if (n & 1) : result *= x # 满足影响result数值的条件 8 | x *= x # 不管能不能影响result,x都应该继续按照2的次幂变化 9 | n >>= 1 # 在每一次while循环中,n应该持续进行移位运算 10 | return result 11 | 12 | # reference https://leetcode-cn.com/problems/powx-n/solution/50-powx-n-kuai-su-mi-qing-xi-tu-jie-by-jyd/ 13 | # 快速幂算法详见Solution中截图 -------------------------------------------------------------------------------- /LC513_Find Bottom Left Tree Value_BFS.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | int findBottomLeftValue(TreeNode* root) { 13 | queue q; 14 | int result; 15 | q.push(root); 16 | while (!q.empty()) { 17 | int size = q.size(); 18 | for (int i = 0; i < size; i++) { 19 | TreeNode* node = q.front(); 20 | if (i == 0) result = node->val; // 保证最后找的是最后一行的最左边节点 21 | q.pop(); 22 | if (node->left) q.push(node->left); 23 | if (node->right) q.push(node->right); 24 | } 25 | } 26 | return result; 27 | } 28 | }; -------------------------------------------------------------------------------- /LC516_Longest Palindromic Subsequence_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int longestPalindromeSubseq(string s) { // 动态规划 dp[i][j]:字符串s在[i, j]范围内最长的回文子序列的长度为dp[i][j]。 4 | vector> dp(s.size(), vector(s.size(), 0)); // 初始化 5 | for (int i = 0; i < s.size(); i++) dp[i][i] = 1; // 自己本身可以算一个单位长度的回文子序列 6 | for (int i = s.size() - 1; i >= 0; i--) { // 注意for循环的遍历顺序,根据递推公式,需要从下到上,从左到右 7 | for (int j = i + 1; j < s.size(); j++) { 8 | if (s[i] == s[j]) { // 如果遇到两个字符相等,那么在原长度基础上面加二 9 | dp[i][j] = dp[i + 1][j - 1] + 2; 10 | } else { 11 | dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]); // 如果不相等,那么由于dp存的是某范围内最长回文子序列, 12 | // 所以它取dp[i + 1][j]和dp[i][j - 1]中的最大值即可,这是一个很动态规划的思维,值得理解明白 13 | } 14 | } 15 | } 16 | return dp[0][s.size() - 1]; // 输出字符串范围内,最长回文子序列长度即可 17 | } 18 | }; 19 | 20 | // reference https://mp.weixin.qq.com/s/jbd3p4QPm5Kh1s2smTzWag -------------------------------------------------------------------------------- /LC518_Coin Change 2_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int change(int amount, vector& coins) { // 完全背包 4 | vector dp(amount + 1, 0); 5 | dp[0] = 1; // 初始化 6 | for (int i = 0; i < coins.size(); i++) { 7 | for (int j = coins[i]; j <= amount; j++) { 8 | dp[j] += dp[j - coins[i]]; // 本题要求的是组合数,所以用这个递推公式。相似的内容在LC494目标和中也有出现 9 | } 10 | } 11 | return dp[amount]; 12 | } 13 | }; 14 | 15 | /* 16 | 本题代码很精简,但是有一些问题值得注意: 17 | 1.递推公式是求组合数的递推公式,不是一般的模板; 18 | 2.一般的完全背包问题,两个for循环可以互换位置,但是本题不可以。原因就是求的是组合数。 19 | 如果只在乎一步步最大化之后的结果,那么for循环没影响;但这里需要组合数,那么就需要外层for循环是 20 | coin,内层是amount;如果反过来,求的就是排列数。 21 | 具体原因见链接: https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ 22 | 也可以自己打印dp数组看看 23 | */ -------------------------------------------------------------------------------- /LC518_Coin ChangeII_DP.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Aug 22 01:59:57 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | def change(amount, coins): 9 | dp = [0]*(amount+1) 10 | dp[0] = 1 11 | for coin in coins: 12 | for i in range(coin,amount+1): 13 | dp[i] = dp[i] + dp[i-coin] 14 | return dp[amount] 15 | 16 | amount = int(input()) 17 | coins = [int(x) for x in input().split()] 18 | print(change(amount,coins)) -------------------------------------------------------------------------------- /LC53_Maximum Subarray v2_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxSubArray(vector& nums) { // 动态规划 4 | if (nums.size() == 0) return 0; 5 | vector dp(nums.size(), 0); // dp代表滑动过程中,当下的最大值 6 | dp[0] = nums[0]; 7 | int result = dp[0]; // 用result存储全局最大值 8 | for (int i = 1; i < nums.size(); i++) { 9 | dp[i] = max(dp[i - 1] + nums[i], nums[i]); // 保存当下的最大值,注意:这里存储的数值不一定就是全局最大值!!!! 10 | if (dp[i] > result) result = dp[i]; // 找寻全局最大值,并且存储下来 11 | } 12 | return result; // 输出结果 13 | } 14 | }; 15 | 16 | // reference https://mp.weixin.qq.com/s/2Xtyi2L4r8sM-BcxgUKmcA 17 | // 本题注意:求的是 连续 子数组!! -------------------------------------------------------------------------------- /LC53_Maximum Subarray_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxSubArray(vector& nums) { // 动态规划 4 | if (nums.size() == 0) return 0; // 特判 5 | vector dp(nums.size(),0); // dp的初始化 6 | int result; // 存放最大结果 7 | dp[0] = nums[0]; 8 | result = nums[0]; 9 | for (int i = 1; i < nums.size(); ++i){ 10 | dp[i] = max(dp[i - 1] + nums[i], nums[i]); // 转移方程。注意不同DP题目建模细节不太相同,所以要弄清dp代表什么,转移方程具体怎么写。此处是求最大子序和,所以 11 | // 不同于很多DP,max中第二个是nums[i] rather than dp[i - 1]。 12 | if(dp[i] > result){ // 保留最大值,不然按照这样一步步转移,最后很可能是局部最优。这点也和很多DP问题不同 13 | result = dp[i]; 14 | } 15 | } 16 | return result; 17 | } 18 | }; 19 | 20 | // reference https://mp.weixin.qq.com/s/DrjIQy6ouKbpletQr0g1Fg -------------------------------------------------------------------------------- /LC541_Reverse String II_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string reverseStr(string s, int k) { 4 | for(int i=0;i children; 7 | 8 | Node() {} 9 | 10 | Node(int _val) { 11 | val = _val; 12 | } 13 | 14 | Node(int _val, vector _children) { 15 | val = _val; 16 | children = _children; 17 | } 18 | }; 19 | */ 20 | 21 | class Solution { 22 | public: 23 | int maxDepth(Node* root) { 24 | queue q; 25 | if(root!=NULL) q.push(root); 26 | int depth = 0; 27 | while(!q.empty()){ 28 | int size = q.size(); 29 | for(int i=0;ichildren.size();++j){ 33 | q.push(node->children[j]); 34 | } 35 | } 36 | depth++; 37 | } 38 | return depth; 39 | } 40 | }; -------------------------------------------------------------------------------- /LC55_Jump Game_Greedy Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool canJump(vector& nums) { // 贪心算法 我们关心的是覆盖范围,也就是能不能覆盖到终点。至于中间是怎么跳的,我们并不关心。也就是说,本题只关注最终的结果,并不管过程。 4 | int cover = 0; 5 | if (nums.size() == 1) return true; 6 | for (int i = 0; i <= cover; i++){ // 注意,小于等于cover。 7 | cover = max(i + nums[i], cover); // 更新覆盖范围 8 | if (cover >= nums.size() - 1) return true; // 如果可以覆盖到终点,那么true 9 | } 10 | return false; 11 | } 12 | }; 13 | 14 | // reference https://mp.weixin.qq.com/s/606_N9j8ACKCODoCbV1lSA -------------------------------------------------------------------------------- /LC561_Array Partition I_Brain Teaser.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int arrayPairSum(vector& nums) { 4 | sort(nums.begin(), nums.end()); // 排序 5 | int result = 0; 6 | for (int i = 0; i < nums.size(); i += 2) { // 每间隔2个单位,取一个数值相加 7 | result += nums[i]; 8 | } 9 | return result; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /LC561_Array Partition I_Brain Teaser.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def arrayPairSum(self, nums: List[int]) -> int: 3 | nums.sort() # 排序 4 | result = 0 5 | for i in range(0, len(nums), 2) : # 每间隔2个单位,取一个数值相加 6 | result += nums[i] 7 | return result 8 | 9 | """ 10 | # Another Version: 11 | class Solution: 12 | def arrayPairSum(self, nums: List[int]) -> int: 13 | return sum(sorted(nums)[::2]) 14 | """ -------------------------------------------------------------------------------- /LC566_Reshape the Matrix_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> matrixReshape(vector>& nums, int r, int c) { // 模拟法 4 | vector> result(r, vector(c, 0)); 5 | int row = 0; 6 | int col = 0; 7 | if (nums.size() * nums[0].size() != r * c) return nums; // 特判 8 | for (int i = 0; i < nums.size(); i++) { 9 | for (int j = 0; j < nums[0].size(); j++) { // 放置元素 10 | if (col == c) { 11 | row++; 12 | col = 0; 13 | } 14 | result[row][col] = nums[i][j]; 15 | col++; 16 | } 17 | } 18 | return result; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /LC589_N-ary Tree Preorder Traversal_Recursion.py: -------------------------------------------------------------------------------- 1 | """ 2 | # Definition for a Node. 3 | class Node: 4 | def __init__(self, val=None, children=None): 5 | self.val = val 6 | self.children = children 7 | """ 8 | 9 | class Solution: 10 | def preorder(self, root: 'Node') -> List[int]: 11 | if not root: return [] 12 | res = [root.val] 13 | for node in root.children: 14 | res.extend(self.preorder(node)) 15 | return res 16 | 17 | # reference https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/python3-er-cha-shu-suo-you-bian-li-mo-ban-ji-zhi-s/ 18 | """ 19 | aList = [123, 'xyz', 'zara', 'abc', 123]; 20 | bList = [2009, 'manni']; 21 | aList.extend(bList) 22 | [123, 'xyz', 'zara', 'abc', 123, 2009, 'manni'] 23 | python extend方法 24 | """ -------------------------------------------------------------------------------- /LC605_Can Place Flowers_Greedy Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool canPlaceFlowers(vector& flowerbed, int n) { // 贪心算法 贪心在于放尽可能多的花,比较花的数量和n的大小。 4 | int flowers = 0; 5 | if (flowerbed.size() == 0) return 0; 6 | for (int i = 0; i < flowerbed.size(); i += 2) { // 两个格子进行跳跃 这是因为一个格子确定有花之后,下一个一定是0。这样一来,下一朵花需要在离 7 | // 当前花儿2个单位的距离下才可以栽种。 8 | if (flowerbed[i] == 0) { // 如果当前位置没有花 9 | if (i == flowerbed.size() - 1 || flowerbed[i + 1] == 0) { // 判断,如果是最后一个格子了,那么就种一朵花,这个时候后面没有格子了;或者下一个是没有花的,可以种一朵 10 | // 不用判断前面的格子,这是因为之前移动单位是2,前面的格子已经检查过了,确认是没有花的。 11 | flowers++; 12 | } 13 | else i++; // 如果这个格子的下一个位置有花,那么这个格子不能种花。这个时候位置i转移到下一个格子,准备i += 2,直接在有花的位置跳两格,查看下一个位置。 14 | } 15 | } 16 | return flowers >= n; // 比较最多能种的花数量和n的大小,如果n更小,显然可以种下。 17 | } 18 | }; 19 | 20 | // reference https://leetcode-cn.com/problems/can-place-flowers/solution/qi-si-miao-jie-by-heroding-h7m0/ -------------------------------------------------------------------------------- /LC611_Valid Triangle Number_Double Pointer.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int triangleNumber(vector& nums) { 4 | sort(nums.begin(), nums.end()); 5 | int res = 0; 6 | for (int i = nums.size() - 1; i >= 2; i--) { 7 | int left = 0; 8 | int right = i - 1; 9 | while (left < right) { 10 | if (nums[left] + nums[right] > nums[i]) { 11 | res += right - left; 12 | right--; 13 | } 14 | else left++; 15 | } 16 | } 17 | return res; 18 | } 19 | }; -------------------------------------------------------------------------------- /LC611_Valid Triangle Number_Double Pointer.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int triangleNumber(int[] nums) { 3 | Arrays.sort(nums); 4 | int n = nums.length; 5 | int res = 0; 6 | for (int i = n - 1; i >= 2; --i) { 7 | int l = 0, r = i - 1; 8 | while (l < r) { 9 | if (nums[l] + nums[r] > nums[i]) { 10 | res += r - l; 11 | r--; 12 | } else { 13 | l++; 14 | } 15 | } 16 | } 17 | return res; 18 | } 19 | } 20 | 21 | // reference https://leetcode-cn.com/problems/valid-triangle-number/solution/ming-que-tiao-jian-jin-xing-qiu-jie-by-jerring/ -------------------------------------------------------------------------------- /LC617_Merge Two Binary Trees_Recursion.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { // 合并两棵树,分别对它们进行遍历,进行相加即可。遍历可以是前序,中序,后序。 11 | public: 12 | TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) { 13 | if (t1 == nullptr) return t2; // t1无,那么t2上 14 | if (t2 == nullptr) return t1; // t2无,那么t1上 15 | t1->val += t2->val; // 前序遍历,对节点做处理 16 | t1->left = mergeTrees(t1->left, t2->left); // 左 17 | t1->right = mergeTrees(t1->right, t2->right); // 右 18 | return t1; 19 | } 20 | }; 21 | 22 | // reference https://leetcode-cn.com/problems/merge-two-binary-trees/solution/617-he-bing-er-cha-shu-san-chong-di-gui-yi-chong-d/ -------------------------------------------------------------------------------- /LC61_Ans1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/LC61_Ans1.png -------------------------------------------------------------------------------- /LC61_Ans2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/LC61_Ans2.png -------------------------------------------------------------------------------- /LC628_Maximum Product of Three Numbers_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | static bool cmp(const int a, const int b) { 4 | return a < b; 5 | } 6 | int maximumProduct(vector& nums) { // 数学题 7 | sort(nums.begin(), nums.end(), cmp); // 排序 8 | int n = nums.size(); 9 | // 本题最应该注意的就是会有负数的出现。针对于负数,我们需要分类讨论: 10 | // 首先要明确,我们为什么对负数进行分类讨论? 其实就是怕两个负数一个正数的情况。如果数组里面的数任取三个数,都是正的或者是 11 | // 负的,那么就不用讨论了,直接排序出结果就好。明白了这一点,下面一行代码就可以看懂了,其实就是考虑了两个负数一个正数的情况。 12 | return max(nums[0] * nums[1] * nums[n - 1], nums[n - 1] * nums[n - 2] * nums[n - 3]); 13 | } 14 | }; 15 | 16 | // reference https://leetcode-cn.com/problems/maximum-product-of-three-numbers/solution/san-ge-shu-de-zui-da-cheng-ji-by-leetcod-t9sb/ -------------------------------------------------------------------------------- /LC62_Unique Paths_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int uniquePaths(int m, int n) { // 组合数可解 4 | long long ans = 1; // 注意数据类型 5 | for (int x = n, y = 1; y < m; ++x, ++y) { // 注意,这里组合数的处理可以分子分母乘法一起做,相当于乘法拆分再结合 6 | ans = ans * x / y; // 日后在写长串公式时,可以这么做 7 | } 8 | return ans; 9 | } 10 | }; -------------------------------------------------------------------------------- /LC62_Unique Paths_Math.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def uniquePaths(self, m: int, n: int) -> int: 3 | return comb(m - 1 + n - 1, n - 1) # 调用相关API 4 | 5 | # 组合数 -------------------------------------------------------------------------------- /LC647_Palindromic Substrings_Center Expansion.c: -------------------------------------------------------------------------------- 1 | int countSubstrings(char* s) { 2 | int n = strlen(s), ans = 0; 3 | for (int i = 0; i < 2 * n - 1; ++i) { 4 | int l = i / 2, r = i / 2 + i % 2; 5 | while (l >= 0 && r < n && s[l] == s[r]) { 6 | --l; 7 | ++r; 8 | ++ans; 9 | } 10 | } 11 | return ans; 12 | } 13 | -------------------------------------------------------------------------------- /LC647_Palindromic Substrings_Center Expansion.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int countSubstrings(string s) { 4 | int n = s.size(), ans = 0; 5 | for (int i = 0; i < 2 * n - 1; ++i) { 6 | int l = i / 2, r = i / 2 + i % 2; 7 | while (l >= 0 && r < n && s[l] == s[r]) { 8 | --l; 9 | ++r; 10 | ++ans; 11 | } 12 | } 13 | return ans; 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /LC647_Palindromic Substrings_Center Expansion.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int countSubstrings(String s) { 3 | int n = s.length(), ans = 0; 4 | for (int i = 0; i < 2 * n - 1; ++i) { 5 | int l = i / 2, r = i / 2 + i % 2; 6 | while (l >= 0 && r < n && s.charAt(l) == s.charAt(r)) { 7 | --l; 8 | ++r; 9 | ++ans; 10 | } 11 | } 12 | return ans; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /LC647_Palindromic Substrings_Center Expansion.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sun Nov 1 14:47:31 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | class Solution: 9 | def countSubstrings(self, s: str) -> int: 10 | size = len(s) 11 | res = 0 12 | for i in range(2*size-1): # 以i为中心,向两边扩张,找寻相同字符 13 | left = i//2 14 | right = i//2 + i%2 15 | while(left>=0 and right= 0 && j < n && s[i] == s[j]) { 15 | i--; 16 | j++; 17 | res++; 18 | } 19 | return res; 20 | } 21 | }; 22 | 23 | // reference https://mp.weixin.qq.com/s/2WetyP6IYQ6VotegepVpEw -------------------------------------------------------------------------------- /LC64_Minimum Path Sum_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int minPathSum(vector>& grid) { // 动态规划 4 | 5 | for (int i = 0; i < grid.size(); ++i){ // 没有必要再建一个dp数组,直接在grid上面进行修改即可。覆盖后的grid不会对结果产生影响,这样做可行。 6 | for (int j = 0; j < grid[0].size(); ++j){ 7 | if (i == 0 && j == 0) continue; // i和j都是零,代表是自身,没有转移的过程,直接continue即可 8 | else if (i == 0) grid[i][j] += grid[i][j - 1]; // i=0,代表转移只能来自于一个方向,不用min 9 | else if (j == 0) grid[i][j] += grid[i - 1][j]; // j=0 同i=0 的操作 10 | else grid[i][j] = min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]; // 正常的转移方程 11 | } 12 | } 13 | return grid[grid.size() - 1][grid[0].size() - 1]; // 记得减1,不然超维度了 14 | } 15 | }; 16 | 17 | // 设dp为大小m×n矩阵,其中dp[i][j]的值代表直到走到(i,j)的最小路径和。 18 | 19 | // reference https://leetcode-cn.com/problems/minimum-path-sum/solution/zui-xiao-lu-jing-he-dong-tai-gui-hua-gui-fan-liu-c/ -------------------------------------------------------------------------------- /LC64_Minimum Path Sum_DP.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int minPathSum(int[][] grid) { 3 | for(int i = 0; i < grid.length; i++) { 4 | for(int j = 0; j < grid[0].length; j++) { 5 | if(i == 0 && j == 0) continue; 6 | else if(i == 0) grid[i][j] = grid[i][j - 1] + grid[i][j]; 7 | else if(j == 0) grid[i][j] = grid[i - 1][j] + grid[i][j]; 8 | else grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]; 9 | } 10 | } 11 | return grid[grid.length - 1][grid[0].length - 1]; 12 | } 13 | } 14 | 15 | 16 | // reference https://leetcode-cn.com/problems/minimum-path-sum/solution/zui-xiao-lu-jing-he-dong-tai-gui-hua-gui-fan-liu-c/ 17 | -------------------------------------------------------------------------------- /LC64_Minimum Path Sum_DP.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def minPathSum(self, grid: [[int]]) -> int: 3 | for i in range(len(grid)): 4 | for j in range(len(grid[0])): 5 | if i == j == 0: continue 6 | elif i == 0: grid[i][j] = grid[i][j - 1] + grid[i][j] 7 | elif j == 0: grid[i][j] = grid[i - 1][j] + grid[i][j] 8 | else: grid[i][j] = min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j] 9 | return grid[-1][-1] 10 | 11 | # reference https://leetcode-cn.com/problems/minimum-path-sum/solution/zui-xiao-lu-jing-he-dong-tai-gui-hua-gui-fan-liu-c/ -------------------------------------------------------------------------------- /LC66_Plus One_Math.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int[] plusOne(int[] digits) { 3 | for (int i = digits.length - 1; i >= 0; i--) { // 数学题 4 | digits[i]++; // 直接在原本digits上面+1 5 | digits[i] = digits[i] % 10; // 但是怕进位,所以和10取模值,如果是0,代表进位 6 | if (digits[i] != 0) return digits; // 直到不等于0,输出加1之后的digits。 7 | // 但是怕99 999 9999 这类数字,就是全部都要进位。所以这里设置这样的for循环,进行全部digits的查阅 8 | // 如果是99类的数字,就跳出循环 9 | } 10 | digits = new int[digits.length + 1]; // 比如99进位成100,数位多一位,所以新建一个digits,里面数值默认为0 11 | digits[0] = 1; // 让第一个数值为1就是原本digits加1之后的结果 12 | return digits; // 返回答案 13 | } 14 | } 15 | 16 | // reference https://leetcode-cn.com/problems/plus-one/solution/java-shu-xue-jie-ti-by-yhhzw/ 17 | // 数位的处理是数学类题目中常考的类型,主要就是考察进位处理和0的处理。 18 | // 本题直接利用题目给的digits,没有再用额外空间,是值得学习的。 -------------------------------------------------------------------------------- /LC674_Longest Continuous Increasing Subsequence_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { // 最长子序列问题 2 | public: 3 | int findLengthOfLCIS(vector& nums) { // 动态规划 dp[i]:以下标i为结尾的数组的连续递增的子序列长度为dp[i]。 4 | if (nums.size() == 0) return 0; // 特判 5 | int result = 1; 6 | vector dp(nums.size() ,1); // 初始化赋值为1,因为本身可以算一个 7 | for (int i = 0; i < nums.size() - 1; i++) { 8 | if (nums[i + 1] > nums[i]) { // 连续记录,如果递增就进行状态转移方程 9 | dp[i + 1] = dp[i] + 1; 10 | } 11 | if (dp[i + 1] > result) result = dp[i + 1]; // 记下最大值,维护一个数值即可 12 | } 13 | return result; 14 | } 15 | }; 16 | 17 | // reference https://mp.weixin.qq.com/s/c0Nn0TtjkTISVdqRsyMmyA -------------------------------------------------------------------------------- /LC674_Longest Continuous Increasing Subsequence_Naive Algorithm.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def findLengthOfLCIS(self, nums: List[int]) -> int: # 模拟法 3 | res = [] 4 | i = 0 5 | while (i < len(nums)): 6 | count = 1 7 | while (i + 1 < len(nums) and nums[i] < nums[i + 1]): # 满足条件的就加一 8 | count += 1 9 | i += 1 10 | res.append(count); 11 | i += 1 12 | return max(res) if res else 0 # 特判,防止res就没有东西 13 | 14 | # reference https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence/submissions/ -------------------------------------------------------------------------------- /LC67_Add Binary_Bit Operation.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def addBinary(self, a: str, b: str) -> str: # 位运算实现加法 经典处理 3 | x = int(a, 2) # 这个函数使得数据从10进制变到2进制 4 | y = int(b, 2) 5 | while y: 6 | z = x ^ y # 异或运算,这个是模拟加法过程中1+0=1 1+1=0 0+0=0 的过程 7 | carry = (x & y) << 1 # 异或模拟加法,弊病在于没有记录进位。这里记录进位。进位是用与运算模拟,注意:因为是进位,所以要左移运算1个单位 8 | x, y = z, carry 9 | return bin(x)[2:] # bin(x)函数用于将x返回成2进制的形式。这里的形式是'0b1010'的样式。因为addBinary函数变成str类型(函数定义),所以 10 | # return bin(x) return的是"0b1010"样式。我们的结果中不希望有0b,所以是[2:],把前面两个"0b"去掉。 11 | 12 | # 这种进制转换的题目最好用Python写,可以比较方便地调用库函数。这样一来,我们只用关注怎么用逻辑运算实现加法器就好,不用关心一些format的次要问题。 -------------------------------------------------------------------------------- /LC69_Sqrt(x)_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int mySqrt(int x) { // 二分法 4 | int l = 0, r = x, ans = -1; 5 | while (l <= r) { 6 | int mid = l + (r - l) / 2; // 防止溢出 7 | if ((long long)mid * mid <= x) { // 小于和等于,两种情况一起考虑 8 | ans = mid; // 等于的情况 9 | l = mid + 1; // 小于的处理 10 | } else { 11 | r = mid - 1; // 大于的情况 12 | } 13 | } 14 | return ans; 15 | } 16 | }; 17 | 18 | // 其实本题也可以小于,大于,等于,三种情况分开处理。 19 | // 二分法是重要的方法,比起传统的,一个个试过去的方法,二分法显然高效 -------------------------------------------------------------------------------- /LC700_Search in a Binary Search Tree_Recursion.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | TreeNode* searchBST(TreeNode* root, int val) { // 本题虽然说要把子树输出出来,但其实只要输出root节点就好 13 | if(root == NULL || root->val == val) return root; 14 | if(root->val > val) return searchBST(root->left, val); // 递归,找寻节点 15 | if(root->val < val) return searchBST(root->right, val); 16 | return NULL; 17 | } 18 | }; // 树的问题有涉及递归也有BFS,一般就这两种方法,尝试一下,便知一道题目应该用什么办法。 19 | 20 | // reference https://mp.weixin.qq.com/s/vsKrWRlETxCVsiRr8v_hHg -------------------------------------------------------------------------------- /LC701_Insert into a Binary Search Tree_Recursion.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode() : val(0), left(nullptr), right(nullptr) {} 8 | * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 9 | * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} 10 | * }; 11 | */ 12 | class Solution { 13 | public: 14 | TreeNode* insertIntoBST(TreeNode* root, int val) { // 增加的节点和原有的都不相同 15 | if (root == NULL ) { // 节点空,就加一个,然后返回 16 | TreeNode* node = new TreeNode(val); 17 | return node; 18 | } 19 | if (val > root->val) root->right = insertIntoBST(root->right, val); // 因为BST有序,所以可以这样增加。注意,增加的和原有的不同,所以不取等号 20 | if (val < root->val) root->left = insertIntoBST(root->left, val); 21 | return root; 22 | } 23 | }; 24 | 25 | // reference https://mp.weixin.qq.com/s/lwKkLQcfbCNX2W-5SOeZEA -------------------------------------------------------------------------------- /LC705_Design HashSet_HashTable.java: -------------------------------------------------------------------------------- 1 | class MyHashSet { // 哈希表思想的应用 2 | // 本题需要设计一个哈希表,设计过程中不能调用哈希表的函数。虽然如此,我们依然可以借鉴哈希表的思想, 3 | // 设输入的数值为key,对应的value为true或false。已经知道输入数据的大小范围之后,设定一个不小于这个范围 4 | // 的数组,数组的下标就是key,对应数值是true或false。利用这样的想法结合题目,可以得到下面的代码。 5 | /** Initialize your data structure here. */ 6 | boolean nodes[] = new boolean[1000009]; 7 | 8 | public void add(int key) { 9 | nodes[key] = true; 10 | } 11 | 12 | public void remove(int key) { 13 | nodes[key] = false; 14 | } 15 | 16 | /** Returns true if this set contains the specified element */ 17 | public boolean contains(int key) { 18 | return nodes[key]; 19 | } 20 | } 21 | 22 | /** 23 | * Your MyHashSet object will be instantiated and called as such: 24 | * MyHashSet obj = new MyHashSet(); 25 | * obj.add(key); 26 | * obj.remove(key); 27 | * boolean param_3 = obj.contains(key); 28 | */ -------------------------------------------------------------------------------- /LC706_Design HashMap_HashTable.java: -------------------------------------------------------------------------------- 1 | class MyHashMap { // 本题和LC705思路一致 2 | 3 | private int[] res; 4 | 5 | public MyHashMap() { 6 | res = new int[1000001]; 7 | Arrays.fill(res, -1); 8 | } 9 | 10 | public void put(int key, int value) { 11 | res[key] = value; 12 | } 13 | 14 | public int get(int key) { 15 | return res[key]; 16 | } 17 | 18 | public void remove(int key) { 19 | res[key] = -1; 20 | } 21 | } 22 | // reference https://leetcode-cn.com/problems/design-hashmap/solution/she-ji-ha-xi-ying-she-shu-zu-xia-biao-bi-xrq9/ -------------------------------------------------------------------------------- /LC714_Ans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/LC714_Ans.jpg -------------------------------------------------------------------------------- /LC714_Best Time to Buy and Sell Stock with Transaction Fee_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProfit(vector& prices, int fee) { 4 | vector dp(2, 0); 5 | dp[0] = 0; // 一开始没东西,不做操作,所以是0 6 | dp[1] = -prices[0]; // 买入,所以负数 7 | for (int i = 1 ; i < prices.size(); i++) { 8 | dp[0] = max(dp[0], prices[i] + dp[1] - fee); // 卖出 9 | dp[1] = max(dp[1], dp[0] - prices[i]); // 买入 10 | } 11 | return dp[0]; 12 | } 13 | }; 14 | 15 | // reference https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/solution/jian-dan-dpmiao-dong-gu-piao-mai-mai-by-tejdo/ 16 | 17 | /* 18 | 详见Solution中的图解,这里是二维的简化。 19 | 因为要获得最大利润,所以都要max。 20 | 操作过程无非买入或卖出,最后的输出应该是最后一天的情况,所以应该就是卖出对应的数值,不是买入的,所以是dp[0]。 21 | */ -------------------------------------------------------------------------------- /LC714_Best Time to Buy and Sell Stock with Transaction Fee_DP.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int maxProfit(int[] prices, int fee) { 3 | int n = prices.length; 4 | int[] dp = new int[2]; 5 | dp[0] = 0; 6 | dp[1] = -prices[0]; 7 | for (int i = 1; i < n; i++) { 8 | dp[0] = Math.max(dp[0], dp[1] + prices[i] - fee); 9 | dp[1] = Math.max(dp[1], dp[0] - prices[i]); 10 | } 11 | return dp[0]; 12 | } 13 | } 14 | 15 | // reference https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/solution/jian-dan-dpmiao-dong-gu-piao-mai-mai-by-tejdo/ 16 | // 详解见C++版 -------------------------------------------------------------------------------- /LC718_Maximum Length of Repeated Subarray_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findLength(vector& A, vector& B) { // 动态规划 注意本题需要求的是连续重复的子串 最长重复子数组 4 | vector> dp (A.size() + 1, vector(B.size() + 1, 0)); // 初始化 5 | // 此处,dp[i][j]代表:以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度为dp[i][j]。 6 | int result = 0; 7 | for (int i = 1; i <= A.size(); i++) { // A或B在内或外循环都可以;注意,这里for循环从1开始,是为了方便后续的递推公式和dp数组的定义 8 | for (int j = 1; j <= B.size(); j++) { 9 | if (A[i - 1] == B[j - 1]) { // 如果当前字符相等 10 | dp[i][j] = dp[i - 1][j - 1] + 1; // 那么长度+1 11 | } // 如果当前字符不相等,那么不用管了,因为长度的初值已经赋为0 12 | if (dp[i][j] > result) result = dp[i][j]; // 我们需要搜集最长的长度 13 | } 14 | } 15 | return result; 16 | } 17 | }; 18 | 19 | // reference https://mp.weixin.qq.com/s/U5WaWqBwdoxzQDotOdWqZg -------------------------------------------------------------------------------- /LC724_Find Pivot Index_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int pivotIndex(vector& nums) { 4 | int leftSum = 0; 5 | int rightSum = 0; 6 | int sum = 0; 7 | for (int num : nums) { 8 | sum += num; 9 | } 10 | for (int i = 0; i < nums.size(); i++) { 11 | leftSum += nums[i]; 12 | rightSum = sum - leftSum + nums[i]; 13 | if (leftSum == rightSum) return i; 14 | } 15 | return -1; 16 | } 17 | }; 18 | 19 | // reference https://leetcode-cn.com/problems/find-pivot-index/solution/724-xun-zhao-shu-zu-de-zhong-xin-suo-yin-h18i/ 20 | /* 21 | 本题用最基本的模拟法就可求解,但是需要一定的数学推导: 22 | 由题目要求可知,中心索引左侧和值和右侧和值相等。那么左侧和值加上中心索引对应数值应该和右侧和值加上中心索引对应数值相等 23 | 上述解法中,leftsum就是左侧和值加上中心索引对应数值,那么与之对应相等的,就是右侧和值加上中心索引数值。 24 | 这样一来,就有了上述的leftsum与rightsum的代码 25 | 判断它们是否相等,输出索引即可。 26 | */ -------------------------------------------------------------------------------- /LC72_Edit Distance.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Aug 22 15:43:37 2020 4 | 5 | @author: Three 6 | """ 7 | #关键在于要留有0行0列的留白 8 | def EditDistance(word1,word2): 9 | n1 = len(word1) 10 | n2 = len(word2) 11 | 12 | dp = [[0]*(n1+1) for _ in range(n2+1)] 13 | 14 | for i in range(1,n2+1): 15 | dp[i][0] = dp[i-1][0] + 1 16 | for j in range(1,n1+1): 17 | dp[0][j] = dp[0][j-1] + 1 18 | 19 | for i in range(1,n2+1): 20 | for j in range(1,n1+1): 21 | if word2[i-1] == word1[j-1]: 22 | dp[i][j] = dp[i-1][j-1] 23 | else: 24 | dp[i][j] = min(dp[i-1][j],dp[i-1][j-1],dp[i][j-1]) + 1 25 | 26 | return dp[-1][-1] 27 | 28 | word1 = input() 29 | word2 = input() 30 | print(EditDistance(word1,word2)) -------------------------------------------------------------------------------- /LC739_Daily Temperatures_Stack.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector dailyTemperatures(vector& T) { // stack的使用 4 | vector result(T.size(), 0); // 初始化 5 | stack st; 6 | for (int i = 0; i < T.size(); i++) { 7 | while (!st.empty() && T[i] > T[st.top()]) { // 当栈顶有元素且元素比当前值小,那么栈顶元素出栈 8 | auto t = st.top(); // 出栈处理 9 | st.pop(); 10 | result[t] = i - t; // 计算多少天温度可以更高 11 | } 12 | st.push(i); // 对应温度的index入栈 13 | } 14 | return result; 15 | } 16 | }; 17 | 18 | // reference https://leetcode-cn.com/problems/daily-temperatures/solution/leetcode-tu-jie-739mei-ri-wen-du-by-misterbooo/ 具体详解见链接中的动画 -------------------------------------------------------------------------------- /LC73_Set Matrix Zeroes_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void setZeroes(vector>& matrix) { // 模拟法 4 | int m = matrix.size(); 5 | int n = matrix[0].size(); 6 | vector row(m), col(n); // 记录零的行位置和列位置 7 | for (int i = 0; i < m; i++) { 8 | for (int j = 0; j < n; j++) { 9 | if (!matrix[i][j]) { 10 | row[i] = col[j] = true; 11 | } 12 | } 13 | } 14 | for (int i = 0; i < m; i++) { 15 | for (int j = 0; j < n; j++) { 16 | if (row[i] || col[j]) { // 零的同行或者同列置零 17 | matrix[i][j] = 0; 18 | } 19 | } 20 | } 21 | } 22 | }; 23 | 24 | 25 | // reference https://leetcode-cn.com/problems/set-matrix-zeroes/solution/ju-zhen-zhi-ling-by-leetcode-solution-9ll7/ -------------------------------------------------------------------------------- /LC746_Min Cost Climbing Stairs_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int minCostClimbingStairs(vector& cost) { // 动态规划 4 | int n = cost.size(); 5 | vector dp(n + 1, 0); 6 | for (int i = 2; i <= n; i++) { // i最大可以取到n,代表dp的vector有n+1的长度。这样一来,可以把最后一个n+1的位置独立地当成是楼顶,其他 7 | // 楼层在往上爬的过程中,再将cost加上。即要离开了再加上。这样一来,对cost的处理和dp的处理就变得更加简单。 8 | dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]); 9 | } 10 | return dp[n]; 11 | } 12 | }; -------------------------------------------------------------------------------- /LC74_Search a 2D Matrix_Binary Search.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool searchMatrix(vector>& matrix, int target) { // 二分法,核心思想是把矩阵拉成一条数组。 4 | // 可行的原因是每一行开头的数值比上一行末尾的大。可以把下一行拼接到上一行,最后将矩阵变成一行。 5 | int m = matrix.size(), n = matrix[0].size(); // 得到矩阵行和列 6 | int left = 0, right = m * n - 1; // 左边位置和右边位置 7 | while (left <= right) { // 二分法套路 8 | int mid = (right - left) / 2 + left; // 这样设置防止溢出的风险 9 | int x = matrix[mid / n][mid % n]; // 善于利用矩阵位置和除法运算与取模运算的关系 10 | if (x < target) { // 目标数值太大 11 | left = mid + 1; 12 | } else if (x > target) { // 目标数值小 13 | right = mid - 1; 14 | } else { 15 | return true; // 找到了 16 | } 17 | } 18 | return false; // 没找到 19 | } 20 | }; 21 | 22 | // reference https://leetcode-cn.com/problems/search-a-2d-matrix/solution/sou-suo-er-wei-ju-zhen-by-leetcode-solut-vxui/ -------------------------------------------------------------------------------- /LC74_Search a 2D Matrix_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool searchMatrix(vector>& matrix, int target) { // 模拟法,从矩阵右上角元素开始。 4 | 5 | int column = matrix[0].size() - 1; // 列 6 | int row = 0; // 行 7 | while (row <= matrix.size() - 1 && column >= 0) { 8 | if (target == matrix[row][column]) { 9 | // 找到就直接返回 10 | return true; 11 | } else if (target < matrix[row][column]) { 12 | // 如果目标值小,那么下一步往左找 13 | column--; 14 | } else if (target > matrix[row][column]) { 15 | // 如果目标值大,那么下一步往下找 16 | row++; 17 | } 18 | } 19 | return false; // 没找到 20 | } 21 | }; 22 | 23 | // reference https://leetcode-cn.com/problems/search-a-2d-matrix-ii/solution/3chong-jie-fa-zui-hao-de-ji-bai-liao-100-5ozh/ -------------------------------------------------------------------------------- /LC75_Sort Colors_Double Pointer.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void sortColors(vector& nums) { // 双指针法 4 | int p1 = 0, p2 = nums.size() - 1; 5 | for (int i = 0; i < nums.size(); i++) { 6 | while (i <= p2 && nums[i] == 2) { // 当数值等于2的时候 7 | swap(nums[i], nums[p2]); // 与最右边进行交换,并且同时把最右指针-1 8 | p2--; // 因为只有0,1, 2三个数值,并且0在左,2在右。所以分析的时候,可以从0和2着手即可 9 | } 10 | if (nums[i] == 0) { // 数值为0时,与最左边的p1指针交换 11 | swap(nums[i], nums[p1]); 12 | p1++; // 交换之后,p1++ 13 | } // 这里先用while之后用if,是while处理2之后,才有if来处理1与0这两个选择的机会。需要先while,后面才有if。 14 | } 15 | } 16 | }; 17 | 18 | // reference https://leetcode-cn.com/problems/sort-colors/solution/yan-se-fen-lei-by-leetcode-solution/ -------------------------------------------------------------------------------- /LC763_Partition Labels_Greedy Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector partitionLabels(string S) { // 贪心算法 4 | int hash[26] = {0}; // 26个字母 5 | for (int i = 0; i < S.size(); i++) { // 对string中每个字母处理 6 | hash[S[i] - 'a'] = i; // 统计不同字母出现的最远位置,随着i的遍历,这个值自动更新。 7 | } 8 | int left = 0, right = 0; 9 | vector result; 10 | for (int i = 0; i < S.size(); i++) { 11 | right = max(right, hash[S[i] - 'a']); // 找到某个字母对应的最远距离,将不同字母的最远距离比较,取较大的数值。 12 | if (right == i) { // 如果这个较大的数值可以正好等于i,那么代表这个i前面的字母串是可以分开的。 13 | result.push_back(right - left + 1); // 统计长度 14 | left = i + 1; // 前面的字母统计过了,之后统计后面的,所以left=i+1 15 | } 16 | } 17 | return result; 18 | } 19 | }; 20 | 21 | // reference https://mp.weixin.qq.com/s/pdX4JwV1AOpc_m90EcO2Hw 22 | // 确定分割点的关键是:一直找某个字母最后一次出现的位置,并且取较大的位置。一直到当遍历的i和最后一个位置相等的时候,代表前面可以成为一串,且不能再长了。所以 23 | // 进行分割。之后再对后面的字符串进行处理,重复上述过程。 详细图解见链接 -------------------------------------------------------------------------------- /LC765_Couples Holding Hands_Bit Operation.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int minSwapsCouples(vector& row) { 4 | int result = 0; 5 | int n = row.size(); 6 | for (int i = 0; i < n; i += 2) { 7 | if (row[i] == (row[i + 1] ^ 1)) continue; // 运用异或运算判断是不是一对情侣 8 | for (int j = i + 1; j < n; j++) { // 如果不是,再进行搜寻 9 | if ((row[j] ^ 1) == row[i]) { // 找到了另一半 10 | swap(row[i + 1], row[j]); // 交换座位 11 | result++; // 交换次数+1 12 | break; 13 | } 14 | } 15 | } 16 | return result; 17 | } 18 | }; -------------------------------------------------------------------------------- /LC765_Couples Holding Hands_Bit Operation.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def minSwapsCouples(self, row: List[int]) -> int: # 暴力解,异或运算 3 | result = 0 4 | for i in range(0, len(row), 2): 5 | if row[i] == row[i + 1] ^ 1: # 运用异或运算判断是不是一对情侣 6 | continue 7 | for j in range(i + 2, len(row), 1): # 如果不是,再进行搜寻 8 | if row[j] ^ 1 == row[i]: # 搜到了,那么接下来进行座位交换 9 | row[i + 1], row[j] = row[j], row[i + 1] 10 | result += 1 # 交换次数+1 11 | break 12 | return result # 得到总的交换次数 13 | # reference https://leetcode-cn.com/problems/couples-holding-hands/solution/qing-lu-qian-shou-by-leetcode/ 14 | 15 | # 那么,为什么可以用异或呢? 异或运算:相同两个数字,结果为0;不同为1.可以用异或判断两个数字是否相等。此处用处不在此,在于: 16 | # 将数字转为2进制: 1 → 0001 2 → 0010 3 → 0011,Python中,^代表异或(同C++)。所以 0001 ^ 0010 = 0011 = 3 17 | # 反过来,0001 ^ 0011 = 0010 = 2。这就表明,题目中对应的情侣号可以用异或运算实现。(多试几组,显然也是如此) 18 | # 总的来说,可以用上述异或运算做判别,这也是因为题目中对情侣号的限定导致的有趣结果。位运算有时候可以有点睛之笔的作用。 -------------------------------------------------------------------------------- /LC766_Toeplitz Matrix_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isToeplitzMatrix(vector>& matrix) { // 模拟法 4 | for (int i = 0; i < matrix.size() - 1; i++) { 5 | for (int j = 0; j < matrix[0].size() - 1; j++) { 6 | if (matrix[i][j] != matrix[i + 1][j + 1]) { // 本题虽是模拟法,但也讲究方法。只需要跟右下角的元素比较即可。 7 | return false; 8 | } 9 | } 10 | } 11 | return true; 12 | } 13 | }; 14 | 15 | // reference https://leetcode-cn.com/problems/toeplitz-matrix/solution/pan-duan-mei-ge-yuan-su-he-ta-de-you-xia-x3fi/ -------------------------------------------------------------------------------- /LC77_Combinations_Backtracking.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | private: 3 | vector> result; 4 | vector path; 5 | void backtracking(int index,int n,int k){ 6 | if(path.size()==k){ 7 | result.push_back(path); 8 | return; 9 | } 10 | for(int i=index;i> combine(int n, int k) { 19 | result.clear(); 20 | path.clear(); 21 | backtracking(0,n,k); 22 | return result; 23 | } 24 | }; 25 | 26 | // reference https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ -------------------------------------------------------------------------------- /LC781_Rabbits in Forest_Greedy Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int numRabbits(vector &answers) { // 贪心算法 4 | unordered_map count; // 用一个哈希表记录每个数字出现的次数 5 | for (int y : answers) { // 记录频次 6 | count[y]++; 7 | } 8 | int ans = 0; 9 | for (auto &[y, x] : count) { // 这种语法值得学习 10 | // 有x只兔子都回答y,则至少有 向上取整(x / (y + 1)) 种不同的颜色,且每种颜色有y+1只兔子,因此兔子数至少为 向上取整的数值乘以(y + 1)。 11 | ans += (x + y) / (y + 1) * (y + 1); // 这是向上取整的意思,需要记住! 12 | } 13 | return ans; 14 | } 15 | }; 16 | 17 | // reference https://leetcode-cn.com/problems/rabbits-in-forest/solution/sen-lin-zhong-de-tu-zi-by-leetcode-solut-kvla/ -------------------------------------------------------------------------------- /LC783_Minimum Distance Between BST Nodes v3_Recursion.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int result = INT_MAX; 4 | int pre = -1; // 此处pre仅仅存为一个数值,不用做Treenode*的指针 5 | void traversal(TreeNode* cur) { // 中序遍历,边遍历边比较 6 | if (cur == NULL) return; 7 | traversal(cur->left); // 左 8 | if (pre != -1){ // 中 9 | result = min(result, cur->val - pre); // 此时处理比较大小的事情 10 | } 11 | pre = cur->val; // 更新pre 12 | traversal(cur->right); // 右 13 | } 14 | int minDiffInBST(TreeNode* root) { 15 | traversal(root); 16 | return result; // 得到结果 17 | } 18 | }; 19 | 20 | // reference https://leetcode-cn.com/problems/minimum-distance-between-bst-nodes/solution/yi-ti-shuang-jie-liang-chong-fang-fa-fei-ieqc/ -------------------------------------------------------------------------------- /LC78_Subsets_Backtracking.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | private: 3 | vector> result; 4 | vector path; 5 | void backtracking(vector& nums,int index){ 6 | result.push_back(path); // 放在一开头加进result,便于空集第一个加入,方便 7 | for(int i=index;i> subsets(vector& nums) { 16 | result.clear(); 17 | path.clear(); 18 | backtracking(nums,0); // index从0开始 19 | return result; 20 | } 21 | }; 22 | 23 | // reference https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA -------------------------------------------------------------------------------- /LC7_Reverse Integer_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int reverse(int x) { 4 | int y = 0; 5 | while (x != 0) { 6 | if (y > 214748364 || y < -214748364) return 0; // 溢出,那么输出为0 7 | y = y * 10 + x % 10; // y在变化的同时x也在变化,效率高 8 | x = x / 10; 9 | } 10 | return y; 11 | } 12 | }; 13 | 14 | // reference https://leetcode-cn.com/problems/reverse-integer/solution/hua-jie-suan-fa-7-zheng-shu-fan-zhuan-by-guanpengc/ 15 | 16 | // 溢出的数字是由2的31次方-1和负2的31次方决定。此外,由于这是x的界限,且x需要/10,所以实际上,214748364是2的31次方-1与负2的31次方除法之后的结果 -------------------------------------------------------------------------------- /LC80_Remove Duplicates from Sorted Array II_Brain Teaser.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int removeDuplicates(vector& nums) { // 数组操作,思路偏脑筋急转弯 4 | int i = 0; 5 | for (int num : nums) { // 遍历数组中的元素 6 | if (i < 2 || nums[i - 2] < num) nums[i++] = num; // 因为至多两个元素连续,并且根据题目要求元素大小递增 7 | // 新的nums是在原有的nums下更新的,这个新的nums不会把原来nums全部元素都更新,它会更新前面一部分的内容 8 | // 更新的范围就是0到i,最后return i就好。如果是返回更新之后的nums,那么在原有nums的基础上截取前i个的部分即可 9 | } 10 | return i; 11 | } 12 | }; 13 | 14 | // reference https://leetcode-cn.com/u/yinyinnie/ 15 | // 本题是“原地改动”数组的模范题目,还有其他的“原地”修改的题目和本题思路相似,都是直接在原数组上进行更新,但前面更新之后的内容 16 | // 不会影响到后面正在进行的操作。需要掌握这种思想 -------------------------------------------------------------------------------- /LC80_Remove Duplicates from Sorted Array II_Double Pointer.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int removeDuplicates(vector& nums) { // 双指针法 4 | int n = nums.size(); 5 | if (n <= 2) { // 特殊判断,如果nums长度小于2,直接输出长度n即可 6 | return n; 7 | } 8 | int slow = 2, fast = 2; // 因为上面已经做过特殊判别,所以这里快慢指针从2开始 9 | while (fast < n) { 10 | if (nums[slow - 2] != nums[fast]) { // 因为题目要求最多两个数相同,所以这么判断 11 | // 如果nums[slow - 2] == nums[fast],代表已经有两个数相等,此时nums[fast] 12 | // 对应的数值不能放进结果之中。反之,如果nums[slow - 2] != nums[fast], 13 | // 那么nums[fast]可以放进nums[slow]中,并且slow++,记录结果的长度。 14 | nums[slow] = nums[fast]; 15 | slow++; 16 | } 17 | fast++; // 不管怎么样,快指针都是要向前遍历各个元素的 18 | } 19 | return slow; // 返回结果的长度,即slow 20 | } 21 | }; 22 | 23 | // reference https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii/solution/ju-yi-fan-er-ni-zhen-de-zhen-de-zhi-de-x-eicz/ 24 | -------------------------------------------------------------------------------- /LC812_Largest Triangle Area_Math.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public double largestTriangleArea(int[][] points) { // 鞋带公式 数学暴力解 此外还可以用海伦公式 可以调用Python的NumPy 3 | int N = points.length; 4 | double ans = 0; 5 | for (int i = 0; i < N; ++i) 6 | for (int j = i+1; j < N; ++j) 7 | for (int k = j+1; k < N; ++k) 8 | ans = Math.max(ans, area(points[i], points[j], points[k])); 9 | return ans; 10 | } 11 | 12 | public double area(int[] P, int[] Q, int[] R) { 13 | return 0.5 * Math.abs(P[0]*Q[1] + Q[0]*R[1] + R[0]*P[1] 14 | -P[1]*Q[0] - Q[1]*R[0] - R[1]*P[0]); 15 | } 16 | } 17 | 18 | // https://leetcode-cn.com/problems/largest-triangle-area/solution/zui-da-san-jiao-xing-mian-ji-by-leetcode/ -------------------------------------------------------------------------------- /LC830_Positions of Large Groups_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> largeGroupPositions(string s) { // 直接使用模拟法即可 4 | vector> res; 5 | int n = s.size(); 6 | int num = 1; 7 | for (int i = 0; i < n; i++) { 8 | if (i == n - 1 || s[i] != s[i + 1]) { // 注意最后一个元素的判别,如果是最后一个了,那么需要特殊判断一下 9 | if (num >= 3) { 10 | res.push_back({i - num + 1, i}); 11 | } 12 | num = 1; 13 | } else { 14 | num++; 15 | } 16 | } 17 | return res; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /LC83_Remove Duplicates from Sorted List_Linked List.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode() : val(0), next(nullptr) {} 7 | * ListNode(int x) : val(x), next(nullptr) {} 8 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 9 | * }; 10 | */ 11 | class Solution { 12 | public: 13 | ListNode* deleteDuplicates(ListNode* head) { // 链表 本题根据题目要求,跳过重复值的节点即可 14 | ListNode* cur = head; 15 | while (cur != nullptr && cur->next != nullptr) { 16 | if (cur->val == cur->next->val) { 17 | cur->next = cur->next->next; 18 | } 19 | else { 20 | cur = cur->next; 21 | } 22 | } 23 | return head; 24 | } 25 | }; 26 | 27 | // 注意::java和python的指针,使用.;C++使用->!! -------------------------------------------------------------------------------- /LC860_Lemonade Change_Greedy Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool lemonadeChange(vector& bills) { // 找零无非几种情况:1.5美金不用找;2.10美金找5元;3.20美金,找10+5或者5+5+5.优先10+5,因为5美元更有用。 4 | // 这样一来,也有贪心的思路在里面。按照这个逻辑,写判断即可。 5 | int five = 0, ten = 0, twenty = 0; 6 | for (int bill : bills) { 7 | if (bill == 5) five++; 8 | if (bill == 10) { 9 | if (five == 0) return false; 10 | else { 11 | five--; 12 | ten++; 13 | } 14 | } 15 | if (bill == 20) { 16 | if (ten != 0 && five != 0) { 17 | ten--; 18 | five--; 19 | } 20 | else if (five >= 3) { 21 | five -= 3; 22 | } 23 | else return false; 24 | } 25 | } 26 | return true; 27 | } 28 | }; 29 | 30 | // reference https://mp.weixin.qq.com/s/0kT4P-hzY7H6Ae0kjQqnZg -------------------------------------------------------------------------------- /LC867_Transpose Matrix_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector > transpose(vector>& A) { 4 | int row = A.size(), col = A[0].size(); 5 | vector> B(col, vector(row, 0)); // 把原来矩阵的行列反转 6 | for (int i = 0; i < row; i++){ 7 | for (int j = 0; j < col; j++){ 8 | B[j][i] = A[i][j]; 9 | } 10 | } 11 | return B; 12 | } 13 | }; -------------------------------------------------------------------------------- /LC888_Fair Candy Swap_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector fairCandySwap(vector& A, vector& B) { // 数学题 4 | int sumA = accumulate(A.begin(), A.end(), 0); // C++中可以直接求和的函数 5 | int sumB = accumulate(B.begin(), B.end(), 0); 6 | int delta = (sumA - sumB) / 2; // 可以对本题先进行简单的数学推导,然后得到这个式子 7 | vector result; 8 | unordered_set table(A.begin(), A.end()); // 把元素存入表中,之后方便查看各个元素是否存在 9 | for (auto& y : B) { 10 | int x = y + delta; // 式子由数学推导得到。如果满足题目要求,那么x与y应该有这样的关系。可以从y入手找可否有x存在 11 | // 因此用到哈希表判断一个数值是否存在 12 | if (table.count(x)) { 13 | result = vector {x, y}; 14 | break; 15 | } 16 | } 17 | return result; 18 | } 19 | }; 20 | 21 | // 题目虽简单,但还是有值得学习的处理方法; 22 | // 因为返回一个即可,所以可使用unordered_set; 23 | // accumulate方法在C++中可以有求和效果。 -------------------------------------------------------------------------------- /LC896_Monotonic Array (API)_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isMonotonic(vector &A) { 4 | return is_sorted(A.begin(), A.end()) || is_sorted(A.rbegin(), A.rend()); // 第二个迭代器是倒序的 5 | } 6 | }; 7 | 8 | // 调用相关函数求解 -------------------------------------------------------------------------------- /LC896_Monotonic Array_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isMonotonic(vector &A) { // 模拟法,判断单调性即可 4 | bool increase = true, decrease = true; 5 | int n = A.size(); 6 | for (int i = 0; i < n - 1; ++i) { 7 | if (A[i] > A[i + 1]) { 8 | increase = false; 9 | } 10 | if (A[i] < A[i + 1]) { 11 | decrease = false; 12 | } 13 | } 14 | return increase || decrease; 15 | } 16 | }; 17 | 18 | // 本题不难,把握单调递增和单调递减两种情况就好 -------------------------------------------------------------------------------- /LC90_ClimbStairs.py: -------------------------------------------------------------------------------- 1 | def ClimbStairs(stairs): 2 | num = [0]*(stairs+1) 3 | num[0] = 0 4 | num[1] = 1 5 | num[2] = 2 6 | for i in range(3,stairs+2): 7 | num[i] = num[i-1] + num[i-2] 8 | return num[stairs] 9 | 10 | 11 | stairs = int(input()) 12 | print(ClimbStairs(stairs)) 13 | -------------------------------------------------------------------------------- /LC912_Sort an Array_Quick Sort.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def sortArray(self, nums: List[int]) -> List[int]: # 快速排序 模板题 3 | # Baseline 4 | if len(nums) < 2: 5 | return nums 6 | else: 7 | pivot = nums[0] 8 | greater = [i for i in nums[1:] if i > pivot] 9 | less = [i for i in nums[1:] if i < pivot] 10 | equal = [i for i in nums[1:] if i == pivot] 11 | return self.sortArray(less) + equal + [pivot] + self.sortArray(greater) -------------------------------------------------------------------------------- /LC941_Valid Mountain Array_Double Pointer.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool validMountainArray(vector& arr) { 4 | if (arr.size() < 3) return false; 5 | int left = 0; 6 | int right = arr.size() - 1; 7 | bool flagUp = false; 8 | bool flagDown = false; 9 | while ((left < arr.size() - 1) && (arr[left] < arr[left + 1])) { 10 | left++; 11 | flagUp = true; 12 | } 13 | while (right > 0 && arr[right] < arr[right - 1]) { 14 | right--; 15 | flagDown = true; 16 | } 17 | if (((left == right) && flagDown) && flagUp) return true; 18 | return false; 19 | } 20 | }; -------------------------------------------------------------------------------- /LC94_Binary Tree Inorder Traversal_Recursion.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void inorder(TreeNode* root, vector& res) { // 树的中序遍历 4 | if (!root) { 5 | return; 6 | } 7 | inorder(root->left, res); 8 | res.push_back(root->val); 9 | inorder(root->right, res); 10 | } 11 | vector inorderTraversal(TreeNode* root) { 12 | vector res; 13 | inorder(root, res); 14 | return res; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /LC94_Binary Tree Inorder Traversal_Recursion.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Wed Nov 4 13:48:40 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | # Definition for a binary tree node. 9 | class TreeNode: 10 | def __init__(self, val=0, left=None, right=None): 11 | self.val = val 12 | self.left = left 13 | self.right = right 14 | class Solution: 15 | def inorderTraversal(self, root): 16 | if root is None: return [] # 审题,要输出list不是int 17 | 18 | return self.inorderTraversal(root.left) + [root.val] + self.inorderTraversal(root.right) 19 | 20 | root = TreeNode(2) 21 | root.left = TreeNode(10) 22 | root.right = TreeNode(24) 23 | 24 | res = Solution() 25 | print(res.inorderTraversal(root)) -------------------------------------------------------------------------------- /LC96_Unique Binary Search Trees_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int numTrees(int n) { 4 | vector result(n + 1, 0); // 用vector定义比用数组定义更好 5 | result[0] = 1; // 初始化 6 | result[1] = 1; // 赋初值 7 | for (int i = 2; i < n + 1; i++){ 8 | for(int j = 1; j < i + 1; j++){ 9 | result[i] += result[j - 1] * result[i - j]; // 卡特兰数求值 本问题可以理解成卡特兰数的应用,具体见参考链接 10 | } 11 | } 12 | return result[n]; 13 | } 14 | }; 15 | 16 | // reference https://leetcode-cn.com/problems/unique-binary-search-trees/solution/bu-tong-de-er-cha-sou-suo-shu-by-leetcode-solution/ -------------------------------------------------------------------------------- /LC96_Unique Binary Search Trees_Math.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int numTrees(int n) { 3 | int[] dp = new int[n+1]; 4 | dp[0] = 1; 5 | dp[1] = 1; 6 | 7 | for(int i = 2; i < n + 1; i++) 8 | for(int j = 1; j < i + 1; j++) 9 | dp[i] += dp[j-1] * dp[i-j]; 10 | 11 | return dp[n]; 12 | } 13 | } 14 | 15 | // reference https://leetcode-cn.com/problems/unique-binary-search-trees/solution/hua-jie-suan-fa-96-bu-tong-de-er-cha-sou-suo-shu-b/ -------------------------------------------------------------------------------- /LC976_Largest Perimeter Triangle_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int largestPerimeter(vector& A) { // 两边之和大于第三边,先进行排序,从大到小遍历,找到最先满足的即可。因为再往后肯定更差。 4 | sort(A.begin(), A.end()); 5 | for (int i = A.size() - 1; i >= 2; i--){ 6 | if(A[i - 2] + A[i - 1] > A[i]){ 7 | return A[i - 2] + A[i - 1] + A[i]; 8 | } 9 | } 10 | return 0; 11 | } 12 | }; 13 | 14 | -------------------------------------------------------------------------------- /LC995_Minimum Number of K Consecutive Bit Flips_Sliding Window.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int minKBitFlips(vector& A, int K) { // 滑动窗口 队列 4 | int len = A.size(); 5 | queue que; 6 | int result = 0; 7 | for (int i = 0; i < len; i++) { 8 | if (!que.empty() && i >= que.front() + K) { // que不空,并且que最前面的元素已经在滑窗外,“过期了” 9 | que.pop(); // 弹出 10 | } 11 | if (que.size() % 2 == A[i]) { // 这里判断的原因详见Solution中的图,很巧妙。把各种情况都考虑到了 12 | if (i + K > len) return -1; // 如果滑窗超过了数组长度,那么失败 13 | result++; // 成功。那么就把翻转次数++ 14 | que.push(i); // 把开始翻转的index(位置)放进队列 15 | } 16 | } 17 | return result; 18 | } 19 | }; 20 | 21 | // reference https://leetcode-cn.com/problems/minimum-number-of-k-consecutive-bit-flips/solution/hua-dong-chuang-kou-shi-ben-ti-zui-rong-z403l/ -------------------------------------------------------------------------------- /LC9_Palindrome Number_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isPalindrome(int x) { 4 | if (x < 0) return false; 5 | long long y = 0; // 防止溢出 6 | int flag = x; // 留一个做比较 7 | while(x != 0){ // 常见处理 8 | y = y * 10 + x % 10; 9 | x = x / 10; 10 | } 11 | return flag == y; // 写成逻辑式,更简单 12 | } 13 | }; 14 | 15 | // 本题可以把数位放进队列,之后再弹出来。但能简单就用简单方法,不见得都要用数据结构。 16 | -------------------------------------------------------------------------------- /POJ1000_A+B Problem_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main(void) { 5 | int a, b; 6 | cin >> a; 7 | cin >> b; 8 | cout << a + b << endl; 9 | 10 | return 0; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /POJ1004_Financial Management_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | 6 | int main(void) { 7 | const int N = 12; 8 | double sum = 0.0; 9 | 10 | for(int i = 0; i < N; i++) { 11 | double num = 0.0; 12 | cin >> num; 13 | sum += num; 14 | } 15 | 16 | double avg = sum / N; 17 | cout << fixed << setprecision(2) << '$' << avg << endl; 18 | 19 | return 0; 20 | } 21 | 22 | // 注意数据类型! -------------------------------------------------------------------------------- /Solution/LC1004_Ans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC1004_Ans.jpg -------------------------------------------------------------------------------- /Solution/LC11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC11.jpg -------------------------------------------------------------------------------- /Solution/LC134.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC134.jpg -------------------------------------------------------------------------------- /Solution/LC134_Ans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC134_Ans.jpg -------------------------------------------------------------------------------- /Solution/LC204_Ans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC204_Ans.jpg -------------------------------------------------------------------------------- /Solution/LC21_Ans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC21_Ans.jpg -------------------------------------------------------------------------------- /Solution/LC238_Ans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC238_Ans.jpg -------------------------------------------------------------------------------- /Solution/LC304_Ans1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC304_Ans1.jpg -------------------------------------------------------------------------------- /Solution/LC304_Ans2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC304_Ans2.jpg -------------------------------------------------------------------------------- /Solution/LC392_Ans1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC392_Ans1.jpg -------------------------------------------------------------------------------- /Solution/LC392_Ans2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC392_Ans2.jpg -------------------------------------------------------------------------------- /Solution/LC406_Ans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC406_Ans.jpg -------------------------------------------------------------------------------- /Solution/LC459_Ans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC459_Ans.jpg -------------------------------------------------------------------------------- /Solution/LC47解题思路.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC47解题思路.png -------------------------------------------------------------------------------- /Solution/LC50_Ans1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC50_Ans1.jpg -------------------------------------------------------------------------------- /Solution/LC50_Ans2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC50_Ans2.jpg -------------------------------------------------------------------------------- /Solution/LC543_Ans_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC543_Ans_1.jpg -------------------------------------------------------------------------------- /Solution/LC543_Ans_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC543_Ans_2.jpg -------------------------------------------------------------------------------- /Solution/LC5_Ans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC5_Ans.jpg -------------------------------------------------------------------------------- /Solution/LC61_Ans1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC61_Ans1.png -------------------------------------------------------------------------------- /Solution/LC61_Ans2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC61_Ans2.png -------------------------------------------------------------------------------- /Solution/LC647.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC647.jpg -------------------------------------------------------------------------------- /Solution/LC647_Ans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC647_Ans.jpg -------------------------------------------------------------------------------- /Solution/LC669_Ans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC669_Ans.jpg -------------------------------------------------------------------------------- /Solution/LC714_Ans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC714_Ans.jpg -------------------------------------------------------------------------------- /Solution/LC778_Ans.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC778_Ans.gif -------------------------------------------------------------------------------- /Solution/LC91_Ans.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC91_Ans.png -------------------------------------------------------------------------------- /Solution/LC92_Ans.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC92_Ans.gif -------------------------------------------------------------------------------- /Solution/LC947_Ans1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC947_Ans1.png -------------------------------------------------------------------------------- /Solution/LC947_Ans2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC947_Ans2.png -------------------------------------------------------------------------------- /Solution/LC947_Ans3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC947_Ans3.png -------------------------------------------------------------------------------- /Solution/LC947_Ans4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC947_Ans4.png -------------------------------------------------------------------------------- /Solution/LC947_Ans5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC947_Ans5.png -------------------------------------------------------------------------------- /Solution/LC96_Ans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC96_Ans.jpg -------------------------------------------------------------------------------- /Solution/LC995.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/LC995.jpg -------------------------------------------------------------------------------- /Solution/动态规划-问题思考方向.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/动态规划-问题思考方向.png -------------------------------------------------------------------------------- /Solution/递归的调用过程.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeSR/LeetCode/6e736dac88a85811eb739a911227fd75db2e703e/Solution/递归的调用过程.jpg -------------------------------------------------------------------------------- /Subdocument/Interesting Stuff.md: -------------------------------------------------------------------------------- 1 | 2 | In this file, I would like to share some interesting things about computer science. 3 | 4 | ### 什么是核心代码模式?什么是ACM模式? 5 | 6 | 核心代码模式指的是像力扣那样,只关注算法逻辑的模式;ACM模式是需要从头文件开始,写到主函数结束的模式。显然ACM模式更加全面。 7 | 8 | ### 什么是GNU? 9 | 10 | ### 什么是万能头文件?为什么在OJ中,C++编译器下没办法AC,但是G++可以? 11 | 12 | 13 | 14 | ### 什么是析构函数? 15 | 16 | 类的析构函数(Destructor)是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。 17 | 18 | 析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。 19 | 20 | 关于析构函数和构造函数的使用,详见[字典树]()中的内容。 21 | 22 | ### 为什么++i比i++的效率高? 23 | 24 | ### 什么是AC, WA, TLE, CE, OJ ? 25 | 26 | OJ = online judge,是练习ACM-ICPC题目的地方,常见的有[POJ](), [HDOJ](), [ZOJ]() ... ; 其他简写都是OJ上的术语:AC = accepted,WA = wrong answer;TLE = time limit exceeded; CE = 27 | compilation error。 28 | -------------------------------------------------------------------------------- /剑指 Offer 10- II_青蛙跳台阶问题_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int numWays(int n) { 4 | if(n<=1) return 1; 5 | int dp[n+1]; 6 | dp[0] = 1; 7 | dp[1] = 1; 8 | for(int i=2;i<=n;++i){ 9 | dp[i] = (dp[i-1]+dp[i-2])%1000000007; 10 | } 11 | return dp[n]; 12 | } 13 | }; 14 | 15 | // 这种问题不应该用递归,递归速度太慢。要用动态规划,其实DP和递归思想差不多,但还是需要改进一下。 -------------------------------------------------------------------------------- /剑指 Offer 10- II_青蛙跳台阶问题_DP.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Thu Nov 5 13:47:41 2020 4 | 5 | @author: Three 6 | """ 7 | class Solution: 8 | def numWays(self, n: int) -> int: 9 | if n<2: return 1 10 | dp = [0]*(n+1) 11 | dp[0] = 1 12 | dp[1] = 1 13 | for i in range(2,n+1): 14 | dp[i] = (dp[i-1]+dp[i-2])%1000000007 15 | 16 | return dp[n] 17 | 18 | # 这种问题不应该用递归,递归速度太慢。要用动态规划,其实DP和递归思想差不多,但还是需要改进一下。 -------------------------------------------------------------------------------- /剑指 Offer 10- II_青蛙跳台阶问题_Recursion_Break Time Limit.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Thu Nov 5 13:46:03 2020 4 | 5 | @author: Three 6 | """ 7 | 8 | class Solution: 9 | def numWays(self, n: int) -> int: 10 | if n<2: return 1 11 | return (self.numWays(n-1) + self.numWays(n-2))%1000000007 -------------------------------------------------------------------------------- /剑指 Offer 49_Ugly Number_DP.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def nthUglyNumber(self, n: int) -> int: 3 | nums = [1] 4 | i2 = 0 5 | i3 = 0 6 | i5 = 0 7 | for i in range(1,1690): 8 | ugly = min(nums[i2] * 2,nums[i3] * 3,nums[i5] * 5) 9 | nums.append(ugly) 10 | if(nums[i] == nums[i2] * 2): i2 += 1 11 | if(nums[i] == nums[i3] * 3): i3 += 1 12 | if(nums[i] == nums[i5] * 5): i5 += 1 13 | return nums[n-1] -------------------------------------------------------------------------------- /剑指 Offer 58 - II_左旋转字符串_脑筋急转弯.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string reverseLeftWords(string s, int n) { 4 | reverse(s.begin(),s.begin()+n); // reverse函数取一个半开区间,取左不取右。从begin开始,至s.begin()+n-1结束。所以下一行的reverse还是从s.begin()+n开始 5 | reverse(s.begin()+n,s.end()); 6 | reverse(s.begin(),s.end()); 7 | return s; 8 | } 9 | }; 10 | 11 | // reference https://mp.weixin.qq.com/s/PmcdiWSmmccHAONzU0ScgQ 12 | // 本题解法很巧妙,通过三次reverse,得到目的。聪明但不具代表性。 -------------------------------------------------------------------------------- /剑指Offer_03_数组中重复的数字_Hash Table.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findRepeatNumber(vector& nums) { // 利用哈希表统计次数,大于1,找一个出来即可。 4 | unordered_map map; 5 | for (int i = 0; i < nums.size(); i++) { 6 | map[nums[i]]++; 7 | } 8 | int result; 9 | for (int i = 0; i < nums.size(); i++) { 10 | if (map[nums[i]] > 1) { 11 | result = nums[i]; 12 | break; 13 | } 14 | } 15 | return result; 16 | } 17 | }; -------------------------------------------------------------------------------- /剑指Offer_04_二维数组中的查找_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool findNumberIn2DArray(vector>& matrix, int target) { // 找有没有一个数,并且矩阵本身是有序的,那么就将行或列选一个从高到低,另一个从低到高进行筛选即可。 4 | if (matrix.size() == 0 || matrix[0].size() == 0) return false; 5 | int cols = matrix[0].size(); 6 | int rows = matrix.size(); 7 | int row = 0, col = cols - 1; 8 | while (row < rows && col >=0) { 9 | if (matrix[row][col] == target) return true; 10 | else if (matrix[row][col] > target) col--; 11 | else row++; 12 | } 13 | return false; 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /剑指Offer_06_从尾到头打印链表_Linked List.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | vector reversePrint(ListNode* head) { 12 | vector result; 13 | while (head != nullptr) { 14 | result.push_back(head->val); 15 | head = head->next; 16 | } 17 | reverse(result.begin(),result.end()); 18 | return result; 19 | } 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /剑指Offer_09_用两个栈实现队列_Stack.py: -------------------------------------------------------------------------------- 1 | class CQueue: 2 | def __init__(self): # 两个栈 3 | self.A, self.B = [], [] 4 | 5 | def appendTail(self, value: int) -> None: # 一个栈用于加元素 6 | self.A.append(value) 7 | 8 | def deleteHead(self) -> int: # 另一个栈用于出元素 9 | if self.B: return self.B.pop() 10 | if not self.A: return -1 11 | while self.A: 12 | self.B.append(self.A.pop()) 13 | return self.B.pop() 14 | 15 | 16 | # Your CQueue object will be instantiated and called as such: 17 | # obj = CQueue() 18 | # obj.appendTail(value) 19 | # param_2 = obj.deleteHead() -------------------------------------------------------------------------------- /剑指Offer_10-I_斐波那契数列_DP.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def fib(self, n: int) -> int: 3 | a, b = 0, 1 4 | for _ in range(n): 5 | a, b = b, a + b 6 | return a % 1000000007 7 | 8 | # 运用斐波那契数列迭代公式,勿用递归!! 这样的思路与DP相仿 -------------------------------------------------------------------------------- /剑指Offer_11_旋转数组的最小数字_Binary Search.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int minArray(vector& numbers) { // 二分法 4 | int left = 0, right = numbers.size() - 1; 5 | while (left < right) { // 不取等号的二分法 6 | int mid = left + (right - left) / 2; 7 | if (numbers[mid] < numbers[right]) right = mid; 8 | else if (numbers[mid] > numbers[right]) left = mid + 1; 9 | else right--; // 这一步是为了去除重复出现的元素 10 | } 11 | return numbers[left]; // right也可以,这时候left == right 12 | } 13 | }; 14 | 15 | // reference https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/solution/mian-shi-ti-11-xuan-zhuan-shu-zu-de-zui-xiao-shu-3/ 16 | // 具体的分类讨论见链接,是比较复杂的。本题是非典型的二分搜索,这样做比较“胆大”,需要仔细分析不同情况。 17 | // 本题和LC154一样 -------------------------------------------------------------------------------- /剑指Offer_14 - I_剪绳子_Math.py: -------------------------------------------------------------------------------- 1 | class Solution: # 数学,求导 2 | def cuttingRope(self, n: int) -> int: # 根据链接中的数学推导,我们得知:针对这种题目,需要尽量分配3,即3的个数要尽量地多 3 | if n <= 3: return n - 1 # 根据题目要求,如果数值太少,就是输出这样的数值 4 | a, b = n // 3, n % 3 # 以3为基准 5 | if b == 0: return int(math.pow(3, a)) # 如果数值可以被3整除,那么就全部都是3进行相乘即可 6 | if b == 1: return int(math.pow(3, a - 1) * 4) # 如果会留一个数,那就是留一个1。这时候要把前面的3变成2,送一个1给1,变成2*2,大于1*3 7 | return int(math.pow(3, a) * 2) # 如果最后剩两个数,那么老老实实乘上2即可,不用再变动,不然更小 8 | 9 | # reference https://leetcode-cn.com/problems/jian-sheng-zi-lcof/solution/mian-shi-ti-14-i-jian-sheng-zi-tan-xin-si-xiang-by/ 10 | # 相关题解与证明见链接中的内容,非常详细 -------------------------------------------------------------------------------- /剑指Offer_15_Number of 1 Bits_Bit Operation.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int hammingWeight(uint32_t n) { 4 | if (n == 0) return 0; 5 | int count = 0; 6 | while (n != 0) { 7 | n &= n - 1; 8 | count++; 9 | } 10 | return count; 11 | } 12 | }; 13 | 14 | // 详见LC191 -------------------------------------------------------------------------------- /剑指Offer_17_打印从1到最大的n位数_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector printNumbers(int n) { 4 | int end = pow(10, n) - 1; 5 | vector result; 6 | for (int i = 1; i <= end; i++) { 7 | result.push_back(i); 8 | } 9 | return result; 10 | } 11 | }; -------------------------------------------------------------------------------- /剑指Offer_18_删除链表的节点_Linked List.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* deleteNode(ListNode* head, int val) { 12 | ListNode* dummyHead = new ListNode(0); // 删除节点需要制造一个新的头结点安排在现有的头结点之前,这是常用手段 13 | dummyHead->next = head; 14 | ListNode* flag = dummyHead; 15 | while (dummyHead->next != nullptr) { 16 | if (dummyHead->next->val == val) { 17 | dummyHead->next = dummyHead->next->next; 18 | break; 19 | } 20 | dummyHead = dummyHead->next; 21 | } 22 | return flag->next; 23 | } 24 | }; -------------------------------------------------------------------------------- /剑指Offer_21_调整数组顺序使奇数位于偶数前面_Double Pointer.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector exchange(vector& nums) { // 双指针法 4 | int i = 0; // 头指针 5 | int j = nums.size() - 1; // 尾指针 6 | while (i < j) { 7 | while ((i < j) && (nums[i] % 2 == 1)) i++; // 保证前面的都是奇数 8 | while ((i < j) && (nums[j] % 2 == 0)) j--; // 保证后面的都是偶数 9 | swap(nums[i], nums[j]); // 如果能到这一步,说明前面有偶数,后面有奇数,那么这两个数需要调换位置。 10 | } 11 | return nums; 12 | } 13 | }; 14 | 15 | // reference https://leetcode-cn.com/problems/diao-zheng-shu-zu-shun-xu-shi-qi-shu-wei-yu-ou-shu-qian-mian-lcof/solution/mian-shi-ti-21-diao-zheng-shu-zu-shun-xu-shi-qi-4/ -------------------------------------------------------------------------------- /剑指Offer_22_链表中倒数第k个节点_Double Pointer.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* getKthFromEnd(ListNode* head, int k) { // 双指针法 12 | ListNode* p = head; // 慢指针 13 | ListNode* q = head; // 快指针 14 | while (k != 0) { // 快慢指针之间留k的距离 15 | q = q->next; 16 | k--; 17 | } 18 | while (q != nullptr) { // 当快指针指到末尾的时候,慢指针就指到倒数第K个元素 19 | q = q->next; 20 | p = p->next; 21 | } 22 | return p; 23 | } 24 | }; -------------------------------------------------------------------------------- /剑指Offer_24_反转链表_Stack.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.next = None 6 | 7 | class Solution: 8 | def reverseList(self, head: ListNode) -> ListNode: 9 | stack = [] 10 | while head is not None: 11 | stack.append(head.val) 12 | head = head.next 13 | if not stack: 14 | return None 15 | res = init = ListNode(stack.pop()) 16 | while stack: 17 | res.next = ListNode(stack.pop()) 18 | res = res.next 19 | return init 20 | # 同LC206 -------------------------------------------------------------------------------- /剑指Offer_28_对称的二叉树_Recursion.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | bool check(TreeNode* p, TreeNode* q) { // 递归 13 | if (!p && !q) return true; 14 | if (!p || !q) return false; 15 | return p->val == q->val && check(p->left, q->right) && check(p->right, q->left); 16 | } 17 | bool isSymmetric(TreeNode* root) { 18 | return check(root, root); 19 | } 20 | }; 21 | 22 | // 同LC101 -------------------------------------------------------------------------------- /剑指Offer_29_顺时针打印矩阵_Naive Algorithm.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def spiralOrder(self, matrix:[[int]]) -> [int]: # 本题和LC54螺旋矩阵一样,仔细按照题目要求打印出矩阵即可。 3 | if not matrix: return [] 4 | l, r, t, b, res = 0, len(matrix[0]) - 1, 0, len(matrix) - 1, [] 5 | while True: 6 | for i in range(l, r + 1): res.append(matrix[t][i]) # left to right 7 | t += 1 8 | if t > b: break 9 | for i in range(t, b + 1): res.append(matrix[i][r]) # top to bottom 10 | r -= 1 11 | if l > r: break 12 | for i in range(r, l - 1, -1): res.append(matrix[b][i]) # right to left 13 | b -= 1 14 | if t > b: break 15 | for i in range(b, t - 1, -1): res.append(matrix[i][l]) # bottom to top 16 | l += 1 17 | if l > r: break 18 | return res 19 | # reference https://leetcode-cn.com/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/solution/mian-shi-ti-29-shun-shi-zhen-da-yin-ju-zhen-she-di/ -------------------------------------------------------------------------------- /剑指Offer_32 - I_从上到下打印二叉树_BFS.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | vector levelOrder(TreeNode* root) { 13 | queue q; 14 | vector result; 15 | if(root != NULL){ 16 | q.push(root); 17 | } 18 | while(!q.empty()){ 19 | int size = q.size(); 20 | for(int i = 0; i < size; ++i){ 21 | TreeNode* node = q.front(); 22 | q.pop(); 23 | if(node->left) q.push(node->left); 24 | if(node->right) q.push(node->right); 25 | result.push_back(node->val); 26 | } 27 | } 28 | return result; 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /剑指Offer_39_数组中出现次数超过一半的数字_Boyer–Moore Majority Vote Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int majorityElement(vector& nums) { 4 | int moleVote = 0, res = 0; 5 | for (int num: nums) { 6 | if (moleVote == 0) { 7 | res = num; 8 | } 9 | moleVote += num == res ? 1 : -1; 10 | } 11 | return res; 12 | } 13 | }; 14 | 15 | // 本题同LC169,是摩尔投票法 -------------------------------------------------------------------------------- /剑指Offer_40_最小的k个数_Sort.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector getLeastNumbers(vector& arr, int k) { 4 | vector vec(k, 0); 5 | sort(arr.begin(), arr.end()); 6 | for (int i = 0; i < k; ++i) { 7 | vec[i] = arr[i]; 8 | } 9 | return vec; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /剑指Offer_42_Maximum Subarray_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxSubArray(vector& nums) { 4 | if (nums.size() == 0) return 0; 5 | vector dp(nums.size(),0); 6 | int result = nums[0]; 7 | dp[0] = nums[0]; 8 | for (int i = 1; i < nums.size(); ++i){ 9 | dp[i] = max(dp[i - 1] + nums[i], nums[i]); 10 | if (dp[i] > result){ 11 | result = dp[i]; 12 | } 13 | } 14 | return result; 15 | } 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /剑指Offer_45_把数组排成最小的数_String Manipulation.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string minNumber(vector& nums) { // 本题和力扣179基本相同,也是字符串处理,自定义排序 4 | if(nums.empty()) return ""; 5 | if(nums.size() == 1) return to_string(nums[0]); 6 | vector result; 7 | for(int i : nums) result.push_back(to_string(i)); 8 | sort(result.begin(), result.end(), comparison); 9 | string ans = ""; 10 | for (int i = 0; i < result.size(); i++) ans += result[i]; 11 | //if(ans[0] == '0') return "0"; // 0的时候应该输出0而不是000...,需要特殊判断!! (不同于力扣179,此处不用处理前导0) 12 | return ans; 13 | } 14 | static bool comparison(string& a, string& b) // 比较字符串拼接之后的结果 15 | { 16 | return a + b < b + a; 17 | } 18 | }; 19 | 20 | // reference https://leetcode-cn.com/problems/largest-number/solution/ju-yi-fan-er-bu-guang-you-zui-da-shu-hua-uykb/ -------------------------------------------------------------------------------- /剑指Offer_50_第一个只出现一次的字符_Hash Table.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | char firstUniqChar(string s) { 4 | unordered_map hashmap; 5 | for (char a : s) { 6 | hashmap[a]++; 7 | } 8 | char result = ' '; // 注意,C++中,char的输出,要用' '单引号! 9 | for (char b : s) { 10 | if (hashmap[b] == 1) { 11 | result = b; 12 | break; 13 | } 14 | } 15 | return result; 16 | } 17 | }; -------------------------------------------------------------------------------- /剑指Offer_53 - I_在排序数组中查找数字 I_Hash Table.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int search(vector& nums, int target) { // 哈希表统计元素个数 4 | if (nums.size() == 0) return 0; // 特判 5 | unordered_map hashmap; 6 | for (int i = 0; i <= nums.size() - 1; i++) { 7 | hashmap[nums[i]]++; 8 | } 9 | return hashmap[target]; 10 | } 11 | }; 12 | 13 | // 本题和LC34相同,但返回值不同。返回值的不同使得这道题更加简单,可以使用哈希表完成。不然要使用二分搜索。 14 | -------------------------------------------------------------------------------- /剑指Offer_53-II_0~n-1中缺失的数字_Naive Algorithm.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int missingNumber(vector& nums) { 4 | int res; 5 | for (int i = 0; i < nums.size(); i++) { 6 | if (nums[i] != i) { 7 | res = i; 8 | break; 9 | } 10 | } 11 | return res; 12 | } 13 | }; -------------------------------------------------------------------------------- /剑指Offer_54_二叉搜索树的第k大节点_Recursion.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | void inorderTraversal(TreeNode* root, vector& result) { // 中序遍历 13 | if (!root) return; 14 | inorderTraversal(root->left, result); 15 | result.push_back(root->val); 16 | inorderTraversal(root->right, result); 17 | } 18 | int kthLargest(TreeNode* root, int k) { 19 | vector result; 20 | inorderTraversal(root, result); 21 | return result[result.size() - k]; // 根据BST的性质,先中序遍历再找到对应位置即可 22 | } 23 | }; 24 | 25 | // 注意:对于BST而言,中序遍历之后就是从小到大的排序。 26 | 27 | -------------------------------------------------------------------------------- /剑指Offer_55-II_平衡二叉树_Recursion.py: -------------------------------------------------------------------------------- 1 | # Definition for a binary tree node. 2 | # class TreeNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.left = None 6 | # self.right = None 7 | 8 | class Solution: 9 | def isBalanced(self, root: TreeNode) -> bool: # 后序遍历 10 | def recur(root): 11 | if not root: return 0 # 特判 12 | left = recur(root.left) # 左 13 | if left == -1: return -1 14 | right = recur(root.right) # 右 15 | if right == -1: return -1 16 | return max(left, right) + 1 if abs(left - right) <= 1 else -1 # 中 17 | 18 | return recur(root) != -1 -------------------------------------------------------------------------------- /剑指Offer_56 - I_数组中数字出现的次数_Bit Operation.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector singleNumbers(vector& nums) { // 位运算 4 | int x = 0, y = 0, n = 0, m = 1; 5 | for (int num : nums) // 遍历异或。我们需要的是结果的第一个不为零的数字在第几位。这代表着两个不同数字在哪一位开始是不同的 6 | // 注:位数是从右往左数的 7 | n ^= num; 8 | while ((n & m) == 0) // 循环左移,计算 m。这个数值就代表了第一个不为0的位数对应的数值。 9 | m <<= 1; 10 | for (int num : nums) { // 遍历,对 nums 进行分组。分成m位置为0和为1的两组数。 11 | if(num & m) x ^= num; // 当 num & m != 0 12 | else y ^= num; // 当 num & m == 0 13 | } 14 | return vector {x, y}; // 返回出现一次的数字。这是因为分组之后,各自组里面相同数字成对出现。对于两个落单的 15 | // 不同数字,一定会分在不同组里面。这时候各自组内异或,即可得到最终结果。 16 | } 17 | }; 18 | 19 | // reference 《剑指offer》 -------------------------------------------------------------------------------- /剑指Offer_57_和为s的两个数字_Double Pointer.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def twoSum(self, nums: List[int], target: int) -> List[int]: # 双指针法 3 | i = 0 4 | j = len(nums) - 1 5 | while (i < j): # 既然数组是递增的,我们就可以利用这个性质 6 | if (nums[i] + nums[j] > target): j = j - 1 7 | elif (nums[i] + nums[j] < target): i = i + 1 8 | else: return [nums[i], nums[j]] 9 | return [] -------------------------------------------------------------------------------- /剑指Offer_63_股票的最大利润_DP.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProfit(vector& prices) { // 本题和LC121买卖股票的最佳时机一样 4 | if (prices.size() == 0) return 0; 5 | vector> dp(prices.size(), vector(2, 0)); 6 | dp[0][0] = -prices[0]; // 买入 7 | for (int i = 1; i < prices.size(); i++) { // 注意i从何处开始!从1而不是0!! 8 | dp[i][0] = max(dp[i - 1][0], -prices[i]); 9 | dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]); 10 | } 11 | return dp[prices.size() - 1][1]; 12 | } 13 | }; -------------------------------------------------------------------------------- /剑指Offer_64_求1+2+…+n_Math.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int sumNums(int n) { 4 | int result = (1 + n) * n / 2; 5 | return result; 6 | } 7 | }; -------------------------------------------------------------------------------- /剑指Offer_64_求1+2+…+n_Math.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def sumNums(self, n): 3 | """ 4 | :type n: int 5 | :rtype: int 6 | """ 7 | return sum(range(1, n + 1)) -------------------------------------------------------------------------------- /剑指Offer_65_不用加减乘除做加法_Bit Operation.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int add(int a, int b) { // 本题不能用+-*/,显然就是要用位运算了。其实对于底层的数字逻辑电路,它们的加法器也是这么实现的,所以本题很有意义。 4 | int sum; // 和值 5 | int carry; // 进位值,注意:一般进位均习惯用carry表示 6 | do{ // 用do while 方便判断 7 | sum = a ^ b; // 二进制求和其实是异或的过程,比如01 + 11 = 10(不算进位项) 8 | carry = (unsigned int)(a & b) << 1; // unsigned int是防止负数,这样类型转换之后,剩下的交给计算机自己处理。至于负数怎么表达,查阅相关的数电资料即可。 9 | // 我们就来说说正数,还是上面的例子:01 & 11 = 01(按位与),之后左移一位(<<移位运算符),变成10,这是进的位。 10 | a = sum; // 用a承接sum 11 | b = carry; // b承接carry,之后再a与b求和:010 + 010 = 000(不算进位),之后进位100,之后再相加(异或)...... 总之,最后不再进位,就是最终结果。 12 | }while(carry != 0); 13 | return sum; // 不再进位后,得到最终sum。 14 | } 15 | }; 16 | 17 | // reference 《剑指offer》 -------------------------------------------------------------------------------- /剑指Offer_66_构建乘积数组_Math.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def constructArr(self, a: List[int]) -> List[int]: 3 | if (len(a) == 0): return [] # 特判 4 | res = [1] # 初始的1是很关键的,在后续理解索引值上很重要 5 | p = q = 1 6 | for i in range(len(a) - 1): # 下三角矩阵,注意,这里取不到len(nums) - 1,只能到len(nums) - 2 7 | p *= a[i] 8 | res.append(p) # 存入下三角数值的乘积 9 | for j in range(len(a) - 1, 0, -1): # 上三角矩阵,取不到0 10 | q *= a[j] 11 | res[j - 1] *= q # 合于一处就是乘积结果 12 | return res 13 | 14 | # 本题和LC238 Product of Array Except Self一样 15 | # LC238 https://github.com/ThreeSR/LeetCode/blob/main/LC238_Product%20of%20Array%20Except%20Self_Math.py -------------------------------------------------------------------------------- /剑指offer_25_Merge Two Sorted Lists_Double Pointer.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | # class ListNode: 3 | # def __init__(self, x): 4 | # self.val = x 5 | # self.next = None 6 | 7 | class Solution: 8 | def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode: # 双指针法,本题和力扣21相同 9 | dummyHaed = cur = ListNode(0) 10 | while l1 and l2: 11 | if l1.val < l2.val: 12 | cur.next, l1 = l1, l1.next 13 | else: 14 | cur.next, l2 = l2, l2.next 15 | cur = cur.next 16 | cur.next = l1 if l1 else l2 17 | return dummyHaed.next 18 | -------------------------------------------------------------------------------- /剑指offer_68 - II_Lowest Common Ancestor of a Binary Tree_Recursion.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { 13 | if (root == p || root == q || root == nullptr) return root; 14 | TreeNode* left = lowestCommonAncestor(root->left, p, q); 15 | TreeNode* right = lowestCommonAncestor(root->right, p ,q); 16 | if (left != nullptr && right != nullptr) return root; 17 | if (left == nullptr) return right; 18 | return left; 19 | } 20 | }; 21 | 22 | // 分析见LC236 -------------------------------------------------------------------------------- /剑指offer_68 - I_Lowest Common Ancestor of a Binary Search Tree_Iteration.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { // 本题采用迭代法,正是因为BST的属性,才可以用迭代,不然就要回溯,用递归,像LC236那样。 11 | public: 12 | TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { 13 | if (root == nullptr) return root; // 特判 14 | while (root){ // 当root非空时 15 | if (root->val > p->val && root->val > q->val) root = root->left; // val大了向左 16 | else if (root->val < p->val && root->val < q->val) root = root->right; // val小了向右 17 | else return root; // 找到,返回root 18 | } 19 | return NULL; // 没有,则null 20 | } 21 | }; 22 | 23 | // 详见LC235 -------------------------------------------------------------------------------- /程序员面试金典17.04_Missing Number_Bit Operation.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int missingNumber(vector& nums) { // 异或运算 这里对于异或的理解要从配对入手 能配对代表为0.并且任何数和0异或都是本身,这一点也很关键。 4 | int result = nums.size(); 5 | for (int i = 0; i < nums.size(); i++) { // 这里的意思是,将所有nums里面的index和value异或。此外,特别要注意的是,result一开始赋值要为n 6 | // 不然会出问题。 经过这样的计算,相同的数值都被配对,变成0. 0和那个孤立的数异或,又是得到它本身。这样一来,缺失的数可以从index或result 7 | // 等于n的初值得到。 8 | result ^= nums[i]; 9 | result ^= i; 10 | } 11 | return result; 12 | } 13 | }; 14 | 15 | // 对位运算可以从不同方面理解,能够从多方面理解,就可以更好地利用位运算得到精妙的答案。本题和LC268一样 -------------------------------------------------------------------------------- /程序员面试金典17.21_直方图的水量_Double Pointer.c: -------------------------------------------------------------------------------- 1 | int trap(int* height, int heightSize) { // 面试题17.21,同接雨水 2 | int volume = 0; 3 | int Sum = 0; 4 | int left = 0; 5 | int right = heightSize - 1; 6 | int high = 0; 7 | while (left <= right) { 8 | high++; 9 | while ((left <= right) && (height[left] < high)) { 10 | Sum += height[left]; 11 | left++; 12 | } 13 | while ((left <= right) && (height[right] < high)) { 14 | Sum += height[right]; 15 | right--; 16 | } 17 | volume += right - left + 1; 18 | } 19 | return volume - Sum; 20 | } 21 | 22 | // reference https://leetcode-cn.com/problems/volume-of-histogram-lcci/solution/shuang-zhi-zhen-an-xing-qiu-jie-xiang-xi-d162/ -------------------------------------------------------------------------------- /程序员面试金典17.21_直方图的水量_Double Pointer.cpp: -------------------------------------------------------------------------------- 1 | class Solution { // 本题同接雨水 2 | public: 3 | int trap(vector& height) { 4 | int Sum = accumulate(height.begin(), height.end(), 0); // 得到柱子的体积 5 | int volume = 0; // 总体积和高度初始化 6 | int high = 1; 7 | int size = height.size(); 8 | int left = 0; // 双指针初始化 9 | int right = size - 1; 10 | while (left <= right) { 11 | while (left <= right && height[left] < high) { 12 | left++; 13 | } 14 | while (left <= right && height[right] < high) { 15 | right--; 16 | } 17 | volume += right - left + 1; // 每一层的容量都加起来 18 | high++; // 高度加一 19 | } 20 | return volume - Sum; // 总体积减去柱子体积,即雨水总量 21 | } 22 | }; 23 | 24 | 25 | // reference https://leetcode-cn.com/problems/volume-of-histogram-lcci/solution/shuang-zhi-zhen-an-xing-qiu-jie-xiang-xi-d162/ 26 | -------------------------------------------------------------------------------- /程序员面试金典17.21_直方图的水量_Double Pointer.java: -------------------------------------------------------------------------------- 1 | public class Solution { // 本题同接雨水 2 | public int trap(int[] height) 3 | { 4 | int sum = 0; 5 | for(int i = 0;i int: 3 | Sum = sum(height) # 得到柱子的体积 4 | size = len(height) 5 | left, right = 0, size - 1 # 双指针初始化 6 | volume, high = 0, 1 # 总体积和高度初始化 7 | while (left <= right): 8 | while (left <= right and height[left] < high): 9 | left += 1 10 | while (left <= right and height[right] < high): 11 | right -= 1 12 | volume += right - left + 1 # 每一层的容量都加起来 13 | high += 1 # 高度加一 14 | return volume - Sum # 总体积减去柱子体积,即雨水总量 15 | 16 | 17 | // reference https://leetcode-cn.com/problems/volume-of-histogram-lcci/solution/shuang-zhi-zhen-an-xing-qiu-jie-xiang-xi-d162/ 18 | --------------------------------------------------------------------------------