├── .gitignore ├── .vscode ├── last.sql └── settings.json ├── amazon ├── kNearestPostOffices.py ├── moviesOnFlight.py ├── reorderElements.py ├── retrieveMostFrequentlyUsedWords.py └── treasureIsland.py ├── bit-manipulation ├── 1. A + B Problem.py ├── 142. O(1) Check Power of 2.py ├── 365. Count 1 in Binary.py └── 408. Add Binary.py ├── ladder_advanced ├── 1_followup_in_code_interview │ ├── 382_Triangle_Count.py │ ├── 384_Longest_Substring_Without_Repeating_Characters.py │ ├── 386_Longest_Substring_with_At_Most_K_Distinct_Characters.py │ ├── 401_Kth_Smallest_Number_in_Sorted_Matrix.py │ ├── 406_Minimum_Size_Subarray_Sum.py │ ├── 433_Number_of_Islands.py │ ├── 461_Kth_Smallest_Numbers_in_Unsorted_Array.py │ ├── 543_Kth_Largest_in_N_Arrays.py │ ├── 5_Kth_Largest_Element.py │ └── 609_Two_Sum_Less_than_or_equal_to_target.py ├── 2_data_structrure_I │ ├── 123. Word Search.py │ ├── 132. Word Search II.py │ ├── 178_Graph_Valid_Tree.py │ ├── 207. Interval Sum II.py │ ├── 249. Count of Smaller Number before itself.py │ ├── 431. Connected Component in Undirected Graph.py │ ├── 432. Find the Weak Connected Component in the Directed Graph.py │ ├── 432_Find_the_Weak_Connected_Component_in_the_Directed_Graph.py │ ├── 433_Number_of_Islands.py │ ├── 434. Number of Islands II.py │ ├── 442. Implement Trie (Prefix Tree).py │ ├── 442_Implement_Trie.py │ ├── 465. Kth Smallest Sum In Two Sorted Arrays.py │ ├── 477. Surrounded Regions.py │ ├── 589_Connecting_Graph.py │ ├── 590_Connecting_GraphII.py │ ├── 591_Connecting_Graph_III.py │ ├── 634. Word Squares.py │ └── 635. Boggle Game.py ├── 3_data_structure_II │ ├── 12. Min Stack.py │ ├── 122. Largest Rectangle in Histogram.py │ ├── 126. Max Tree.py │ ├── 130. Heapify.py │ ├── 131. The Skyline Problem.py │ ├── 360. Sliding Window Median.py │ ├── 362. Sliding Window Maximum.py │ ├── 363. Trapping Rain Water.py │ ├── 364. Trapping Rain Water II.py │ ├── 367. Expression Tree Build.py │ ├── 40. Implement Queue by Two Stacks.py │ ├── 475. Binary Tree Maximum Path Sum II.py │ ├── 510. Maximal Rectangle.py │ ├── 575. Decode String.py │ ├── 623. K Edit Distance.py │ └── 81. Find Median from Data Stream.py ├── 4_binary_search_sweepline │ ├── 131. The Skyline Problem.py │ ├── 141. Sqrt(x).py │ ├── 183. Wood Cut.py │ ├── 390. Find Peak Element II.py │ ├── 391. Number of Airplanes in the Sky.py │ ├── 414. Divide Two Integers.py │ ├── 437. Copy Books.py │ ├── 586. Sqrt(x) II.py │ ├── 600. Smallest Rectangle Enclosing Black Pixels.py │ ├── 617. Maximum Average Subarray II.py │ ├── 633. Find the Duplicate Number.py │ ├── 74. First Bad Version.py │ └── 75. Find Peak Element.py ├── 5_dynamic_problem_I │ ├── 191. Maximum Product Subarray.py │ ├── 200. Longest Palindromic Substring.py │ ├── 392. House Robber.py │ ├── 393. Best Time to Buy and Sell Stock IV.py │ ├── 394_Coins_in_a_Line.py │ ├── 395_Coins_in_a_Line II.py │ ├── 396. Coins in a Line III.py │ ├── 397. Longest Continuous Increasing Subsequence.py │ ├── 398. Longest Increasing Continuous subsequence II.py │ ├── 41. Maximum Subarray.py │ ├── 435. Post Office Problem.py │ ├── 436. Maximal Square.py │ ├── 437. Copy Books.py │ ├── 581. Longest Repeating Subsequence.py │ ├── 631. Maximal Square II.py │ └── 76. Longest Increasing Subsequence.py ├── 6_dynamic_problem_II │ ├── 118. Distinct Subsequences.py │ ├── 119. Edit Distance.py │ ├── 125. Backpack II.py │ ├── 168. Burst Balloons.py │ ├── 29. Interleaving String.py │ ├── 393. Best Time to Buy and Sell Stock IV.py │ ├── 394. Coins in a Line.py │ ├── 395. Coins in a Line II.py │ ├── 396. Coins in a Line III.py │ ├── 430. Scramble String.py │ ├── 440. Backpack III.py │ ├── 476. Stone Game.py │ ├── 562. Backpack IV.py │ ├── 563. Backpack V.py │ ├── 564. Combination Sum IV.py │ ├── 593. Stone Game II.py │ ├── 623. K Edit Distance.py │ ├── 77. Longest Common Subsequence.py │ ├── 89. k Sum.py │ ├── 91. Minimum Adjustment Cost.py │ └── 92. Backpack.py └── 7_followup │ ├── 138. Subarray Sum.py │ ├── 139. Subarray Sum Closest.py │ ├── 22. Flatten List.py │ ├── 390. Find Peak Element II.py │ ├── 400. Maximum Gap.py │ ├── 401. Kth Smallest Number in Sorted Matrix.py │ ├── 402. Continuous Subarray Sum.py │ ├── 403. Continuous Subarray Sum II.py │ ├── 404. Subarray Sum II.py │ ├── 405. Submatrix Sum.py │ ├── 406. Minimum Size Subarray Sum.py │ ├── 453. Flatten Binary Tree to Linked List.py │ ├── 528. Flatten Nested List Iterator.py │ ├── 540. Zigzag Iterator.py │ ├── 541. Zigzag Iterator II.py │ ├── 551. Nested List Weight Sum.py │ ├── 553. Bomb Enemy.py │ ├── 558. Sliding Window Matrix Maximum.py │ ├── 573. Build Post Office II.py │ ├── 601. Flatten 2D Vector.py │ └── 75. Find Peak Element.py ├── ladder_basic ├── 1_Hack_The_Algorithm_Interview │ ├── 13_Implement_strStr().py │ ├── 200_LongestPalindromic_Substring.py │ ├── 415_ValidPalindrome.py │ ├── 594_strStrII.py │ ├── 627. Longest Palindrome.py │ ├── 667. Longest Palindromic Subsequence.py │ └── 841. String Replace.py ├── 2_Binary_Search&LogN_Algorithm │ ├── 14. First Position of Target.py │ ├── 140. Fast Power.py │ ├── 141. Sqrt(x).py │ ├── 159. Find Minimum in Rotated Sorted Array.py │ ├── 160. Find Minimum in Rotated Sorted Array II.py │ ├── 183. Wood Cut.py │ ├── 235. Prime Factorization.py │ ├── 254. Drop Eggs.py │ ├── 28. Search a 2D Matrix.py │ ├── 38. Search a 2D Matrix II.py │ ├── 414. Divide Two Integers.py │ ├── 428. Pow(x, n).py │ ├── 437. Copy Books.py │ ├── 447. Search in a Big Sorted Array.py │ ├── 457. Classical Binary Search.py │ ├── 458_last_position_of_target.py │ ├── 459. Closest Number in Sorted Array.py │ ├── 460. Find K Closest Elements.py │ ├── 462. Total Occurrence of Target.py │ ├── 585. Maximum Number in Mountain Sequence.py │ ├── 586. Sqrt(x) II.py │ ├── 600. Smallest Rectangle Enclosing Black Pixels.py │ ├── 61. Search for a Range.py │ ├── 617. Maximum Average Subarray II.py │ ├── 62. Search in Rotated Sorted Array.py │ ├── 63. Search in Rotated Sorted Array II.py │ ├── 74. First Bad Version.py │ └── 75. Find Peak Element.py ├── 3_Two_Pointers_Algorithm │ ├── 102. Linked List Cycle.py │ ├── 103. Linked List Cycle II.py │ ├── 143. Sort Colors II.py │ ├── 148. Sort Colors.py │ ├── 228. Middle of Linked List.py │ ├── 31. Partition Array.py │ ├── 380. Intersection of Two Linked Lists.py │ ├── 382. Triangle Count.py │ ├── 443. Two Sum - Greater than target.py │ ├── 461. Kth Smallest Numbers in Unsorted Array.py │ ├── 464. Sort Integers II.py │ ├── 5. Kth Largest Element.py │ ├── 521. Remove Duplicate Numbers in Array.py │ ├── 533. Two Sum - Closest to target.py │ ├── 539. Move Zeroes.py │ ├── 56. Two Sum.py │ ├── 57. 3Sum.py │ ├── 58. 4Sum.py │ ├── 587. Two Sum - Unique pairs.py │ ├── 59. 3Sum Closest.py │ ├── 604. Window Sum.py │ ├── 607. Two Sum III - Data structure design.py │ ├── 608. Two Sum II - Input array is sorted.py │ ├── 609. Two Sum - Less than or equal to target.py │ ├── 610. Two Sum - Difference equals to target.py │ ├── 625. Partition Array II.py │ └── 894. Pancake Sorting.py ├── 5_BinaryTree_TreeBasedDFS │ └── 94. Binary Tree Maximum Path Sum.py └── 8_datastructure_stack_queue_hash_heap │ ├── 104. Merge K Sorted Lists.py │ ├── 124. Longest Consecutive Sequence.py │ ├── 128. Hash Function.py │ ├── 129. Rehashing.py │ ├── 130. Heapify.py │ ├── 134. LRU Cache.py │ ├── 209. First Unique Character in a String.py │ ├── 224. Implement Three Stacks by Single Array.py │ ├── 24. LFU Cache.py │ ├── 4. Ugly Number II.py │ ├── 40. Implement Queue by Two Stacks.py │ ├── 471. Top K Frequent Words.py │ ├── 486. Merge K Sorted Arrays.py │ ├── 494. Implement Stack by Two Queues.py │ ├── 495. Implement Stack.py │ ├── 526. Load Balancer.py │ ├── 528. Flatten Nested List Iterator.py │ ├── 540. Zigzag Iterator.py │ ├── 541. Zigzag Iterator II.py │ ├── 544. Top k Largest Numbers.py │ ├── 545. Top k Largest Numbers II.py │ ├── 551. Nested List Weight Sum.py │ ├── 575. Decode String.py │ ├── 601. Flatten 2D Vector.py │ ├── 606. Kth Largest Element II.py │ ├── 612. K Closest Points.py │ ├── 613. High Five.py │ ├── 642. Moving Average from Data Stream.py │ ├── 657. Insert Delete GetRandom O(1).py │ └── 685. First Unique Number In Stream.py ├── lecture_advanced ├── Lecture1.HotFollowupQuestions │ ├── 32. Minimum Window Substring.py │ ├── 384. Longest Substring Without Repeating Characters.py │ ├── 386. Longest Substring with At Most K Distinct Characters.py │ ├── 401. Kth Smallest Number in Sorted Matrix.py │ ├── 406. Minimum Size Subarray Sum.py │ ├── 465. Kth Smallest Sum In Two Sorted Arrays.py │ └── 543. Kth Largest in N Arrays.py ├── Lecture2.DataStructure1 │ ├── 132. Word Search II.py │ ├── 433. Number of Islands.py │ ├── 434. Number of Islands II.py │ ├── 442. Implement Trie (Prefix Tree).py │ ├── 477. Surrounded Regions.py │ ├── 589. Connecting Graph.py │ ├── 590. Connecting Graph II.py │ └── 591. Connecting Graph III.py └── Lecture3.DataStructure2 │ ├── 363. Trapping Rain Water.py │ ├── 364. Trapping Rain Water II.py │ └── 81. Find Median from Data Stream.py ├── lecture_basic ├── Lecture2.Binary_Search │ ├── 14. First Position of Target.py │ ├── 141. Sqrt(x).py │ ├── 159. Find Minimum in Rotated Sorted Array.py │ ├── 183. Wood Cut.py │ ├── 28. Search a 2D Matrix.py │ ├── 39. Recover Rotated Sorted Array.py │ ├── 447. Search in a Big Sorted Array.py │ ├── 457. Classical Binary Search.py │ ├── 458. Last Position of Target.py │ ├── 60. Search Insert Position.py │ ├── 62. Search in Rotated Sorted Array.py │ └── 75. Find Peak Element.py ├── Lecture3.Binary_Tree__Divide_Conquer │ ├── 11. Search Range in Binary Search Tree.py │ ├── 448. Inorder Successor in BST.py │ ├── 475. Binary Tree Maximum Path Sum II.py │ ├── 66. Binary Tree Preorder Traversal.py │ ├── 67. Binary Tree Inorder Traversal.py │ ├── 68. Binary Tree Postorder Traversal.py │ ├── 69. Binary Tree Level Order Traversal.py │ ├── 70. Binary Tree Level Order Traversal II.py │ ├── 71. Binary Tree Zigzag Level Order Traversal.py │ ├── 85. Insert Node in a Binary Search Tree.py │ ├── 86. Binary Search Tree Iterator.py │ ├── 87. Remove Node in Binary Search Tree.py │ ├── 88. Lowest Common Ancestor of a Binary Tree.py │ ├── 93. Balanced Binary Tree.py │ ├── 95. Validate Binary Search Tree.py │ └── 97. Maximum Depth of Binary Tree.py ├── Lecture4.Dynamic_Programming │ ├── 109. Triangle.py │ ├── 110. Minimum Path Sum.py │ ├── 111. Climbing Stairs.py │ ├── 114. Unique Paths.py │ ├── 116. Jump Game.py │ ├── 117. Jump Game II.py │ ├── 124. Longest Consecutive Sequence.py │ ├── 136. Palindrome Partitioning.py │ └── 76. Longest Increasing Subsequence.py ├── Lecture5.0.BFS │ └── readme.txt ├── Lecture5.1.DFS_Binary_Tree_Based │ ├── 175. Invert Binary Tree.py │ ├── 596. Minimum Subtree.py │ ├── 597. Subtree with Maximum Average.py │ ├── 902. Kth Smallest Element in a BST.py │ └── 95. Validate Binary Search Tree.py ├── Lecture5.2.DFS_Combination_Based │ ├── 135. Combination Sum.py │ ├── 136. Palindrome Partitioning.py │ └── 153. Combination Sum II.py ├── Lecture5.3.DFS_Permutation_Based │ └── readme.txt ├── Lecture6.Linked_List │ ├── 102. Linked List Cycle.py │ ├── 104. Merge K Sorted Lists.py │ ├── 105. Copy List with Random Pointer.py │ ├── 106. Convert Sorted List to Binary Search Tree.py │ ├── 113. Remove Duplicates from Sorted List II.py │ ├── 170. Rotate List.py │ ├── 35. Reverse Linked List.py │ ├── 36. Reverse Linked List II.py │ ├── 372. Delete Node in a Linked List.py │ ├── 96. Partition List.py │ ├── 98. Sort List.py │ └── 99. Reorder List.py ├── Lecture7.Array__Numbers │ ├── 138. Subarray Sum.py │ ├── 148. Sort Colors.py │ ├── 149. Best Time to Buy and Sell Stock.py │ ├── 150. Best Time to Buy and Sell Stock II.py │ ├── 31. Partition Array.py │ ├── 41. Maximum Subarray.py │ ├── 42. Maximum Subarray II.py │ ├── 44. Minimum Subarray.py │ ├── 56. Two Sum.py │ ├── 57. 3Sum.py │ ├── 58. 4Sum.py │ └── 64. Merge Sorted Array.py ├── Lecture8.Data_Structure │ ├── 104. Merge K Sorted Lists.py │ ├── 12. Min Stack.py │ ├── 122. Largest Rectangle in Histogram.py │ ├── 126. Max Tree.py │ ├── 129. Rehashing.py │ ├── 130. Heapify.py │ ├── 134. LRU Cache.py │ ├── 138. Subarray Sum.py │ ├── 40. Implement Queue by Two Stacks.py │ ├── 486. Merge K Sorted Arrays.py │ ├── 494. Implement Stack by Two Queues.py │ └── 517. Ugly Number.py └── Lecture9.Graph_Search │ ├── 120. Word Ladder.py │ ├── 127. Topological Sorting.py │ ├── 135. Combination Sum.py │ ├── 136. Palindrome Partitioning.py │ ├── 137. Clone Graph.py │ ├── 15. Permutations.py │ ├── 153. Combination Sum II.py │ └── 33. N-Queens.py ├── monos_tack └── readme.md ├── monostack └── readme.md ├── none_ladder ├── 104. Merge K Sorted Lists.py ├── 1201. Next Greater Element II.py ├── 1206. Next Greater Element I.py ├── 134. LRU Cache.py ├── 138. Subarray Sum.py ├── 139. Subarray Sum Closest.py ├── 13_strstr.py ├── 156. Merge Intervals.py ├── 15_permutations.py ├── 16_permutations_II.py ├── 17_subsets.py ├── 18_subset_II.py ├── 201. Segment Tree Build.py ├── 213_string_compression.py ├── 28_search_2d_matrix.py ├── 32. Minimum Window Substring.py ├── 3_Digit_Counts.py ├── 405. Submatrix Sum.py ├── 41. Maximum Subarray.py ├── 42. Maximum Subarray II.py ├── 44. Minimum Subarray.py ├── 4_Ugly_NumberII.py ├── 545. Top k Largest Numbers II.py ├── 56_towsum.py ├── 57_3sum.py ├── 5_kth_largest_element.py └── 659_string_serialization.py ├── other ├── calc_fullbinarytree_node_count.py ├── implement_haffman_tree.py └── string_xor.py ├── pinterest └── ContentChecker.py ├── recursive_to_nonrecursive ├── 135. Combination Sum.py └── 18. Subsets II.py ├── segment_tree ├── 201. Segment Tree Build.py ├── 202. Segment Tree Query.py ├── 203. Segment Tree Modify.py ├── 247. Segment Tree Query II.py └── 439. Segment Tree Build II.py └── trie_tree └── 442. Implement Trie (Prefix Tree).py /.gitignore: -------------------------------------------------------------------------------- 1 | .history 2 | .vscode/settings.json 3 | 4 | -------------------------------------------------------------------------------- /.vscode/last.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonforce2010/interview-algothims/338d3bc2f2916c5c4936767b07b2fd22b4121049/.vscode/last.sql -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "/usr/local/bin/python3", 3 | "python.unitTest.unittestArgs": [ 4 | "-v", 5 | "-s", 6 | ".", 7 | "-p", 8 | "test*.py" 9 | ], 10 | "python.unitTest.unittestEnabled": true, 11 | "python.linting.enabled": false 12 | } -------------------------------------------------------------------------------- /amazon/kNearestPostOffices.py: -------------------------------------------------------------------------------- 1 | ''' 2 | https://aonecode.com/amazon-online-assessment-questions 3 | 4 | Find the k post offices located closest to you, given your location and a list of locations of all post offices available. 5 | Locations are given in 2D coordinates in [X, Y], where X and Y are integers. 6 | Euclidean distance is applied to find the distance between you and a post office. 7 | Assume your location is [m, n] and the location of a post office is [p, q], the Euclidean distance between the office and you is SquareRoot((m - p) * (m - p) + (n - q) * (n - q)). 8 | K is a positive integer much smaller than the given number of post offices. from aonecode.com 9 | 10 | e.g. 11 | Input 12 | you: [0, 0] 13 | post_offices: [[-16, 5], [-1, 2], [4, 3], [10, -2], [0, 3], [-5, -9]] 14 | k = 3 15 | 16 | Output from aonecode.com 17 | [[-1, 2], [0, 3], [4, 3]] 18 | ''' 19 | import heapq 20 | class Solutoin: 21 | def findNearestPostOffices(self, srcx, srcy, postOffices): 22 | if not postOffices: 23 | return [] 24 | 25 | heap = [] 26 | for x, y in postOffices: 27 | dist = (srcx - x) ** 2 + (srcy - y) ** 2 28 | heapq.heappush(-dist, x, y) 29 | if len(heap) > k: 30 | heapq.heappop(heap) 31 | 32 | ans = [(heapq.heappop()[1], heapq.heappop()[2]) for i in range(k)] 33 | return ans 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /amazon/moviesOnFlight.py: -------------------------------------------------------------------------------- 1 | ''' 2 | https://aonecode.com/amazon-online-assessment-questions 3 | 4 | You are on a flight and wanna watch two movies during this flight. 5 | You are given int[] movie_duration which includes all the movie durations. 6 | You are also given the duration of the flight which is d in minutes. 7 | Now, you need to pick two movies and the total duration of the two movies is less than or equal to (d - 30min). 8 | Find the pair of movies with the longest total duration. If multiple found, return the pair with the longest movie. 9 | 10 | e.g. 11 | Input 12 | movie_duration: [90, 85, 75, 60, 120, 150, 125] 13 | d: 250 14 | 15 | Output from aonecode.com 16 | [90, 125] 17 | 90min + 125min = 215 is the maximum number within 220 (250min - 30min) 18 | ''' 19 | class Solution: 20 | def findLongestMoivePairs(self, movies, flightDuration): 21 | if not movies: 22 | return [] 23 | 24 | movies.sort() 25 | left, right = 0, len(movies) - 1 26 | ans = [] 27 | while left < right: 28 | duration = movies[left] + movies[right] 29 | if duration > flightDuration: 30 | right -= 1 31 | else: 32 | ans = [left, right] 33 | left += 1 34 | 35 | return ans -------------------------------------------------------------------------------- /amazon/retrieveMostFrequentlyUsedWords.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | def retrieveMostFrequentlyUsedWords(literatureText, wordsToExclude): 4 | # WRITE YOUR CODE HERE 5 | if not literatureText: 6 | return [] 7 | 8 | separatorPattern = re.compile('\W') 9 | words = separatorPattern.split(literatureText) 10 | 11 | wordFreq = {} 12 | result = [] 13 | 14 | for w in words: 15 | if wordsToExclude and w in wordsToExclude: 16 | continue 17 | 18 | if w not in wordFreq: 19 | wordFreq[w] = 0 20 | else: 21 | wordFreq[w] += 1 22 | 23 | hightestFreq = hightestFreq = max(wordFreq.values()) 24 | 25 | for word, freq in wordFreq.items(): 26 | if freq == hightestFreq: 27 | result.append(word) 28 | 29 | return result 30 | 31 | 32 | literatureText = "romeo romeo whereforce art thou romeo" 33 | wordsToExclude = ["art", "thou"] 34 | result = retrieveMostFrequentlyUsedWords(literatureText, wordsToExclude) 35 | print(result) -------------------------------------------------------------------------------- /bit-manipulation/1. A + B Problem.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a function that add two numbers A and B. 3 | 4 | Example 5 | Given a=1 and b=2 return 3. 6 | 7 | Challenge 8 | Of course you can just return a + b to get accepted. But Can you challenge not do it like that?(You should not use + or any arithmetic operators.) 9 | ''' 10 | class Solution: 11 | """ 12 | @param a: An integer 13 | @param b: An integer 14 | @return: The sum of a and b 15 | """ 16 | def aplusb(self, a, b): 17 | # write your code here 18 | while b: 19 | localsum = a ^ b 20 | carry = (a & b) << 1 21 | a = localsum 22 | b = carry 23 | 24 | return a 25 | ''' 26 | // 主要利用异或运算来完成 27 | // 异或运算有一个别名叫做:不进位加法 28 | // 那么a ^ b就是a和b相加之后,该进位的地方不进位的结果 29 | // 然后下面考虑哪些地方要进位,自然是a和b里都是1的地方 30 | // a & b就是a和b里都是1的那些位置,a & b << 1 就是进位 31 | // 之后的结果。所以:a + b = (a ^ b) + (a & b << 1) 32 | // 令a' = a ^ b, b' = (a & b) << 1 33 | // 可以知道,这个过程是在模拟加法的运算过程,进位不可能 34 | // 一直持续,所以b最终会变为0。因此重复做上述操作就可以 35 | // 求得a + b的值。 36 | ''' -------------------------------------------------------------------------------- /bit-manipulation/142. O(1) Check Power of 2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Using O(1) time to check whether an integer n is a power of 2. 3 | 4 | Example 5 | For n=4, return true; 6 | 7 | For n=5, return false; 8 | 9 | Challenge 10 | O(1) time 11 | ''' 12 | class Solution: 13 | """ 14 | @param n: An integer 15 | @return: True or false 16 | """ 17 | def checkPowerOf2(self, n): 18 | # write your code here 19 | if n < 1: 20 | return False 21 | 22 | return n & (n - 1) == 0 23 | 24 | ''' 25 | 用O(1)的时间检查一个数是否是2的平方。这里可以用位运算。我们可以先列举一下,2的倍数的二进制数分别是10、100、1000、10000、100000等等。找到规律后,可以发现 26 | 符合这种规律的数都是最左边是一个1,然后右边都是0.那我们把它减去1之后再看看,分别是01、011、0111、01111、011111等等。然后再把他两做&操作,发现得到的都是0了。这个规律是肯定成立的,利用这个规律就可以在O(1)时间内判断了: 27 | ''' -------------------------------------------------------------------------------- /bit-manipulation/365. Count 1 in Binary.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Count how many 1 in binary representation of a 32-bit integer. 3 | 4 | Example 5 | Given 32, return 1 6 | 7 | Given 5, return 2 8 | 9 | Given 1023, return 9 10 | 11 | Challenge 12 | If the integer is n bits with m 1 bits. Can you do it in O(m) time? 13 | ''' 14 | class Solution: 15 | """ 16 | @param: num: An integer 17 | @return: An integer 18 | """ 19 | def countOnes1(self, num): 20 | # write your code here 21 | count = 0 22 | while num: 23 | if num & 1: 24 | count += 1 25 | 26 | num = num >> 1 27 | 28 | return count 29 | ''' 30 | 每次“&”都会去掉num最右边的1. 31 | 如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。 32 | 举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011. 33 | 我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。 34 | 如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。 35 | ''' 36 | def countOnes2(self, num): 37 | count = 0 38 | while num: 39 | num = num & (num - 1) 40 | count += 1 41 | 42 | return count -------------------------------------------------------------------------------- /bit-manipulation/408. Add Binary.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given two binary strings, return their sum (also a binary string). 3 | 4 | Example 5 | a = 11 6 | 7 | b = 1 8 | 9 | Return 100 10 | ''' 11 | class Solution: 12 | """ 13 | @param a: a number 14 | @param b: a number 15 | @return: the result 16 | """ 17 | def addBinary(self, a, b): 18 | # write your code here 19 | indexa = len(a) - 1 20 | indexb = len(b) - 1 21 | result = [] 22 | carry = 0 23 | 24 | # while循环的条件是只要string a或b其中一个没有扫描完就继续进行 25 | while indexa >= 0 or indexb >= 0: 26 | # 如果某个string已经被扫描完了,我们就用0表示其数组 27 | operanda = int(a[indexa]) if indexa >= 0 else 0 28 | operandb = int(b[indexb]) if indexb >= 0 else 0 29 | localResult = (operanda + operandb + carry) % 2 30 | carry = (operanda + operandb + carry) // 2 31 | result.append(str(localResult)) 32 | 33 | # 注意移动指针,使得while循环能够结束 34 | indexa -= 1 35 | indexb -= 1 36 | 37 | # 记住在末尾检查进位 38 | if carry == 1: 39 | result.append('1') 40 | 41 | # 需要翻转result数组,才能得到正确的表示 42 | return ''.join(reversed(result)) 43 | ''' 44 | 算法武器:数字逐位相加求和 + carry计算 45 | 46 | 本题考查string类型的大数相加算法,我们要了解一下基本点 47 | 48 | 累加需要从最低位开始,也就是从string的最后一位开始 49 | 累加结束条件是两个字符串都遍历完毕的时候 50 | 每次累加计算的本层计算结果是: 51 | (carry + a + b) % 2 52 | 每次累加本层进位结果是: 53 | (carry + a + b) / 2 54 | 当while循环跳出时,不要忘记检查最后的进位,如果进位是1,我们需要在结果前补上“1” 55 | ''' 56 | -------------------------------------------------------------------------------- /ladder_advanced/1_followup_in_code_interview/382_Triangle_Count.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given an array of integers, how many three numbers can be found in the array, so that we can build an triangle whose three edges length is the three numbers that we find? 3 | Example 4 | Given array S = [3,4,6,7], return 3. They are: 5 | 6 | [3,4,6] 7 | [3,6,7] 8 | [4,6,7] 9 | Given array S = [4,4,4,4], return 4. They are: 10 | 11 | [4(1),4(2),4(3)] 12 | [4(1),4(2),4(4)] 13 | [4(1),4(3),4(4)] 14 | [4(2),4(3),4(4)] 15 | ''' 16 | class Solution: 17 | # @param S: a list of integers 18 | # @return: a integer 19 | def triangleCount(self, S): 20 | if not S or len(S) < 3: 21 | raise Exception('Invalid parameter!') 22 | 23 | ans = 0 24 | S.sort() 25 | for index in range(2, len(S)): 26 | longestedge = S[index] 27 | left, right = 0, index - 1 28 | while left < right: 29 | if S[left] + S[right] > longestEdge: 30 | ans += right - left 31 | right -= 1 32 | else: 33 | left += 1 34 | 35 | return ans 36 | 37 | '''Summary 38 | 算法武器:排序 + 双指针(对冲型) 39 | 备注:寻找twosum > target的升级版,本题的target是三角形的斜边,这个斜边可以是数组中的任何一个边,所以我们需要枚举出这个斜边(用一个for循环),内层就变成了twosum > target问题 40 | 41 | 确定能够构成一个三角形的条件是:两边之和大于第三边 42 | - 本题中的第一个for循环时遍历第三条边的所有可能值,内层循环是一个two sum问题,two sum的区间从【0,index - 1】 43 | - two sum的经典解法就是使用一个while循环,让后左右指针相向而行,通过左右指针所指元素和与target进行比较,确定更新指针的方式。 44 | - two sum中,当条件满足时更新答案 45 | ''' -------------------------------------------------------------------------------- /ladder_advanced/1_followup_in_code_interview/461_Kth_Smallest_Numbers_in_Unsorted_Array.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Find the kth smallest numbers in an unsorted integer array. 3 | 4 | Example 5 | Given [3, 4, 1, 2, 5], k = 3, the 3rd smallest numbers are [1, 2, 3]. 6 | 7 | Challenge 8 | An O(nlogn) algorithm is acceptable, if you can do it in O(n), that would be great. 9 | ''' 10 | 11 | import heapq 12 | class Solution: 13 | # @param {int} k an integer 14 | # @param {int[]} nums an integer array 15 | # return {int} kth smallest element 16 | # def kthSmallest(self, k, nums): 17 | # # Write your code here 18 | # import heapq 19 | # heapq.heapify(nums) 20 | # return heapq.nsmallest(k, nums)[-1] 21 | 22 | def kthSmallest(self, k, nums): 23 | if not nums or k < 0: 24 | raise Exception('Invalid parameters!') 25 | 26 | heap = [] 27 | for ele in nums: 28 | heapq.heappush(heap, -ele) 29 | if len(heap) > k: 30 | heapq.heappop(heap) 31 | 32 | return heap[0] 33 | 34 | '''Summary 35 | 算法武器:大根堆(将元素取负值入堆构建大根堆) + 固定尺寸 36 | 答案:返回堆顶元素(别忘记加负号) 37 | 38 | 第k小元问题,还是一下子就要想到用堆,维护一个size为k的最小堆。 39 | 放入元素的时候要注意: 40 | 对于每一个遍历到的元素直接放入 41 | 放置完元素之后检查尺寸,如果已经满尺寸k,则需要pop一个元素出去。因为我们建立的是大根堆,所以最大的元素会被淘汰。 42 | 当所有元素遍历完之后,堆中存放的元素就是最小的k个元素,我们要求的最小的第k个元素就是堆顶元素 43 | 注意元素不断流入大根堆(尺寸为k)中,最终我们可以获得最小的k个元素。因为大根堆总是不断淘汰最大的元素 44 | 同理,如果元素不断流入尺寸为k的小根堆中,最终我们获得的是最大的k个元素,因为小根堆总是淘汰最小元素 45 | 所以以后根据题意,如果求第k大元,我们就建立维护k的小根堆 46 | 如果求第k小元,我们就建立维护k的大根堆 47 | 怎么建立大根堆? 48 | - 只要将放入堆中的元素取反就行 49 | ''' -------------------------------------------------------------------------------- /ladder_advanced/1_followup_in_code_interview/543_Kth_Largest_in_N_Arrays.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Find K-th largest element in N arrays. 3 | Example 4 | In n=2 arrays [[9,3,2,4,7],[1,2,3,4,8]], the 3rd largest element is 7. 5 | 6 | In n=2 arrays [[9,3,2,4,8],[1,2,3,4,2]], the 1st largest element is 9, 2nd largest element is 8, 3rd largest element is 7 and etc. 7 | ''' 8 | 9 | import heapq 10 | class Solution: 11 | """ 12 | @param arrays: a list of array 13 | @param k: An integer 14 | @return: an integer, K-th largest element in N arrays 15 | """ 16 | def KthInArrays(self, arrays, k): 17 | # write your code here 18 | if not arrays or k < 1: 19 | raise Exception('Invalid parameter!') 20 | 21 | heap = [] 22 | for arr in arrays: 23 | for ele in arr: 24 | heapq.heappush(heap, ele) 25 | if len(heap) > k: 26 | heapq.heappop(heap) 27 | 28 | return heap[0] 29 | 30 | '''Summary 31 | 算法武器:堆 32 | 33 | 第k大元问题,还是一下子就要想到用堆,维护一个size为k的最小堆。因为本题数组没有排序,所以我们必须要用两个for循环将所有元素一次放入堆中。 34 | 35 | 放入元素的时候要注意: 36 | 37 | 对于每一个遍历到的元素直接放入 38 | 放置完元素之后检查尺寸,如果已经满尺寸k,则需要pop一个元素出去。因为我们建立的是小根堆,所以最小的元素会被淘汰。 39 | 当所有元素遍历完之后,堆中存放的元素就是最大的k个元素,我们要求的最大的k个元素就是堆顶元素 40 | 注意元素不断流入小根堆(尺寸为k)中,最终我们可以获得最大的k个元素。因为小根堆总是不断淘汰最小的元素 41 | 42 | 同理,如果元素不断流入尺寸为k的大根堆中,最终我们获得的是最小的k个元素,因为大根堆总是淘汰最大元素 43 | 44 | 所以以后根据题意,如果求第k大元,我们就建立维护k的小根堆 45 | 如果求第k小元,我们就建立维护k的大根堆 46 | 47 | 怎么建立大根堆? 48 | - 只要将放入堆中的元素取反就行 49 | ''' -------------------------------------------------------------------------------- /ladder_advanced/1_followup_in_code_interview/5_Kth_Largest_Element.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Find K-th largest element in an array. 3 | Example 4 | In array [9,3,2,4,8], the 3rd largest element is 4. 5 | 6 | In array [1,2,3,4,5], the 1st largest element is 5, 2nd largest element is 4, 3rd largest element is 3 and etc. 7 | 8 | Challenge 9 | O(n) time, O(1) extra memory. 10 | ''' 11 | 12 | import heapq 13 | class Solution: 14 | # @param k & A a integer and an array 15 | # @return ans a integer 16 | # def kthLargestElement(self, k, A): 17 | # import heapq 18 | # heapq.heapify(A) 19 | # return heapq.nlargest(k, A)[-1] 20 | 21 | 22 | def kthLargestElement(self, k, A): 23 | if not A or k < 0: 24 | raise Exception('Invalid parameter!') 25 | 26 | heap = [] 27 | for elem in A: 28 | heapq.heappush(heap, elem) 29 | if len(heap) > k: 30 | heapq.heappop(heap) 31 | 32 | return heap[0] 33 | '''Summary 34 | 算法武器:堆 35 | ''' 36 | 37 | -------------------------------------------------------------------------------- /ladder_advanced/1_followup_in_code_interview/609_Two_Sum_Less_than_or_equal_to_target.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given an array of integers, find how many pairs in the array such that their sum is less than or equal to a specific target number. Please return the number of pairs. 3 | Example 4 | Given nums = [2, 7, 11, 15], target = 24. 5 | Return 5. 6 | 2 + 7 < 24 7 | 2 + 11 < 24 8 | 2 + 15 < 24 9 | 7 + 11 < 24 10 | 7 + 15 < 25 11 | ''' 12 | 13 | class Solution: 14 | """ 15 | @param nums: an array of integer 16 | @param target: an integer 17 | @return: an integer 18 | """ 19 | def twoSum5(self, nums, target): 20 | # write your code here 21 | if not nums: 22 | return 0 23 | 24 | left, right, count = 0, len(nums) - 1, 0 25 | nums.sort() 26 | 27 | while left < right: 28 | if nums[left] + nums[right] > target: 29 | right -= 1 30 | else: 31 | count += right - left 32 | left += 1 33 | 34 | return count 35 | 36 | '''Summary 37 | 算法武器:双指针 38 | Two sum问题,使用双指针(对冲型/相向型)方法,对原数组进行排序,然后根据左右两个指针所指向元素的和与target的关系对左右指针进行调节同时进行个数统计。 39 | ''' -------------------------------------------------------------------------------- /ladder_advanced/2_data_structrure_I/589_Connecting_Graph.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given n nodes in a graph labeled from 1 to n. There is no edges in the graph at beginning. 3 | 4 | You need to support the following method: 5 | 1. connect(a, b), add an edge to connect node a and node b. 2.query(a, b)`, check if two nodes are connected 6 | 7 | Example 8 | 5 // n = 5 9 | query(1, 2) return false 10 | connect(1, 2) 11 | query(1, 3) return false 12 | connect(2, 4) 13 | query(1, 4) return true 14 | ''' 15 | 16 | class ConnectingGraph: 17 | """ 18 | @param: n: An integer 19 | """ 20 | def __init__(self, n): 21 | # do intialization if necessary 22 | self.father = [i for i in range(n + 1)] 23 | 24 | def find(self, x): 25 | if self.father[x] == x: 26 | return x 27 | 28 | self.father[x] = self.find(self.father[x]) 29 | return self.father[x] 30 | 31 | """ 32 | @param: a: An integer 33 | @param: b: An integer 34 | @return: nothing 35 | """ 36 | def connect(self, a, b): 37 | # write your code here 38 | roota = self.find(a) 39 | rootb = self.find(b) 40 | # 只有所属不同集合的时候才进行合并 41 | if roota != rootb: 42 | # 这里合并的时候,是吧集合rootb合并到集合roota中 43 | self.father[rootb] = roota 44 | 45 | """ 46 | @param: a: An integer 47 | @param: b: An integer 48 | @return: A boolean 49 | """ 50 | def query(self, a, b): 51 | # write your code here 52 | return self.find(a) == self.find(b) 53 | 54 | '''Summary 55 | 算法武器:并查集 56 | ''' -------------------------------------------------------------------------------- /ladder_advanced/2_data_structrure_I/634. Word Squares.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given a set of words without duplicates, find all word squares you can build from them. 3 | 4 | A sequence of words forms a valid word square if the kth row and column read the exact same string, where 0 ≤ k < max(numRows, numColumns). 5 | 6 | For example, the word sequence ["ball","area","lead","lady"] forms a word square because each word reads the same both horizontally and vertically. 7 | 8 | b a l l 9 | a r e a 10 | l e a d 11 | l a d y 12 | Notice 13 | There are at least 1 and at most 1000 words. 14 | All words will have the exact same length. 15 | Word length is at least 1 and at most 5. 16 | Each word contains only lowercase English alphabet a-z. 17 | Example 18 | Given a set ["area","lead","wall","lady","ball"] 19 | return [["wall","area","lead","lady"],["ball","area","lead","lady"]] 20 | Explanation: 21 | The output consists of two word squares. The order of output does not matter (just the order of words in each word square matters). 22 | 23 | Given a set ["abat","baba","atan","atal"] 24 | return [["baba","abat","baba","atan"],["baba","abat","baba","atal"]] 25 | Explanation: 26 | The output consists of two word squares. The order of output does not matter (just the order of words in each word square matters). 27 | ''' 28 | -------------------------------------------------------------------------------- /ladder_advanced/3_data_structure_II/12. Min Stack.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Implement a stack with min() function, which will return the smallest number in the stack. 3 | It should support push, pop and min operation all in O(1) cost. 4 | 5 | Notice 6 | min operation will never be called if there is no number in the stack.Example 7 | push(1) 8 | pop() // return 1 9 | push(2) 10 | push(3) 11 | min() // return 2 12 | push(1) 13 | min() // return 1 14 | 15 | ''' 16 | class MinStack(object): 17 | 18 | def __init__(self): 19 | # do some intialize if necessary 20 | self.stack = [] 21 | self.minstack = [] 22 | 23 | def push(self, number): 24 | # write yout code here 25 | self.stack.append(number) 26 | # maintain the minstack 27 | if len(self.minstack) == 0 or number <= self.minstack[-1]: 28 | self.minstack.append(number) 29 | 30 | def pop(self): 31 | # maintain the minstack 32 | if self.stack[-1] == self.minstack[-1]: 33 | self.minstack.pop() 34 | 35 | # pop and return the top item in stack 36 | return self.stack.pop() 37 | 38 | def min(self): 39 | # return the minimum number in stack 40 | return self.minstack[-1] 41 | 42 | '''Summary 43 | 算法武器:最小栈 44 | 最小栈的使用方法: 45 | - 当数据进入数据栈时,判断最小栈是否有元素或是进入的数据比最小栈的栈顶数据还小,那么就将该数据也推入最小栈 46 | - 当进入数据等于最小栈栈顶数据时,我们也将该数据推入最新哦啊哦栈 47 | - 当数据出栈时,我们判断出栈的数据是否等于最小栈栈顶的数据,如果相等,则最小栈也需要出栈一个元素 48 | - 当查看当前栈中的最小数据时,我们返回最小栈的栈顶数据即可 49 | ''' -------------------------------------------------------------------------------- /ladder_advanced/3_data_structure_II/122. Largest Rectangle in Histogram.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram. 3 | Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3]. 4 | The largest rectangle is shown in the shaded area, which has area = 10 unit. 5 | Example 6 | Given height = [2,1,5,6,2,3], 7 | return 10. 8 | ''' 9 | class Solution: 10 | """ 11 | @param height: A list of integer 12 | @return: The area of largest rectangle in the histogram 13 | """ 14 | def largestRectangleArea(self, height): 15 | stack, i, area =[], 0, 0 16 | 17 | while iheight[stack[-1]]: 19 | stack.append(i) 20 | else: 21 | curr=stack.pop() 22 | # width = i if stack==[] else i-stack[len(stack)-1]-1 23 | width = i-stack[len(stack)-1]-1 24 | area = max(area, width * height[curr]) 25 | i -= 1 26 | i+=1 27 | 28 | while stack!=[]: 29 | curr=stack.pop() 30 | width=i if stack==[] else len(height)-stack[len(stack)-1]-1 31 | area=max(area,width*height[curr]) 32 | return area 33 | 34 | '''Summary 35 | 单调栈:http://fisherlei.blogspot.com/2012/12/leetcode-largest-rectangle-in-histogram.html 36 | ''' -------------------------------------------------------------------------------- /ladder_advanced/3_data_structure_II/367. Expression Tree Build.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | The structure of Expression Tree is a binary tree to evaluate certain expressions. 3 | All leaves of the Expression Tree have an number string value. All non-leaves of the Expression Tree have an operator string value. 4 | 5 | Now, given an expression array, build the expression tree of this expression, return the root of this expression tree. 6 | Clarification 7 | See wiki: 8 | Expression Tree 9 | 10 | Example 11 | For the expression (2*6-(23+7)/(1+2)) (which can be represented by ["2" "*" "6" "-" "(" "23" "+" "7" ")" "/" "(" "1" "+" "2" ")"]). 12 | The expression tree will be like 13 | 14 | [ - ] 15 | / \ 16 | [ * ] [ / ] 17 | / \ / \ 18 | [ 2 ] [ 6 ] [ + ] [ + ] 19 | / \ / \ 20 | [ 23 ][ 7 ] [ 1 ] [ 2 ] . 21 | After building the tree, you just need to return root node [-]. 22 | ''' 23 | """ 24 | Definition of ExpressionTreeNode: 25 | class ExpressionTreeNode: 26 | def __init__(self, symbol): 27 | self.symbol = symbol 28 | self.left, self.right = None, None 29 | """ 30 | 31 | 32 | class Solution: 33 | """ 34 | @param: expression: A string array 35 | @return: The root of expression tree 36 | """ 37 | def build(self, expression): 38 | # write your code here 39 | -------------------------------------------------------------------------------- /ladder_advanced/3_data_structure_II/40. Implement Queue by Two Stacks.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | As the title described, you should only use two stacks to implement a queue's actions. 3 | 4 | The queue should support push(element), pop() and top() where pop is pop the first(a.k.a front) element in the queue. 5 | 6 | Both pop and top methods should return the value of first element. 7 | Example 8 | push(1) 9 | pop() // return 1 10 | push(2) 11 | push(3) 12 | top() // return 2 13 | pop() // return 2 14 | Challenge 15 | implement it by two stacks, do not use any other data structure and push, pop and top should be O(1) by AVERAGE. 16 | ''' 17 | class MyQueue: 18 | 19 | def __init__(self): 20 | self.stack1 = [] 21 | self.stack2 = [] 22 | 23 | def adjust(self): 24 | if len(self.stack2) == 0: 25 | while len(self.stack1) != 0: 26 | self.stack2.append(self.stack1.pop()) 27 | 28 | def push(self, element): 29 | self.stack1.append(element) 30 | 31 | def top(self): 32 | self.adjust() 33 | return self.stack2[len(self.stack2) - 1] 34 | 35 | def pop(self): 36 | self.adjust() 37 | return self.stack2.pop() 38 | '''Summary 39 | 算法武器:栈 40 | 算法思路: 41 | - 使用stack1作为数据栈,保存入栈元素,即push操作全部push到stack1中 42 | - 使用stack2作为数据栈,用于出栈元素,即pop元素都从stack2中pop出来 43 | - 但是注意,从stack2中pop数据时,我们要做一个判断: 44 | - 如果stack2为空,那么我们需要把数据从stack1出栈到stack2中,这样stack1中的数据就可以像队列一样的顺序输出了,因为数据的顺序经过栈的翻转改变了。 45 | - 如果stack2不为空,那么就持续从stack2中pop就好,如果有数据push进来,我们依然持续往statck1中push 46 | - adjust操作仅发生在stack2中的数据没了,消费完了,我们才从stack1中全部导入一次 47 | ''' -------------------------------------------------------------------------------- /ladder_advanced/3_data_structure_II/510. Maximal Rectangle.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given a 2D boolean matrix filled with False and True, find the largest rectangle containing all True and return its area. 3 | Example 4 | Given a matrix: 5 | 6 | [ 7 | [1, 1, 0, 0, 1], 8 | [0, 1, 0, 0, 1], 9 | [0, 0, 1, 1, 1], 10 | [0, 0, 1, 1, 1], 11 | [0, 0, 0, 0, 1] 12 | ] 13 | return 6. 14 | ''' 15 | class Solution: 16 | """ 17 | @param matrix: a boolean 2D matrix 18 | @return: an integer 19 | """ 20 | def maximalRectangle(self, matrix): 21 | # write your code here 22 | -------------------------------------------------------------------------------- /ladder_advanced/4_binary_search_sweepline/141. Sqrt(x).py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Implement int sqrt(int x). 3 | 4 | Compute and return the square root of x. 5 | Example 6 | sqrt(3) = 1 7 | 8 | sqrt(4) = 2 9 | 10 | sqrt(5) = 2 11 | 12 | sqrt(10) = 3 13 | 14 | Challenge 15 | O(log(x)) 16 | ''' 17 | class Solution: 18 | """ 19 | @param x: An integer 20 | @return: The sqrt of x 21 | """ 22 | def sqrt(self, x): 23 | start, end = 0, x 24 | while start + 1 < end: 25 | mid = start + (end - start) / 2 26 | if mid ** 2 == x: 27 | return mid 28 | elif mid ** 2 <= x: 29 | start = mid 30 | else: 31 | end = mid 32 | 33 | if end ** 2 <= x: 34 | return end 35 | else: 36 | return start 37 | '''Summary 38 | 算法武器: 二分法 39 | ''' -------------------------------------------------------------------------------- /ladder_advanced/4_binary_search_sweepline/586. Sqrt(x) II.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Implement double sqrt(double x) and x >= 0. 3 | 4 | Compute and return the square root of x. 5 | 6 | Notice 7 | You do not care about the accuracy of the result, we will help you to output results. 8 | Example 9 | Given n = 2 return 1.41421356 10 | ''' 11 | class Solution: 12 | # @param {double} x a double 13 | # @return {double} the square root of x 14 | def sqrt(self, x): 15 | # Write your code here 16 | 17 | left, right = 0.0, x 18 | eps = 1e-12 19 | 20 | if x < 1.0: 21 | right = 1.0 22 | 23 | while right - left > eps: 24 | mid = left + (right - left) / 2 25 | if mid * mid < x: 26 | left = mid 27 | else: 28 | right = mid 29 | 30 | return left 31 | '''Summary 32 | 算法武器:二分法 33 | 注意: 34 | 设计到浮点数的比较大小,需要用一个精度来控制,比如eps = le-12. 35 | solution中while的循环条件是: 36 | 37 | right - left > eps 38 | ''' -------------------------------------------------------------------------------- /ladder_advanced/4_binary_search_sweepline/633. Find the Duplicate Number.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one. 3 | 4 | Notice 5 | You must not modify the array (assume the array is read only). 6 | You must use only constant, O(1) extra space. 7 | Your runtime complexity should be less than O(n^2). 8 | There is only one duplicate number in the array, but it could be repeated more than once. 9 | Example 10 | Given nums = [5,5,4,3,2,1] return 5 11 | Given nums = [5,4,4,3,2,1] return 4 12 | ''' 13 | class Solution: 14 | # @param {int[]} nums an array containing n + 1 integers which is between 1 and n 15 | # @return {int} the duplicate one 16 | def findDuplicate(self, nums): 17 | # Write your code here 18 | if len(nums) <= 1: 19 | return -1 20 | 21 | slow = nums[0] 22 | fast = nums[nums[0]] 23 | while slow != fast: 24 | slow = nums[slow] 25 | fast = nums[nums[fast]] 26 | 27 | fast = 0; 28 | while fast != slow: 29 | fast = nums[fast] 30 | slow = nums[slow] 31 | 32 | return slow 33 | '''Summary 34 | ''' -------------------------------------------------------------------------------- /ladder_advanced/5_dynamic_problem_I/191. Maximum Product Subarray.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Find the contiguous subarray within an array (containing at least one number) which has the largest product. 3 | Example 4 | For example, given the array [2,3,-2,4], the contiguous subarray [2,3] has the largest product = 6. 5 | ''' 6 | class Solution: 7 | # @param nums: an integer[] 8 | # @return: an integer 9 | def maxProduct(self, nums): 10 | f, g = [], [] 11 | f.append(nums[0]) 12 | g.append(nums[0]) 13 | for i in xrange(1, len(nums)): 14 | f.append(max(f[i-1]*nums[i], g[i-1]*nums[i], nums[i])) 15 | g.append(min(f[i-1]*nums[i], g[i-1]*nums[i], nums[i])) 16 | m = f[0] 17 | for i in xrange(1, len(f)): m = max(m, f[i]) 18 | return m 19 | '''Summary 20 | http://blog.csdn.net/whuwangyi/article/details/39577455 21 | ''' -------------------------------------------------------------------------------- /ladder_advanced/5_dynamic_problem_I/392. House Robber.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night. 3 | 4 | Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police. 5 | Example 6 | Given [3, 8, 4], return 8. 7 | 8 | Challenge 9 | O(n) time and O(1) memory. 10 | ''' 11 | class Solution: 12 | # @param A: a list of non-negative integers. 13 | # return: an integer 14 | def houseRobber(self, A): 15 | # write your code here 16 | if not A: 17 | return 0 18 | 19 | dp = [0] * (len(A) + 1) 20 | dp[0], dp[1] = 0, A[0] 21 | 22 | for i in range(2, len(A) + 1): 23 | dp[i] = max(dp[i - 1], dp[i - 2] + A[i - 1]) 24 | 25 | return dp[len(A)] 26 | '''Summary 27 | 算法武器:动态规划 28 | 29 | 本题属于序列型动态规划,不是坐标型动态规划,所以dp[i]或者f[i]定义为:robber前i个房子能够获取的最大金钱。答案表达式为dp[n]或f[n] 30 | ''' -------------------------------------------------------------------------------- /ladder_advanced/5_dynamic_problem_I/393. Best Time to Buy and Sell Stock IV.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Say you have an array for which the ith element is the price of a given stock on day i. 3 | 4 | Design an algorithm to find the maximum profit. You may complete at most k transactions. 5 | 6 | Notice 7 | You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again). 8 | 9 | Example 10 | Given prices = [4,4,6,1,1,4,2,5], and k = 2, return 6. 11 | 12 | Challenge 13 | O(nk) time. 14 | ''' 15 | class Solution: 16 | """ 17 | @param k: an integer 18 | @param prices: a list of integer 19 | @return: an integer which is maximum profit 20 | """ 21 | def maxProfit(self, k, prices): 22 | size = len(prices) 23 | if k >= size / 2: 24 | return self.quickSolve(size, prices) 25 | dp = [None] * (2 * k + 1) 26 | dp[0] = 0 27 | for i in range(size): 28 | for j in range(min(2 * k, i + 1) , 0 , -1): 29 | dp[j] = max(dp[j], dp[j - 1] + prices[i] * [1, -1][j % 2]) 30 | return max(dp) 31 | 32 | def quickSolve(self, size, prices): 33 | sum = 0 34 | for x in range(size - 1): 35 | if prices[x + 1] > prices[x]: 36 | sum += prices[x + 1] - prices[x] 37 | return sum 38 | '''Summary 39 | ''' -------------------------------------------------------------------------------- /ladder_advanced/5_dynamic_problem_I/397. Longest Continuous Increasing Subsequence.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Give an integer array,find the longest increasing continuous subsequence in this array. 3 | 4 | An increasing continuous subsequence: 5 | 6 | Can be from right to left or from left to right. 7 | Indices of the integers in the subsequence should be continuous. 8 | Example 9 | For [5, 4, 2, 1, 3], the LICS is [5, 4, 2, 1], return 4. 10 | 11 | For [5, 1, 2, 3, 4], the LICS is [1, 2, 3, 4], return 4. 12 | ''' 13 | class Solution: 14 | # @param {int[]} A an array of Integer 15 | # @return {int} an integer 16 | def longestIncreasingContinuousSubsequence(self, A): 17 | # need to check both directions according by the problem description 18 | return max(self.getLongest(A), self.getLongest(list(reversed(A)))) 19 | 20 | # find the LICS in Array A 21 | def getLongest(self, A): 22 | length, longest = 0, 0 23 | for index, _ in enumerate(A): 24 | # check if we need to reset length 25 | if index == 0 or A[index] < A[index - 1]: 26 | length = 1 27 | else: 28 | length += 1 29 | # keep the record of the longest 30 | longest = max(longest, length) 31 | return longest 32 | '''Summary 33 | 注意:题目中要求的是下标连续的子序列,我刚开始错把它看成下标可以不连续,lol 34 | 题目基本框架: 35 | 扫描数组,根据条件重置局部解,并且不断更新全局解。 36 | 问题复杂度为O(n) 37 | 38 | 对比题目: 39 | http://lintcode.com/en/problem/continuous-subarray-sum/ 40 | 求具有最大和的连续子数组的题目中我们也使用了这个策略,一次扫描,局部解的计算和重置以及全局解的更新。只不过那道题更复杂一点,还需要使用前向型双指针策略 41 | ''' -------------------------------------------------------------------------------- /ladder_advanced/5_dynamic_problem_I/435. Post Office Problem.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | On one line there are n houses. Give you an array of integer means the the position of each house. Now you need to pick k position to build k post office, so that the sum distance of each house to the nearest post office is the smallest. Return the least possible sum of all distances between each village and its nearest post office. 3 | Example 4 | Given array a = [1,2,3,4,5], k = 2. 5 | return 3. 6 | ''' 7 | class Solution: 8 | """ 9 | @param A: an integer array 10 | @param k: An integer 11 | @return: an integer 12 | """ 13 | def postOffice(self, A, k): 14 | # write your code here 15 | -------------------------------------------------------------------------------- /ladder_advanced/5_dynamic_problem_I/436. Maximal Square.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given a 2D binary matrix filled with 0's and 1's, find the largest square containing all 1's and return its area. 3 | Example 4 | For example, given the following matrix: 5 | 6 | 1 0 1 0 0 7 | 1 0 1 1 1 8 | 1 1 1 1 1 9 | 1 0 0 1 0 10 | Return 4. 11 | ''' 12 | class Solution: 13 | #param matrix: a matrix of 0 and 1 14 | #return: an integer 15 | def maxSquare(self, matrix): 16 | # write your code here 17 | # 获取矩阵的维度 18 | m = len(matrix) 19 | n = len(matrix[0]) 20 | 21 | dp = [[0] * n for _ in range(m)] 22 | 23 | for i in range(n): 24 | dp[0][i] = matrix[0][i] 25 | for i in range(1, m): 26 | dp[i][0] = matrix[i][0] 27 | 28 | for i in xrange(1, m): 29 | for j in xrange(1, n): 30 | if not matrix[i][j]: 31 | dp[i][j] = 0 32 | else: 33 | dp[i][j] = 1 + min(dp[i - 1][j], dp[i - 1][j - 1], dp[i][j - 1]) 34 | 35 | ans = 0 36 | for i in xrange(m): 37 | for j in xrange(n): 38 | ans = max(ans, dp[i][j]) 39 | 40 | return ans*ans 41 | '''Summary 42 | 算法武器:动态规划 43 | 因为动态规划适合求解方案总数,最大最小问题。 44 | ''' -------------------------------------------------------------------------------- /ladder_advanced/5_dynamic_problem_I/581. Longest Repeating Subsequence.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given a string, find length of the longest repeating subsequence such that the two subsequence don’t have same string character at same position, i.e., any ith character in the two subsequences shouldn’t have the same index in the original string. 3 | Example 4 | str = abc, return 0, There is no repeating subsequence 5 | 6 | str = aab, return 1, The two subsequence are a(first) and a(second). 7 | Note that b cannot be considered as part of subsequence as it would be at same index in both. 8 | 9 | str = aabb, return 2 10 | ''' 11 | class Solution: 12 | """ 13 | @param str: a string 14 | @return: the length of the longest repeating subsequence 15 | """ 16 | def longestRepeatingSubsequence(self, str): 17 | # write your code here 18 | 19 | -------------------------------------------------------------------------------- /ladder_advanced/5_dynamic_problem_I/631. Maximal Square II.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given a 2D binary matrix filled with 0's and 1's, find the largest square which diagonal is all 1 and others is 0. 3 | 4 | Notice 5 | Only consider the main diagonal situation. 6 | Example 7 | For example, given the following matrix: 8 | 9 | 1 0 1 0 0 10 | 1 0 0 1 0 11 | 1 1 0 0 1 12 | 1 0 0 1 0 13 | Return 9 14 | ''' 15 | class Solution: 16 | """ 17 | @param matrix: a matrix of 0 an 1 18 | @return: an integer 19 | """ 20 | def maxSquare2(self, matrix): 21 | # write your code here 22 | -------------------------------------------------------------------------------- /ladder_advanced/6_dynamic_problem_II/118. Distinct Subsequences.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given a string S and a string T, count the number of distinct subsequences of T in S. 3 | 4 | A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not). 5 | 6 | Have you met this question in a real interview? 7 | Example 8 | Given S = "rabbbit", T = "rabbit", return 3. 9 | 10 | Challenge 11 | Do it in O(n2) time and O(n) memory. 12 | 13 | O(n2) memory is also acceptable if you do not know how to optimize memory. 14 | ''' 15 | class Solution: 16 | # @param S, T: Two string. 17 | # @return: Count the number of distinct subsequences 18 | def numDistinct(self, S, T): 19 | # write your code here 20 | dp = [[0 for j in range(len(T) + 1)] for i in range(len(S) + 1)] 21 | for i in range(len(S) + 1): 22 | dp[i][0] = 1 23 | for i in xrange(len(S)): 24 | for j in xrange(len(T)): 25 | if S[i] == T[j]: 26 | dp[i+1][j+1] = dp[i][j+1] + dp[i][j] 27 | else: 28 | dp[i+1][j+1] = dp[i][j + 1] 29 | return dp[len(S)][len(T)] 30 | -------------------------------------------------------------------------------- /ladder_advanced/6_dynamic_problem_II/119. Edit Distance.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.) 3 | 4 | You have the following 3 operations permitted on a word: 5 | 6 | Insert a character 7 | Delete a character 8 | Replace a character 9 | Example 10 | Given word1 = "mart" and word2 = "karma", return 3. 11 | ''' 12 | class Solution: 13 | # @param word1 & word2: Two string. 14 | # @return: The minimum number of steps. 15 | def minDistance(self, word1, word2): 16 | # write your code here 17 | len1 = len(word1) 18 | len2 = len(word2) 19 | f = [[0] * (len2 + 1) for i in range(len1 + 1)] 20 | for i in range(len1 + 1): 21 | f[i][0] = i 22 | for j in range(len2 + 1): 23 | f[0][j] = j 24 | 25 | for i in range(1, len1 + 1): 26 | for j in range(1, len2 + 1): 27 | if word2[j - 1] == word1[i - 1]: 28 | f[i][j] = f[i - 1][j - 1] 29 | else: 30 | f[i][j] = min(f[i - 1][j - 1], f[i - 1][j], f[i][j - 1]) + 1 31 | 32 | return f[len1][len2] -------------------------------------------------------------------------------- /ladder_advanced/6_dynamic_problem_II/125. Backpack II.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given n items with size Ai and value Vi, and a backpack with size m. What's the maximum value can you put into the backpack? 3 | 4 | Notice 5 | You cannot divide item into small pieces and the total size of items you choose should smaller or equal to m. 6 | 7 | Have you met this question in a real interview? 8 | Example 9 | Given 4 items with size [2, 3, 5, 7] and value [1, 5, 2, 4], and a backpack with size 10. The maximum value is 9. 10 | 11 | Challenge 12 | O(n x m) memory is acceptable, can you do it in O(m) memory? 13 | ''' 14 | class Solution: 15 | # @param m: An integer m denotes the size of a backpack 16 | # @param A & V: Given n items with size A[i] and value V[i] 17 | # @return: The maximum value 18 | def backPackII(self, m, A, V): 19 | # write your code here 20 | f = [0] * (m+1) 21 | # for i in range(len(A)): 22 | # for j in range(m, A[i] - 1, -1): 23 | # if f[j] < f[j - A[i]] + V[i]: 24 | # f[j] = f[j-A[i]] + V[i] 25 | for j in range(0, m + 1): 26 | for i in range(len(A)): 27 | if j >= A[i] and f[j] < f[j - A[i]] + V[i]: 28 | f[j] = f[j-A[i]] + V[i] 29 | return f[m] 30 | '''Summary 31 | 和背包问题1的区别是: 32 | 背包1给定一个体积的上限,物品体积列表,要求我们装入最大的物品体积 33 | 背包2给定一个体积的上限,物品体积列表,和背包物品value列表,要求我们装入最大的value 34 | 35 | 本题解法分析: 36 | f[i]: 代表当体积上限是i时,我们能够装入背包的最大价值 37 | 答案:f[m], 即当背包体积上限是m时,我们能够装入的最大价值 38 | 39 | 心得:体积上限是限制性因素,我们可以把限制性因素放在dp数组的下标中 40 | ''' -------------------------------------------------------------------------------- /ladder_advanced/6_dynamic_problem_II/168. Burst Balloons.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given n balloons, indexed from 0 to n-1. Each balloon is painted with a number on it represented by array nums. You are asked to burst all the balloons. If the you burst balloon i you will get nums[left] * nums[i] * nums[right] coins. Here left and right are adjacent indices of i. After the burst, the left and right then becomes adjacent. 3 | 4 | Find the maximum coins you can collect by bursting the balloons wisely. 5 | - You may imagine nums[-1] = nums[n] = 1. They are not real therefore you can not burst them. 6 | - 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100 7 | 8 | Have you met this question in a real interview? 9 | Example 10 | Given [4, 1, 5, 10] 11 | Return 270 12 | 13 | nums = [4, 1, 5, 10] burst 1, get coins 4 * 1 * 5 = 20 14 | nums = [4, 5, 10] burst 5, get coins 4 * 5 * 10 = 200 15 | nums = [4, 10] burst 4, get coins 1 * 4 * 10 = 40 16 | nums = [10] burst 10, get coins 1 * 10 * 1 = 10 17 | 18 | Total coins 20 + 200 + 40 + 10 = 270 19 | ''' 20 | class Solution: 21 | """ 22 | @param nums: A list of integer 23 | @return: An integer, maximum coins 24 | """ 25 | def maxCoins(self, nums): 26 | # write your code here 27 | -------------------------------------------------------------------------------- /ladder_advanced/6_dynamic_problem_II/393. Best Time to Buy and Sell Stock IV.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Say you have an array for which the ith element is the price of a given stock on day i. 3 | 4 | Design an algorithm to find the maximum profit. You may complete at most k transactions. 5 | 6 | Notice 7 | You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again). 8 | 9 | Have you met this question in a real interview? 10 | Example 11 | Given prices = [4,4,6,1,1,4,2,5], and k = 2, return 6. 12 | 13 | Challenge 14 | O(nk) time. 15 | ''' 16 | class Solution: 17 | """ 18 | @param k: an integer 19 | @param prices: a list of integer 20 | @return: an integer which is maximum profit 21 | """ 22 | def maxProfit(self, k, prices): 23 | size = len(prices) 24 | if k >= size / 2: 25 | return self.quickSolve(size, prices) 26 | dp = [None] * (2 * k + 1) 27 | dp[0] = 0 28 | for i in range(size): 29 | for j in range(min(2 * k, i + 1) , 0 , -1): 30 | dp[j] = max(dp[j], dp[j - 1] + prices[i] * [1, -1][j % 2]) 31 | return max(dp) 32 | 33 | def quickSolve(self, size, prices): 34 | sum = 0 35 | for x in range(size - 1): 36 | if prices[x + 1] > prices[x]: 37 | sum += prices[x + 1] - prices[x] 38 | return sum 39 | -------------------------------------------------------------------------------- /ladder_advanced/6_dynamic_problem_II/395. Coins in a Line II.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | There are n coins with different value in a line. Two players take turns to take one or two coins from left side until there are no more coins left. The player who take the coins with the most value wins. 3 | 4 | Could you please decide the first player will win or lose? 5 | 6 | Example 7 | Given values array A = [1,2,2], return true. 8 | 9 | Given A = [1,2,4], return false. 10 | ''' 11 | -------------------------------------------------------------------------------- /ladder_advanced/6_dynamic_problem_II/440. Backpack III.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given n kind of items with size Ai and value Vi( each item has an infinite number available) and a backpack with size m. What's the maximum value can you put into the backpack? 3 | 4 | Notice 5 | You cannot divide item into small pieces and the total size of items you choose should smaller or equal to m. 6 | 7 | Have you met this question in a real interview? 8 | Example 9 | Given 4 items with size [2, 3, 5, 7] and value [1, 5, 2, 4], and a backpack with size 10. The maximum value is 15. 10 | ''' 11 | class Solution: 12 | # @param {int[]} A an integer array 13 | # @param {int[]} V an integer array 14 | # @param {int} m an integer 15 | # @return {int} an array 16 | def backPackIII(self, A, V, m): 17 | f = [0 for i in xrange(m+1)] 18 | for (a, v) in zip(A, V): 19 | for j in xrange(a, m+1): 20 | if f[j - a] + v > f[j]: 21 | f[j] = f[j - a] + v 22 | return f[m] 23 | '''Summary 24 | 这道背包问题的特点是物品可以重复放入,限定条件是体积一定,目标能够在有限体积下放入的最大价值。 25 | 26 | for (a, v) in zip(A, V): 27 | for j in xrange(a, m+1): 28 | if f[j - a] + v > f[j]: 29 | f[j] = f[j - a] + v 30 | 解释一下上面这段关键的部分: 31 | 对于每个物品(a, v), 遍历所有可能的体积a ~ m(体积得知道>= a) 32 | 对于每个可能的体积,我们尝试将a加入背包,查看是否能够增加背包的价值,如果可以,我们就更新体积为j时的背包的价值。这种加入是重复的加入的,我们不断地尝试加入a物品,知道背包满为止。 33 | 34 | 备注: 35 | 36 | f[j - a] 代表加入a之前的背包的价值 37 | f[j - a] + v 代表加入a之后的背包价值 38 | ''' -------------------------------------------------------------------------------- /ladder_advanced/6_dynamic_problem_II/562. Backpack IV.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given n items with size nums[i] which an integer array and all positive numbers, no duplicates. An integer target denotes the size of a backpack. Find the number of possible fill the backpack. 3 | 4 | Each item may be chosen unlimited number of times 5 | 6 | Have you met this question in a real interview? 7 | Example 8 | Given candidate items [2,3,6,7] and target 7, 9 | 10 | A solution set is: 11 | [7] 12 | [2, 2, 3] 13 | return 2 14 | ''' 15 | class Solution: 16 | # @param {int[]} nums an integer array and all positive numbers, no duplicates 17 | # @param {int} target an integer 18 | # @return {int} an integer 19 | def backPackIV(self, nums, target): 20 | dp = [0] * (target + 1) 21 | dp[0] = 1 22 | 23 | for a in nums: 24 | for j in xrange(a, target+1): 25 | dp[j] += dp[j - a] 26 | 27 | return dp[target] 28 | '''Summary 29 | 注意:元素可以重复 30 | 31 | 思路:遍历item数组中的每一个元素,针对每一个元素,给其机会去更新每一个可能的体积。 32 | 33 | 对于体积j而言,item a能够贡献给总方案数的个数为dp[j - a], 因为我们选择a的方案数dp[j - a + a]相对于没选a之前的方案数dp[j -a]是相同的,如果dp[j - a]的方案数为0,那么dp[j]就也为0 34 | 35 | 再简单解释一下: 36 | 比如就j = 8, a = 5, 我们看看元素5能够对最终方案数dp[8]的影响。 37 | 我们先求出dp[8 - 5] = dp[3]的方案数,我们假设dp[3] = 20, 那么对于每一个dp[3]的方案中我们都加入元素5,这样就获得了加入5之后对dp[8]的方案的贡献,记为dp[8]',加入元素5之后,这个dp[8]的方案数就可以更新为dp[8] += dp[8]' 38 | 39 | 因为本题不是坐标型动态规划,所以我们为dp数组开target + 1个空间, 这样dp[target]就是我们要求得解 40 | ''' -------------------------------------------------------------------------------- /ladder_advanced/6_dynamic_problem_II/563. Backpack V.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given n items with size nums[i] which an integer array and all positive numbers. An integer target denotes the size of a backpack. Find the number of possible fill the backpack. 3 | 4 | Each item may only be used once 5 | 6 | Have you met this question in a real interview? 7 | Example 8 | Given candidate items [1,2,3,3,7] and target 7, 9 | 10 | A solution set is: 11 | [7] 12 | [1, 3, 3] 13 | return 2 14 | ''' 15 | class Solution: 16 | # @param {int[]} nums an integer array and all positive numbers 17 | # @param {int} target an integer 18 | # @return {int} an integer 19 | def backPackV(self, nums, target): 20 | # Write your code here 21 | dp = [0] * (target + 1) 22 | dp[0] = 1 23 | 24 | for a in nums: 25 | for j in xrange(target, a - 1, -1): 26 | dp[j] += dp[j - a] 27 | 28 | return dp[target] 29 | '''Summary 30 | ''' -------------------------------------------------------------------------------- /ladder_advanced/6_dynamic_problem_II/564. Combination Sum IV.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given an integer array nums with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target. 3 | 4 | Notice 5 | A number in the array can be used multiple times in the combination. 6 | Different orders are counted as different combinations. 7 | 8 | Have you met this question in a real interview? 9 | Example 10 | Given nums = [1, 2, 4], target = 4 11 | 12 | The possible combination ways are: 13 | [1, 1, 1, 1] 14 | [1, 1, 2] 15 | [1, 2, 1] 16 | [2, 1, 1] 17 | [2, 2] 18 | [4] 19 | return 6 20 | ''' 21 | class Solution: 22 | # @param {int[]} nums an integer array and all positive numbers, no duplicates 23 | # @param {int} target an integer 24 | # @return {int} an integer 25 | def backPackVI(self, nums, target): 26 | dp = [0] * (target + 1) 27 | dp[0] = 1 28 | 29 | for j in xrange(1, target+1): 30 | for a in nums: 31 | if j >= a: 32 | dp[j] += dp[j - a] 33 | 34 | return dp[target] 35 | '''Summary 36 | ''' -------------------------------------------------------------------------------- /ladder_advanced/6_dynamic_problem_II/89. k Sum.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given n distinct positive integers, integer k (k <= n) and a number target. 3 | 4 | Find k numbers where sum is target. Calculate how many solutions there are? 5 | 6 | Have you met this question in a real interview? 7 | Example 8 | Given [1,2,3,4], k = 2, target = 5. 9 | 10 | There are 2 solutions: [1,4] and [2,3]. 11 | 12 | Return 2. 13 | ''' 14 | class Solution: 15 | """ 16 | @param A: An integer array. 17 | @param k: a positive integer (k <= length(A)) 18 | @param target: integer 19 | @return an integer 20 | """ 21 | def kSum(self, A, k, target): 22 | # write your code here 23 | ans = [[[0 for i in range(target + 1)] for j in range(k + 1)] for K in range(len(A) + 1)] 24 | 25 | ans[0][0][0] = 1 26 | for I in range(len(A)): 27 | item = A[I] 28 | for J in range(target + 1): 29 | for K in range(k + 1): 30 | tk = k - K 31 | tj = target - J 32 | ans[I + 1][tk][tj] = ans[I][tk][tj] 33 | if tk - 1 >= 0 and tj - item >= 0: 34 | ans[I + 1][tk][tj] += ans[I][tk - 1][tj - item] 35 | return ans[len(A)][k][target] 36 | 37 | '''Summary 38 | http://www.cnblogs.com/yuzhangcmu/p/4279676.html 39 | ''' -------------------------------------------------------------------------------- /ladder_advanced/6_dynamic_problem_II/91. Minimum Adjustment Cost.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given an integer array, adjust each integers so that the difference of every adjacent integers are not greater than a given number target. 3 | 4 | If the array before adjustment is A, the array after adjustment is B, you should minimize the sum of |A[i]-B[i]| 5 | 6 | Notice 7 | You can assume each number in the array is a positive integer and not greater than 100. 8 | 9 | Have you met this question in a real interview? 10 | Example 11 | Given [1,4,2,3] and target = 1, one of the solutions is [2,3,2,3], the adjustment cost is 2 and it's minimal. 12 | 13 | Return 2. 14 | ''' 15 | class Solution: 16 | """ 17 | @param: A: An integer array 18 | @param: target: An integer 19 | @return: An integer 20 | """ 21 | def MinAdjustmentCost(self, A, target): 22 | # write your code here -------------------------------------------------------------------------------- /ladder_advanced/7_followup/22. Flatten List.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given a list, each element in the list can be a list or integer. flatten it into a simply list with integers. 3 | 4 | Notice 5 | If the element in the given list is a list, it can contain list too. 6 | Example 7 | Given [1,2,[1,2]], return [1,2,1,2]. 8 | 9 | Given [4,[3,[2,[1]]]], return [4,3,2,1]. 10 | 11 | Challenge 12 | Do it in non-recursive. 13 | ''' 14 | class Solution(object): 15 | 16 | # @param nestedList a list, each element in the list 17 | # can be a list or integer, for example [1,2,[1,2]] 18 | # @return {int[]} a list of integer 19 | 20 | # Recursive solution 21 | def flatten(self, nestedList): 22 | # Write your code here 23 | # Termination condition 24 | if isinstance(nestedList, int): 25 | return [nestedList] 26 | 27 | result = [] 28 | for ele in nestedList: 29 | result.extend(self.flatten(ele)) 30 | 31 | return result 32 | '''Summary 33 | 算法武器:递归 34 | ''' -------------------------------------------------------------------------------- /ladder_advanced/7_followup/400. Maximum Gap.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given an unsorted array, find the maximum difference between the successive elements in its sorted form. 3 | 4 | Return 0 if the array contains less than 2 elements. 5 | Example 6 | Given [1, 9, 2, 5], the sorted form of it is [1, 2, 5, 9], the maximum gap is between 5 and 9 = 4. 7 | ''' 8 | class Solution: 9 | # @param nums: a list of integers 10 | # @return: the maximum difference 11 | def maximumGap(self, nums): 12 | # write your code here 13 | nums = sorted(nums) 14 | maxGap = 0 15 | for i in xrange(1, len(nums)): 16 | maxGap = max(maxGap, nums[i] - nums[i - 1]) 17 | return maxGap 18 | 19 | 20 | -------------------------------------------------------------------------------- /ladder_advanced/7_followup/402. Continuous Subarray Sum.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given an integer array, find a continuous subarray where the sum of numbers is the biggest. Your code should return the index of the first number and the index of the last number. (If their are duplicate answer, return anyone) 3 | Example 4 | Give [-3, 1, 3, -3, 4], return [1,4]. 5 | ''' 6 | class Solution: 7 | # @param {int[]} A an integer array 8 | # @return {int[]} A list of integers includes the index of the 9 | # first number and the index of the last number 10 | def continuousSubarraySum(self, A): 11 | # Write your code here 12 | maxmumPresum, presum = -sys.maxint, 0 13 | start, end = 0, 0 14 | section = [0, 0] 15 | for i in range(len(A)): 16 | if presum < 0: 17 | presum = A[i] 18 | start = end = i 19 | else: 20 | presum += A[i] 21 | end = i 22 | if maxmumPresum < presum: 23 | maxmumPresum = presum 24 | section = [start, end] 25 | return section 26 | '''Summary 27 | 算法武器:同方向双指针 + 一次数组扫描 28 | 利用双指针技法,都是前向型的,在从左往右扫描数组的过程中寻找最优的区间的起止点。 29 | 总结:向向型双指针一次扫描确定具有最大和的最优子区间 30 | Awesome! 31 | 32 | 算法思路: 33 | - start, end初始化为0, 双指针同方向一遍扫描数组 34 | - 维护一个section变量,作为结果返回 35 | - 维护一个全局最大子区间和maxmumSum 36 | - 维护当前累加和sum,注意这个sum不是前缀和,而是代表区间的累加和 37 | - 当sum累加编程负数的时候,我们对其进行丢弃,重新当当前游标i作为start和end的初值 38 | - 否则将继续自动累加A[i], 并且更新end 39 | - 将当前sum和全局sum比较,如果比全局大,则对全局进行更新,同时更新全局答案 40 | ''' -------------------------------------------------------------------------------- /ladder_advanced/7_followup/540. Zigzag Iterator.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given two 1d vectors, implement an iterator to return their elements alternately. 3 | Example 4 | Given two 1d vectors: 5 | 6 | v1 = [1, 2] 7 | v2 = [3, 4, 5, 6] 8 | By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1, 3, 2, 4, 5, 6]. 9 | ''' 10 | class ZigzagIterator: 11 | 12 | # @param {int[]} v1 v2 two 1d vectors 13 | def __init__(self, v1, v2): 14 | # initialize your data structure here 15 | self.queue = [v for v in (v1, v2) if v] 16 | # self.stack = [v1, v2] 17 | 18 | def next(self): 19 | v = self.queue.pop(0) 20 | value = v.pop(0) 21 | if v: 22 | self.queue.append(v) 23 | return value 24 | 25 | 26 | def hasNext(self): 27 | # Write your code here 28 | return len(self.queue) > 0 29 | 30 | 31 | # Your ZigzagIterator object will be instantiated and called as such: 32 | # solution, result = ZigzagIterator(v1, v2), [] 33 | # while solution.hasNext(): result.append(solution.next()) 34 | # Output result 35 | '''Summary 36 | 算法武器: queue的交替 37 | 本题有交替输出的需求,交替是改变输出顺序,对于顺序有影响的数据结构我们可以想到栈stack或者queue. 本题使用queue来进行求解。 38 | 39 | 我们可以想象list v1和v2在同一队列中,然后分别出队输出一个元素,再把自己(v1或者v2)放入队中,这样就实现了交替。 40 | 41 | 因为我们是用python的list []来模拟queue,所以我们使用了以下api,对于list v 42 | - v.pop(0)表示出队,发生在list的首部 43 | - v.append(item)表示元素入队,发生在list的尾部 44 | 45 | 注意初始化部分,我们不想让空list也加入队中,所以我们做了条件限制 46 | 47 | self.queue = [v for v in (v1, v2) if v] 48 | ''' -------------------------------------------------------------------------------- /ladder_advanced/7_followup/601. Flatten 2D Vector.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Implement an iterator to flatten a 2d vector. 3 | Example 4 | Given 2d vector = 5 | 6 | [ 7 | [1,2], 8 | [3], 9 | [4,5,6] 10 | ] 11 | By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,2,3,4,5,6]. 12 | ''' 13 | class Vector2D(object): 14 | 15 | # @param vec2d {List[List[int]]} 16 | def __init__(self, vec2d): 17 | # Initialize your data structure here 18 | self.row, self.col, self.vec2d = 0, -1, vec2d 19 | 20 | 21 | # @return {int} a next element 22 | def next(self): 23 | # Write your code here 24 | # self.col += 1 25 | return self.vec2d[self.row][self.col] 26 | 27 | 28 | # @return {boolean} true if it has next element 29 | # or false 30 | def hasNext(self): 31 | # Write your code here 32 | self.col += 1 33 | while self.row < len(self.vec2d) and \ 34 | self.col >= len(self.vec2d[self.row]): 35 | self.row, self.col = self.row + 1, 0 36 | return self.row < len(self.vec2d) 37 | '''Summary 38 | 算法武器: 数组 + 基础编程能力 39 | hasNext: 不仅检查是否还有下一个元素,同时移动row和col,使之指向下一个元素的位置。 40 | 数据矩阵中可能有很多空行,hasNext需要把这些空行都跳过,让row和col指向下一个元素的位置 41 | 注意:client在调用next时总是首先调用hasNext方法 42 | 43 | 本题难点: 44 | - iterator重点在于控制游标,对于二维情况就是指row,col 45 | - hasNext方法不仅检测是否有下一个元素,同时移动游标指向下一个元素 46 | - 考虑到边界条件:一个数据矩阵中的行数据可能是空的,并且可能存在多个空行,那么在移动游标时就需要跳过这些空行 47 | ''' -------------------------------------------------------------------------------- /ladder_basic/1_Hack_The_Algorithm_Interview/200_LongestPalindromic_Substring.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def longestPalindrome(self, s): 3 | ansl, ansr, maxx = 0, 1, 0 4 | length = len(s) 5 | 6 | for i in range(length * 2): 7 | if i & 1: 8 | left = i / 2 9 | right = left 10 | else: 11 | left = i / 2 - 1 12 | right = left + 1 13 | 14 | while left >= 0 and right < length and s[left] == s[right]: 15 | left -= 1 16 | right += 1 17 | 18 | left += 1 19 | right -= 1 20 | if right - left + 1 > maxx: 21 | maxx = right - left + 1 22 | ansl = left 23 | ansr = right 24 | 25 | return s[ansl: ansr + 1] -------------------------------------------------------------------------------- /ladder_basic/1_Hack_The_Algorithm_Interview/415_ValidPalindrome.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Description 3 | Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases. 4 | 5 | Have you consider that the string might be empty? This is a good question to ask during an interview. 6 | 7 | For the purpose of this problem, we define empty string as valid palindrome. 8 | 9 | Example 10 | "A man, a plan, a canal: Panama" is a palindrome. 11 | 12 | "race a car" is not a palindrome. 13 | ''' 14 | class Solution: 15 | """ 16 | @param s: A string 17 | @return: Whether the string is a valid palindrome 18 | """ 19 | def isPalindrome(self, s): 20 | # write your code here 21 | if not s: 22 | return True 23 | 24 | left, right = 0, len(s) - 1 25 | while left < right: 26 | while left < right and not s[left].isalpha() and not s[left].isdigit(): 27 | left += 1 28 | while left < right and not s[right].isalpha() and not s[right].isdigit(): 29 | right -= 1 30 | 31 | # 在进行比较的时候还得进行一次检查left < right, 防止越界 32 | if left < right and s[left].lower() != s[right].lower(): 33 | return False 34 | 35 | left += 1 36 | right -= 1 37 | 38 | return True 39 | '''Summary 40 | 41 | ''' -------------------------------------------------------------------------------- /ladder_basic/1_Hack_The_Algorithm_Interview/627. Longest Palindrome.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given a string which consists of lowercase or uppercase letters, find the length of the longest palindromes that can be built with those letters. 3 | 4 | This is case sensitive, for example "Aa" is not considered a palindrome here. 5 | 6 | Example 7 | Given s = "abccccdd" return 7 8 | 9 | One longest palindrome that can be built is "dccaccd", whose length is 7. 10 | ''' 11 | class Solution: 12 | # @param {string} s a string which consists of lowercase or uppercase letters 13 | # @return {int} the length of the longest palindromes that can be built 14 | def longestPalindrome(self, s): 15 | hash = {} 16 | 17 | for c in s: 18 | if c in hash: 19 | del hash[c] 20 | else: 21 | hash[c] = True 22 | 23 | remove = len(hash) 24 | if remove > 0: 25 | remove -= 1 26 | 27 | return len(s) - remove 28 | 29 | '''Summary 30 | 这又是一道关于回文字符串的问题,LeetCode上关于回文串的题有十来道呢,也算一个比较重要的知识点。但是这道题确实不算一道难题,给了我们一个字符串,让我们找出可以组成的最长的回文串的长度,由于字符顺序可以打乱,所以问题就转化为了求偶数个字符的个数,我们了解回文串的都知道,回文串主要有两种形式,一个是左右完全对称的,比如noon, 还有一种是以中间字符为中心,左右对称,比如bob,level等,那么我们统计出来所有偶数个字符的出现总和,然后如果有奇数个字符的话,我们取取出其最大偶数,然后最后结果加1即可 31 | 32 | ''' -------------------------------------------------------------------------------- /ladder_basic/1_Hack_The_Algorithm_Interview/667. Longest Palindromic Subsequence.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given a string s, find the longest palindromic subsequence's length in s. You may assume that the maximum length of s is 1000. 3 | 4 | Example 5 | Given s = "bbbab" return 4 6 | One possible longest palindromic subsequence is "bbbb". 7 | ''' 8 | class Solution: 9 | """ 10 | @param s: the maximum length of s is 1000 11 | @return: the longest palindromic subsequence's length 12 | """ 13 | def longestPalindromeSubseq(self, s): 14 | # write your code here 15 | if not s: 16 | return 0 17 | 18 | n = len(s) 19 | # dp[i][j]: the longestPalindromeSubseq lenght in subsequence s[i:j+1] 20 | dp = [[0] * n for i in range(n)] 21 | 22 | # since dp[i][j] needs to use dp[i+1][j] to calculate, so we need to go backwards when looping through 23 | for i in range(n - 1, -1, -1): 24 | dp[i][i] = 1 25 | for j in range(i + 1, n): 26 | if s[i] == s[j]: 27 | dp[i][j] = dp[i + 1][j - 1] + 2 28 | else: 29 | dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]) 30 | 31 | return dp[0][n - 1] 32 | -------------------------------------------------------------------------------- /ladder_basic/1_Hack_The_Algorithm_Interview/841. String Replace.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Given two identical-sized string array A, B and a string S. All substrings A appearing in S are replaced by B.(Notice: From left to right, it must be replaced if it can be replaced. If there are multiple alternatives, replace longer priorities. After the replacement of the characters can't be replaced again.) 3 | 4 | Example 5 | Given A = ["ab","aba"], B = ["cc","ccc"], S = "ababa", return "cccba". 6 | 7 | In accordance with the rules, the substring that can be replaced is "ab" or "aba". Since "aba" is longer, we replace "aba" with "ccc". 8 | Given A = ["ab","aba"], B = ["cc","ccc"] ,S = "aaaaa" ,return "aaaaa". 9 | 10 | S does not contain strings in A, so no replacement is done. 11 | Given A = ["cd","dab","ab"], B = ["cc","aaa","dd"], S = "cdab", return "ccdd". 12 | 13 | From left to right, you can find the "cd" can be replaced at first, so after the replacement becomes "ccab", then you can find "ab" can be replaced, so the string after the replacement is "ccdd". 14 | ''' 15 | class Solution: 16 | """ 17 | @param a: The A array 18 | @param b: The B array 19 | @param s: The S string 20 | @return: The answer 21 | """ 22 | def stringReplace(self, a, b, s): 23 | # Write your code here 24 | -------------------------------------------------------------------------------- /ladder_basic/2_Binary_Search&LogN_Algorithm/14. First Position of Target.py: -------------------------------------------------------------------------------- 1 | ''' 2 | For a given sorted array (ascending order) and a target number, find the first index of this number in O(log n) time complexity. 3 | 4 | If the target number does not exist in the array, return -1. 5 | 6 | Example 7 | If the array is [1, 2, 3, 3, 4, 5, 10], for given target 3, return 2. 8 | 9 | Challenge 10 | If the count of numbers is bigger than 2^32, can your code work properly? 11 | ''' 12 | class Solution: 13 | # @param nums: The integer array 14 | # @param target: Target number to find 15 | # @return the first position of target in nums, position start from 0 16 | def binarySearch(self, nums, target): 17 | # write your code here 18 | if not nums: 19 | return -1 20 | 21 | start, end = 0, len(nums) - 1 22 | while start + 1 < end: 23 | mid = start + (end - start) / 2 24 | if nums[mid] >= target: 25 | end = mid 26 | else: 27 | start = mid 28 | 29 | if nums[start] == target: 30 | return start 31 | 32 | if nums[end] == target: 33 | return end 34 | 35 | return -1 -------------------------------------------------------------------------------- /ladder_basic/2_Binary_Search&LogN_Algorithm/140. Fast Power.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Calculate the an % b where a, b and n are all 32bit integers. 3 | 4 | Example 5 | For 231 % 3 = 2 6 | 7 | For 1001000 % 1000 = 0 8 | 9 | Challenge 10 | O(logn) 11 | ''' 12 | 13 | class Solution: 14 | """ 15 | @param a, b, n: 32bit integers 16 | @return: An integer 17 | """ 18 | ''' 19 | 本题使用了递归思想,递归思想也是一种降维思想,把问题的维度规模降低,直至最简单情形 20 | 很明显,本题的n是在控制问题的维度 21 | ''' 22 | def fastPower(self, a, b, n): 23 | if n == 1: 24 | return a % b 25 | elif n == 0: 26 | # do not use `1` instead `1 % b` because `b = 1` 27 | return 1 % b 28 | elif n < 0: 29 | return -1 30 | 31 | # (a * b) % p = ((a % p) * (b % p)) % p 32 | product = self.fastPower(a, b, n / 2) 33 | product = (product * product) % b 34 | 35 | # 如果n是奇数,我们就少乘了一次n,所以我们要再乘一次a 36 | if n % 2 == 1: 37 | product = (product * a) % b 38 | 39 | return product 40 | '''Summary 41 | 题解 42 | 43 | 数学题,考察整数求模的一些特性,不知道这个特性的话此题一时半会解不出来,本题中利用的关键特性为: 44 | 45 | (a * b) % p = ((a % p) * (b % p)) % p 46 | 即 a 与 b 的乘积模 p 的值等于 a, b 分别模 p 相乘后再模 p 的值,只能帮你到这儿了,不看以下的答案先想想知道此关系后如何解这道题。 47 | 48 | 首先不太可能先把 ana^nan 具体值求出来,太大了... 所以利用以上求模公式,可以改写 ana^nan 为: 49 | 50 | an=an/2⋅an/2=an/4⋅an/4⋅an/4⋅an/4⋅=...a^n = a^{n/2} \cdot a^{n/2} = a^{n/4} \cdot a^{n/4} \cdot a^{n/4} \cdot a^{n/4} \cdot = ...an=an/2⋅an/2=an/4⋅an/4⋅an/4⋅an/4⋅=... 51 | 52 | 至此递归模型建立。 53 | ''' -------------------------------------------------------------------------------- /ladder_basic/2_Binary_Search&LogN_Algorithm/141. Sqrt(x).py: -------------------------------------------------------------------------------- 1 | ''' 2 | Implement int sqrt(int x). 3 | 4 | Compute and return the square root of x. 5 | 6 | Example 7 | sqrt(3) = 1 8 | 9 | sqrt(4) = 2 10 | 11 | sqrt(5) = 2 12 | 13 | sqrt(10) = 3 14 | 15 | Challenge 16 | O(log(x)) 17 | ''' 18 | class Solution: 19 | """ 20 | @param x: An integer 21 | @return: The sqrt of x 22 | """ 23 | def sqrt(self, x): 24 | start, end = 0, x 25 | while start + 1 < end: 26 | mid = start + (end - start) / 2 27 | if mid ** 2 == x: 28 | return mid 29 | elif mid ** 2 <= x: 30 | start = mid 31 | else: 32 | end = mid 33 | 34 | if end ** 2 <= x: 35 | return end 36 | else: 37 | return start -------------------------------------------------------------------------------- /ladder_basic/2_Binary_Search&LogN_Algorithm/159. Find Minimum in Rotated Sorted Array.py: -------------------------------------------------------------------------------- 1 | '''Description 2 | Suppose a sorted array is rotated at some pivot unknown to you beforehand. 3 | 4 | (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). 5 | 6 | Find the minimum element. 7 | 8 | Example 9 | Given [4, 5, 6, 7, 0, 1, 2] return 0 10 | ''' 11 | class Solution: 12 | # @param nums: a rotated sorted array 13 | # @return: the minimum number in the array 14 | def findMin(self, nums): 15 | # write your code here 16 | if not nums: 17 | return -1 18 | 19 | start, end = 0, len(nums) - 1 20 | target = nums[-1] 21 | while start + 1 < end: 22 | mid = start + (end - start) / 2 23 | if nums[mid] >= target: 24 | start = mid 25 | else: 26 | end = mid 27 | 28 | # 注意这里是取最小值 29 | return min(nums[start], nums[end]) 30 | 31 | '''Summary 32 | 算法武器:基于rotated sorted array的二分法 33 | 34 | 算法思想: 35 | 36 | 二分法不仅可以针对单调的序列,还可以针对rotated sorted array进行 37 | 本题需要求解在RSA中的最小值,我们把这个最小值定义为第一个小于等于target的元素,target = nums[-1] 38 | 二分法擅长解决first index of 或是 last index of 问题 39 | 本题需要通过画图了解到我们如何根据mid和target的值更新start和end,事实上这个跟新方式和我们普通的单调的序列相反 40 | 当nums[mid] > target, 我们更新的是下届start 41 | 其他情况下,我们更新的是上届end 42 | ''' -------------------------------------------------------------------------------- /ladder_basic/2_Binary_Search&LogN_Algorithm/235. Prime Factorization.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Prime factorize a given integer. 3 | 4 | Example 5 | Given 10, return [2, 5]. 6 | 7 | Given 660, return [2, 2, 3, 5, 11]. 8 | ''' 9 | class Solution: 10 | """ 11 | @param num: An integer 12 | @return: an integer array 13 | """ 14 | def primeFactorization(self, num): 15 | # write your code here 16 | -------------------------------------------------------------------------------- /ladder_basic/2_Binary_Search&LogN_Algorithm/428. Pow(x, n).py: -------------------------------------------------------------------------------- 1 | '''Descriptiion 2 | Implement pow(x, n). 3 | 4 | Example 5 | Pow(2.1, 3) = 9.261 6 | Pow(0, 1) = 0 7 | Pow(1, 0) = 1 8 | Challenge 9 | O(logn) time 10 | ''' 11 | class Solution: 12 | """ 13 | @param: x: the base number 14 | @param: n: the power number 15 | @return: the result 16 | """ 17 | def myPow(self, x, n): 18 | # write your code here 19 | # 这块使用了数学公式处理n为负数的情形 20 | if n < 0: 21 | x = 1 / x 22 | n = -n 23 | 24 | ans = 1 25 | tmp = x 26 | 27 | 28 | # 使用2分的方式将O(n)复杂度降低为O(logn)级别 29 | # 本题是2分相除的类型 30 | while n > 0: 31 | # 注意随着n的不断除2,最终n会变成1,算法结束的时候这个if block一定会被执行,计算出ans 32 | # 如果给定n是奇数,则以下if block会被执行两次,一次是最开始进入while循环时,一次是在while即将退出时 33 | if n % 2 == 1: 34 | ans = ans * tmp 35 | tmp *= tmp 36 | n //= 2 37 | 38 | 39 | return ans 40 | 41 | '''Summary 42 | 算法武器:二分法FirstIndexOfTarget + 二分法LastIndexOfTarget 43 | 44 | 算法思想: 45 | 46 | 求出目标元素首次出现的位置firstIndex和最后一次出现的位置lastIndex 47 | 判断是否这两个位置的值不为-1,即目标元素是否存在于数组中,如果不存在则返回0 48 | 如果存在则答案为: lastIndex - firstIndex + 1 49 | 50 | ''' -------------------------------------------------------------------------------- /ladder_basic/2_Binary_Search&LogN_Algorithm/457. Classical Binary Search.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Find any position of a target number in a sorted array. Return -1 if target does not exist. 3 | 4 | Example 5 | Given [1, 2, 2, 4, 5, 5]. 6 | 7 | For target = 2, return 1 or 2. 8 | 9 | For target = 5, return 4 or 5. 10 | 11 | For target = 6, return -1. 12 | 13 | Challenge 14 | O(logn) time 15 | ''' 16 | class Solution: 17 | # @param {int[]} A an integer array sorted in ascending order 18 | # @param {int} target an integer 19 | # @return {int} an integer 20 | def findPosition(self, A, target): 21 | # Write your code here 22 | if not A: 23 | return -1 24 | 25 | start, end = 0, len(A) - 1 26 | while start + 1 < end: 27 | mid = start + (end - start) / 2 28 | if A[mid] == target: 29 | return mid 30 | elif A[mid] < target: 31 | start = mid 32 | else: 33 | end = mid 34 | 35 | if A[start] == target: 36 | return A[start] 37 | 38 | if A[end] == target: 39 | return A[end] 40 | 41 | return -1 42 | -------------------------------------------------------------------------------- /ladder_basic/2_Binary_Search&LogN_Algorithm/458_last_position_of_target.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | """ 3 | @param nums: An integer array sorted in ascending order 4 | @param target: An integer 5 | @return: An integer 6 | """ 7 | def lastPosition(self, nums, target): 8 | # write your code here 9 | if not nums: 10 | return -1 11 | 12 | start, end = 0, len(nums) - 1 13 | while start + 1 < end: 14 | mid = start + (end - start) // 2 15 | if nums[mid] <= target: 16 | start = mid 17 | else: 18 | end = mid 19 | 20 | if nums[end] == target: 21 | return end 22 | elif nums[start] == target: 23 | return start 24 | else: 25 | return -1 26 | -------------------------------------------------------------------------------- /ladder_basic/2_Binary_Search&LogN_Algorithm/459. Closest Number in Sorted Array.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a target number and an integer array A sorted in ascending order, find the index i in A such that A[i] is closest to the given target. 3 | 4 | Return -1 if there is no element in the array. 5 | 6 | Example 7 | Given [1, 2, 3] and target = 2, return 1. 8 | 9 | Given [1, 4, 6] and target = 3, return 1. 10 | 11 | Given [1, 4, 6] and target = 5, return 1 or 2. 12 | 13 | Given [1, 3, 3, 4] and target = 2, return 0 or 1 or 2. 14 | 15 | Challenge 16 | O(logn) time complexity. 17 | ''' 18 | class Solution: 19 | # @param {int[]} A an integer array sorted in ascending order 20 | # @param {int} target an integer 21 | # @return {int} an integer 22 | 23 | def closestNumber(self, A, target): 24 | if not A: 25 | return -1 26 | 27 | start, end = 0, len(A) - 1 28 | while start + 1 < end: 29 | mid = start + (end - start) / 2 30 | if A[mid] == target: 31 | return mid 32 | elif A[mid] > target: 33 | end = mid 34 | else: 35 | start = mid 36 | 37 | return start if abs(A[start] - target) < abs(A[end] - target) else end 38 | '''Summary 39 | 算法武器:二分法(前提数组排序) 40 | 41 | 使用二分法尝试查找给定target的位置,如果找到就返回,如果没有找到就返回两个端点start,end中离target比较近的那个。 42 | 43 | 注意本题的二分法模板(如果没有找到target元素)会最终确定一个start和end边界使得元素的值介于start和end之间 44 | 45 | ''' -------------------------------------------------------------------------------- /ladder_basic/2_Binary_Search&LogN_Algorithm/586. Sqrt(x) II.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Implement double sqrt(double x) and x >= 0. 3 | 4 | Compute and return the square root of x. 5 | 6 | Example 7 | Given n = 2 return 1.41421356 8 | ''' 9 | class Solution: 10 | # @param {double} x a double 11 | # @return {double} the square root of x 12 | def sqrt(self, x): 13 | # Write your code here 14 | 15 | left, right = 0.0, x 16 | eps = 1e-12 17 | 18 | if x < 1.0: 19 | right = 1.0 20 | 21 | while right - left > eps: 22 | mid = left + (right - left) / 2 23 | if mid * mid < x: 24 | left = mid 25 | else: 26 | right = mid 27 | 28 | return left 29 | ''' 30 | 算法武器:二分法 31 | 32 | 注意: 33 | 设计到浮点数的比较大小,需要用一个精度来控制,比如eps = le-12. 34 | solution中while的循环条件是: 35 | right - left > eps 36 | ''' -------------------------------------------------------------------------------- /ladder_basic/2_Binary_Search&LogN_Algorithm/63. Search in Rotated Sorted Array II.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Follow up for Search in Rotated Sorted Array: 3 | 4 | What if duplicates are allowed? 5 | 6 | Would this affect the run-time complexity? How and why? 7 | 8 | Write a function to determine if a given target is in the array. 9 | 10 | Example 11 | Given [1, 1, 0, 1, 1, 1] and target = 0, return true. 12 | Given [1, 1, 1, 1, 1, 1] and target = 0, return false. 13 | ''' 14 | class Solution: 15 | """ 16 | @param A : an integer ratated sorted array and duplicates are allowed 17 | @param target : an integer to be searched 18 | @return : a boolean 19 | """ 20 | def search(self, A, target): 21 | l, h = 0, len(A) - 1 22 | while (l <= h): 23 | m = l + ((h - l) >> 1) 24 | if A[m] == target: 25 | return True 26 | elif (A[m] > A[l] and target < A[m] and target >= A[l]) or (A[m] < A[l] and not (target <= A[h] and target > A[m])): 27 | h = m - 1 28 | else: 29 | l = m + 1 30 | return False -------------------------------------------------------------------------------- /ladder_basic/3_Two_Pointers_Algorithm/103. Linked List Cycle II.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a linked list, return the node where the cycle begins. 3 | 4 | If there is no cycle, return null. 5 | 6 | Example 7 | Given -21->10->4->5, tail connects to node index 1,return 10 8 | 9 | Challenge 10 | Follow up: 11 | 12 | Can you solve it without using extra space? 13 | ''' 14 | """ 15 | Definition of ListNode 16 | class ListNode(object): 17 | 18 | def __init__(self, val, next=None): 19 | self.val = val 20 | self.next = next 21 | """ 22 | class Solution: 23 | """ 24 | @param head: The first node of the linked list. 25 | @return: The node where the cycle begins. 26 | if there is no cycle, return null 27 | """ 28 | def detectCycle(self, head): 29 | # write your code here 30 | if head == None or head.next == None: 31 | return None 32 | 33 | slow = fast = head 34 | while fast and fast.next: 35 | slow = slow.next 36 | fast = fast.next.next 37 | if fast == slow: 38 | break 39 | 40 | if slow == fast: 41 | slow = head 42 | while slow != fast: 43 | slow = slow.next 44 | fast = fast.next 45 | return slow 46 | 47 | return None 48 | 49 | ''' 50 | 算法武器:快慢指针 51 | 52 | 算法思路: 53 | 54 | 进行参数检测 55 | 声明快慢指针 56 | 使用while循环,寻找环,并且找到slow和fast相遇的地方 57 | 如果slow和fast相等,那么使用一个while循环,让slow从链表首部开始走,让fast从当前位置走,走的速度都相同,直到他们相遇,即slow = fast,这个点就是环的起点 58 | 如果slow和fast不等,那么直接返回None 59 | ''' 60 | -------------------------------------------------------------------------------- /ladder_basic/3_Two_Pointers_Algorithm/228. Middle of Linked List.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Find the middle node of a linked list. 3 | 4 | Example 5 | Given 1->2->3, return the node with value 2. 6 | 7 | Given 1->2, return the node with value 1. 8 | 9 | Challenge 10 | If the linked list is in a data stream, can you find the middle without iterating the linked list again? 11 | ''' 12 | """ 13 | Definition of ListNode 14 | class ListNode(object): 15 | 16 | def __init__(self, val, next=None): 17 | self.val = val 18 | self.next = next 19 | """ 20 | 21 | 22 | class Solution: 23 | """ 24 | @param: head: the head of linked list. 25 | @return: a middle node of the linked list 26 | """ 27 | 28 | # 使用快盘指针寻找链表中点 29 | def middleNode(self, head): 30 | # write your code here 31 | if not head: 32 | return None 33 | 34 | slow = head 35 | fast = head.next 36 | 37 | while fast and fast.next: 38 | slow = slow.next 39 | fast = fast.next.next 40 | 41 | return slow -------------------------------------------------------------------------------- /ladder_basic/3_Two_Pointers_Algorithm/31. Partition Array.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array nums of integers and an int k, partition the array (i.e move the elements in "nums") such that: 3 | 4 | All elements < k are moved to the left 5 | All elements >= k are moved to the right 6 | Return the partitioning index, i.e the first index i nums[i] >= k. 7 | 8 | Example 9 | If nums = [3,2,2,1] and k=2, a valid answer is 1. 10 | 11 | Challenge 12 | Can you partition the array in-place and in O(n)? 13 | ''' 14 | class Solution: 15 | """ 16 | @param nums: The integer array you should partition 17 | @param k: As description 18 | @return: The index after partition 19 | """ 20 | # write your code here 21 | # you should partition the nums by k 22 | # and return the partition index as description 23 | def partitionArray(self, nums, k): 24 | start, end = 0, len(nums) - 1 25 | while start <= end: 26 | while start <= end and nums[start] < k: 27 | start += 1 28 | while start <= end and nums[end] >= k: 29 | end -= 1 30 | if start <= end: 31 | nums[start], nums[end] = nums[end], nums[start] 32 | start += 1 33 | end -= 1 34 | return start 35 | 36 | ''' 37 | 算法武器:双指针 38 | 39 | 算法题型:数组划分 40 | 41 | 注意: 42 | 43 | 本题的边界条件start <= end出现在外层和内层的所有while循环中 44 | 本题返回答案为start,即是k元素的位置 45 | k元素有可能不存在在数组之中 46 | ''' -------------------------------------------------------------------------------- /ladder_basic/3_Two_Pointers_Algorithm/382. Triangle Count.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array of integers, how many three numbers can be found in the array, so that we can build an triangle whose three edges length is the three numbers that we find? 3 | 4 | Example 5 | Given array S = [3,4,6,7], return 3. They are: 6 | 7 | [3,4,6] 8 | [3,6,7] 9 | [4,6,7] 10 | Given array S = [4,4,4,4], return 4. They are: 11 | 12 | [4(1),4(2),4(3)] 13 | [4(1),4(2),4(4)] 14 | [4(1),4(3),4(4)] 15 | [4(2),4(3),4(4)] 16 | ''' 17 | class Solution: 18 | # @param S: a list of integers 19 | # @return: a integer 20 | def triangleCount(self, S): 21 | if not S or len(S) < 3: 22 | return 0 23 | 24 | S.sort() 25 | left, right = 0, len(S) - 1 26 | ans = 0 27 | 28 | for index in range(2, len(S)): 29 | longestEdge = S[index] 30 | left, right = 0, index - 1 31 | while left < right: 32 | if S[left] + S[right] > longestEdge: 33 | ans += right - left 34 | right -= 1 35 | else: 36 | left += 1 37 | return ans 38 | 39 | ''' 40 | 算法武器:排序 + 双指针(对冲型) 41 | 42 | 备注:寻找twosum > target的升级版,本题的target是三角形的斜边,这个斜边可以是数组中的任何一个边,所以我们需要枚举出这个斜边(用一个for循环),内层就变成了twosum > target问题 43 | 44 | 确定能够构成一个三角形的条件是:两边之和大于第三边 45 | 46 | 本题中的第一个for循环时遍历第三条边的所有可能值,内层循环是一个two sum问题,two sum的区间从【0,index - 1】 47 | two sum的经典解法就是使用一个while循环,让后左右指针相向而行,通过左右指针所指元素和与target进行比较,确定更新指针的方式。 48 | two sum中,当条件满足时更新答案 49 | ''' -------------------------------------------------------------------------------- /ladder_basic/3_Two_Pointers_Algorithm/443. Two Sum - Greater than target.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array of integers, find how many pairs in the array such that their sum is bigger than a specific target number. Please return the number of pairs. 3 | 4 | Example 5 | Given numbers = [2, 7, 11, 15], target = 24. Return 1. (11 + 15 is the only pair) 6 | 7 | Challenge 8 | Do it in O(1) extra space and O(nlogn) time. 9 | ''' 10 | class Solution: 11 | # @param nums, an array of integer 12 | # @param target, an integer 13 | # @return an integer 14 | def twoSum2(self, nums, target): 15 | if not nums: 16 | return 0 17 | 18 | nums.sort() 19 | count, i, j = 0, 0, len(nums) - 1 20 | while i < j: 21 | if nums[i] + nums[j] <= target: 22 | i += 1 23 | else: 24 | count += j - i 25 | j -= 1 26 | 27 | return count 28 | ''' 29 | 算法武器:排序 + 双指针 30 | 31 | 算法思路: 32 | 33 | 排序 34 | 定义双指针left,right分别指向最左和最右 35 | 在while循环中,计算2sum,即left指针和right指针之和,并将其和target作比较 36 | 如果小于等于target,那么我们就调整下届,将i指针+1 37 | 如果大于target,那么只是我们解的情形,我们找到了一对(i, j)是的满足题目要求,同时我们也知道(i + 1, j), (i + 2, j)....(j - 1, j)都是满足和大于target的情形,所以对于当前的j,总共的有效解的个数为j - i,我们把这个数目累加到count标量,最后将j变量更新 -1 38 | ''' -------------------------------------------------------------------------------- /ladder_basic/3_Two_Pointers_Algorithm/461. Kth Smallest Numbers in Unsorted Array.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Find the kth smallest numbers in an unsorted integer array. 3 | 4 | Example 5 | Given [3, 4, 1, 2, 5], k = 3, the 3rd smallest numbers are [1, 2, 3]. 6 | 7 | Challenge 8 | An O(nlogn) algorithm is acceptable, if you can do it in O(n), that would be great. 9 | ''' 10 | class Solution: 11 | # @param {int} k an integer 12 | # @param {int[]} nums an integer array 13 | # return {int} kth smallest element 14 | # def kthSmallest(self, k, nums): 15 | # # Write your code here 16 | # import heapq 17 | # heapq.heapify(nums) 18 | # return heapq.nsmallest(k, nums)[-1] 19 | 20 | def kthSmallest(self, k, nums): 21 | import heapq 22 | heap = [] 23 | for elem in nums: 24 | heapq.heappush(heap, -elem) 25 | if len(heap) > k: 26 | heapq.heappop(heap) 27 | 28 | return -heap[0] 29 | 30 | ''' 31 | 算法武器:大根堆(将元素取负值入堆构建大根堆) + 固定尺寸 32 | 答案:返回堆顶元素(别忘记加负号) 33 | 34 | 第k小元问题,还是一下子就要想到用堆,维护一个size为k的最小堆。 35 | 放入元素的时候要注意: 36 | 对于每一个遍历到的元素直接放入 37 | 放置完元素之后检查尺寸,如果已经满尺寸k,则需要pop一个元素出去。因为我们建立的是大根堆,所以最大的元素会被淘汰。 38 | 当所有元素遍历完之后,堆中存放的元素就是最小的k个元素,我们要求的最小的第k个元素就是堆顶元素 39 | 注意元素不断流入大根堆(尺寸为k)中,最终我们可以获得最小的k个元素。因为大根堆总是不断淘汰最大的元素 40 | 同理,如果元素不断流入尺寸为k的小根堆中,最终我们获得的是最大的k个元素,因为小根堆总是淘汰最小元素 41 | 所以以后根据题意,如果求第k大元,我们就建立维护k的小根堆 42 | 如果求第k小元,我们就建立维护k的大根堆 43 | 怎么建立大根堆? 44 | 45 | 只要将放入堆中的元素取反就行 46 | 47 | ''' -------------------------------------------------------------------------------- /ladder_basic/3_Two_Pointers_Algorithm/464. Sort Integers II.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an integer array, sort it in ascending order. Use quick sort, merge sort, heap sort or any O(nlogn) algorithm. 3 | 4 | Example 5 | Given [3, 2, 1, 4, 5], return [1, 2, 3, 4, 5]. 6 | ''' 7 | import random 8 | class Solution: 9 | # @param {int[]} A an integer array 10 | # @return nothing 11 | def sortIntegers2(self, A): 12 | # Write your code here 13 | self.qsort(A, 0, len(A) - 1) 14 | 15 | 16 | # inplace quick sort 17 | def qsort(self, A, start, end): 18 | if start >= end: 19 | return 20 | 21 | i, j = start, end 22 | # 随机选择一个数轴记录 23 | pivot = A[random.randint(start, end)] 24 | 25 | 26 | while i < j: 27 | while A[i] < pivot: 28 | i += 1 29 | while A[j] > pivot: 30 | j -= 1 31 | if i < j: 32 | A[i], A[j] = A[j], A[i] 33 | i, j = i + 1, j - 1 34 | A[i - 1] = pivot 35 | 36 | self.qsort(A, start, i - 2) 37 | self.qsort(A, i, end) -------------------------------------------------------------------------------- /ladder_basic/3_Two_Pointers_Algorithm/521. Remove Duplicate Numbers in Array.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array of integers, remove the duplicate numbers in it. 3 | 4 | You should: 5 | 6 | Do it in place in the array. 7 | Move the unique numbers to the front of the array. 8 | Return the total number of the unique numbers. 9 | Example 10 | Given nums = [1,3,1,4,4,2], you should: 11 | 12 | Move duplicate integers to the tail of nums => nums = [1,3,4,2,?,?]. 13 | Return the number of unique integers in nums => 4. 14 | Actually we don't care about what you place in ?, we only care about the part which has no duplicate integers. 15 | 16 | Challenge 17 | Do it in O(n) time complexity. 18 | Do it in O(nlogn) time without extra space. 19 | ''' 20 | class Solution: 21 | # @param {int[]} nums an array of integers 22 | # @return {int} the number of unique integers 23 | def deduplication(self, nums): 24 | # Write your code here 25 | # 26 | if not nums: 27 | return 0 28 | 29 | cursor = 0 30 | nums.sort() 31 | for num in nums: 32 | if num != nums[cursor]: 33 | nums[cursor + 1] = num 34 | cursor += 1 35 | 36 | return cursor + 1 37 | ''' 38 | 算法武器:数组单指针 + 一遍扫描 39 | 40 | 算法思路: 41 | -先对nums数组进行排序,因为我们需要相同数连起来 42 | 43 | 使用单指针cursor指向数组中不重复元素的最后一个位置 44 | 使用for循环扫描每个元素 45 | 如果扫描到的元素和cursor所指元素不同,那么我们就将该元素复制到cursor + 1的位置,然后cursor = cursor + 1,使cursor始终指向数组中不重复元素的最后一个位置 46 | 算法结束时返回cursor + 1 47 | 注意:最后返回的是元素的个数,所以我们要把cursor + 1 48 | ''' -------------------------------------------------------------------------------- /ladder_basic/3_Two_Pointers_Algorithm/533. Two Sum - Closest to target.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array nums of n integers, find two integers in nums such that the sum is closest to a given number, target. 3 | 4 | Return the difference between the sum of the two integers and the target. 5 | 6 | Example 7 | Given array nums = [-1, 2, 1, -4], and target = 4. 8 | 9 | The minimum difference is 1. (4 - (2 + 1) = 1). 10 | 11 | Challenge 12 | Do it in O(nlogn) time complexity. 13 | ''' 14 | class Solution: 15 | # @param {int[]} nums an integer array 16 | # @param {int} target an integer 17 | # @return {int} the difference between the sum and the target 18 | def twoSumClosest(self, nums, target): 19 | # Write your code here 20 | if not nums or len(nums) < 2: 21 | return -1 22 | 23 | nums.sort() 24 | l, r = 0, len(nums) - 1 25 | minDist = sys.maxint 26 | while l < r: 27 | value = nums[l] + nums[r] 28 | dist = abs(target - value) 29 | if dist < minDist: 30 | minDist = dist 31 | if value > target: 32 | r -= 1 33 | elif value < target: 34 | l += 1 35 | else: 36 | return 0 37 | 38 | return minDist 39 | ''' 40 | 算法武器:双指针(对冲型) 41 | 42 | 注意:本题在while体中计算two sum时,我们每次都要计算一次dist,然后更新全局的minDist,然后再更具two sum和taget的比较,我们更新l,r的边界,循环继续进行。 43 | 44 | two sum或各种sum的题目,首先排序!重要的事情说三遍 45 | 首先排序! 46 | 首先排序! 47 | 首先排序! 48 | ''' -------------------------------------------------------------------------------- /ladder_basic/3_Two_Pointers_Algorithm/539. Move Zeroes.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements. 3 | 4 | Example 5 | Given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0]. 6 | ''' 7 | class Solution: 8 | # @param {int[]} nums an integer array 9 | # @return nothing, do this in-place 10 | def moveZeroes(self, nums): 11 | # Write your code here 12 | y = 0 13 | for x in range(len(nums)): 14 | if nums[x]: 15 | if nums[x] != nums[y]: 16 | nums[x], nums[y] = nums[y], nums[x] 17 | y += 1 18 | ''' 19 | http://bookshadow.com/weblog/2015/09/19/leetcode-move-zeroes/ 20 | 解题思路: 21 | 题目可以在O(n)时间复杂度内求解 22 | 23 | 算法步骤: 24 | 25 | 使用两个"指针"x和y,初始令y = 0 26 | 27 | 利用x遍历数组nums: 28 | 29 | 若nums[x]非0,则交换nums[x]与nums[y],并令y+1 30 | 31 | 算法简析: 32 | 33 | y指针指向首个0元素可能存在的位置 34 | 35 | 遍历过程中,算法确保[y, x)范围内的元素均为0 36 | ''' -------------------------------------------------------------------------------- /ladder_basic/3_Two_Pointers_Algorithm/56. Two Sum.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array of integers, find two numbers such that they add up to a specific target number. 3 | 4 | The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are zero-based. 5 | 6 | Example 7 | numbers=[2, 7, 11, 15], target=9 8 | 9 | return [0, 1] 10 | 11 | Challenge 12 | Either of the following solutions are acceptable: 13 | 14 | O(n) Space, O(nlogn) Time 15 | O(n) Space, O(n) Time 16 | ''' 17 | class Solution: 18 | """ 19 | @param numbers: An array of Integer 20 | @param target: target = numbers[index1] + numbers[index2] 21 | @return: [index1 + 1, index2 + 1] (index1 < index2) 22 | """ 23 | def twoSum(self, numbers, target): 24 | # write your code here 25 | if not numbers: 26 | return [-1, -1] 27 | 28 | myhash = {} 29 | for index, num in enumerate(numbers): 30 | if target - num in myhash: 31 | return [myhash[target - num], index] 32 | 33 | myhash[num] = index 34 | 35 | return [-1, -1] 36 | -------------------------------------------------------------------------------- /ladder_basic/3_Two_Pointers_Algorithm/587. Two Sum - Unique pairs.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array of integers, find how many unique pairs in the array such that their sum is equal to a specific target number. Please return the number of pairs. 3 | 4 | Example 5 | Given nums = [1,1,2,45,46,46], target = 47 6 | return 2 7 | 8 | 1 + 46 = 47 9 | 2 + 45 = 47 10 | ''' 11 | class Solution: 12 | # @param nums {int[]} an array of integer 13 | # @param target {int} an integer 14 | # @return {int} an integer 15 | def twoSum6(self, nums, target): 16 | # Write your code here 17 | if not nums or len(nums) < 2: 18 | return 0 19 | 20 | count = 0 21 | nums.sort() 22 | l, r = 0, len(nums) - 1 23 | while l < r: 24 | value = nums[l] + nums[r] 25 | if value > target: 26 | r -= 1 27 | elif value < target: 28 | l += 1 29 | else: 30 | l += 1 31 | r -= 1 32 | count += 1 33 | while l < r and nums[l] == nums[l - 1]: l += 1 34 | while l < r and nums[r] == nums[r + 1]: r -= 1 35 | 36 | return count 37 | 38 | ''' 39 | 算法武器:双指针 40 | 41 | 本题要求解的是unique pairs,所以我们需要加入去重操作。 42 | 去重操作过程: 43 | 44 | 使用while循环,进行去重,while循环的条件和外层的while循环条件相同 45 | 去重只在得到答案部分进行去重,因为我们只希望避免重复的答案。当然在前面的两个条件中去重也没有问题 46 | ''' -------------------------------------------------------------------------------- /ladder_basic/3_Two_Pointers_Algorithm/604. Window Sum.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array of n integer, and a moving window(size k), move the window at each iteration from the start of the array, find the sum of the element inside the window at each moving. 3 | 4 | Example 5 | For array [1,2,7,8,5], moving window size k = 3. 6 | 1 + 2 + 7 = 10 7 | 2 + 7 + 8 = 17 8 | 7 + 8 + 5 = 20 9 | return [10,17,20] 10 | ''' 11 | class Solution: 12 | # @param nums {int[]} a list of integers 13 | # @param k {int} size of window 14 | # @return {int[]} the sum of element inside the window at each moving 15 | def winSum(self, nums, k): 16 | # Write your code here 17 | n = len(nums) 18 | if n < k or k <= 0: 19 | return [] 20 | 21 | sums = [0] * (n - k + 1) 22 | 23 | for i in range(k): 24 | sums[0] += nums[i] 25 | 26 | for i in xrange(1, n - k + 1): 27 | sums[i] = sums[i - 1] - nums[i - 1] + nums[i + k - 1] 28 | 29 | return sums 30 | 31 | ''' 32 | 算法武器:窗口和(利用windowSum[i - 1] 计算 windowSum[i]) 33 | 计算公式需要熟记: 34 | 35 | sums[i] = sums[i - 1] - nums[i] + nums[i + k - 1] 36 | 窗口和的个数计算: 37 | 38 | windowSumCount = n - k + 1 39 | 算法思路: 40 | 41 | 参数合法性检查 42 | 初始化窗口和数组,开辟空间,窗口和数组长度为n - k + 1 43 | 计算第一个窗口和sums[0],因为后面的窗口和都会由前一个窗口和递推出来 44 | for循环遍,求解所有的窗口和sums[i], 例如如下公式 45 | sums[i] = sums[i - 1] - nums[i] + nums[i + k - 1] 46 | ''' -------------------------------------------------------------------------------- /ladder_basic/3_Two_Pointers_Algorithm/608. Two Sum II - Input array is sorted.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number. 3 | 4 | The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based. 5 | 6 | Example 7 | Given nums = [2, 7, 11, 15], target = 9 8 | return [1, 2] 9 | ''' 10 | class Solution: 11 | """ 12 | @param nums {int[]} n array of Integer 13 | @param target {int} = nums[index1] + nums[index2] 14 | @return {int[]} [index1 + 1, index2 + 1] (index1 < index2) 15 | """ 16 | def twoSum(self, nums, target): 17 | # Write your code here 18 | if not nums: 19 | return [] 20 | 21 | l, r = 0, len(nums) - 1 22 | while l < r: 23 | value = nums[l] + nums[r] 24 | if value > target: 25 | r -= 1 26 | elif value < target: 27 | l += 1 28 | else: 29 | return[l + 1, r + 1] 30 | 31 | return [] 32 | 33 | ''' 34 | 算法武器:双指针 35 | 36 | 算法过程: 37 | 38 | 定义双指针分别指向数组最左和最右 39 | 两个指针所指元素加和 40 | 如果和大于目标,那么更新上界,right -= 1 41 | 如果和小于目标,那么更新下界,left += 1 42 | 如果和定于目标,那么返回结果 43 | 注意while循环的条件是 l < r 44 | l = r是不可行的,因为two sum要求是两个数。 45 | ''' -------------------------------------------------------------------------------- /ladder_basic/3_Two_Pointers_Algorithm/894. Pancake Sorting.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an an unsorted array, sort the given array. You are allowed to do only following operation on array. 3 | 4 | flip(arr, i): Reverse array from 0 to i 5 | Unlike a traditional sorting algorithm, which attempts to sort with the fewest comparisons possible, the goal is to sort the sequence in as few reversals as possible. 6 | 7 | Example 8 | Given array = [6, 7, 10, 11, 12, 20, 23] 9 | Use flip(arr, i) function to sort the array. 10 | ''' 11 | """ 12 | class FlipTool: 13 | 14 | @classmethod 15 | def flip(cls, arr, i): 16 | ... 17 | """ 18 | class Solution: 19 | """ 20 | @param array: an integer array 21 | @return: nothing 22 | """ 23 | def pancakeSort(self, array): 24 | # Write your code here -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/104. Merge K Sorted Lists.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Merge k sorted linked lists and return it as one sorted list. 3 | 4 | Analyze and describe its complexity. 5 | 6 | Example 7 | Given lists: 8 | 9 | [ 10 | 2->4->null, 11 | null, 12 | -1->null 13 | ], 14 | return -1->2->4->null. 15 | ''' 16 | class Solution: 17 | # @param a list of ListNode 18 | # @return a ListNode 19 | def mergeKLists(self, lists): 20 | heap = [] 21 | for node in lists: 22 | if node: 23 | heap.append((node.val, node)) 24 | 25 | import heapq 26 | heapq.heapify(heap) 27 | head = ListNode(0); curr = head 28 | while heap: 29 | pop = heapq.heappop(heap) 30 | curr.next = ListNode(pop[0]) 31 | curr = curr.next 32 | if pop[1].next: 33 | heapq.heappush(heap, (pop[1].next.val, pop[1].next)) 34 | return head.next 35 | 36 | ''' 37 | 算法武器: heap + list + dummy head 38 | 39 | 我们使用堆的方式和使用队列的模式有相同模式,即我们使用一个while循环,一次从堆中取出元素,进行操作,同时随着操作右不断地向堆中加入元素,知道堆中的元素被处理完毕。 40 | 41 | 思路和求解过程: 42 | 43 | 合并多个链表的问题一定是使用堆 44 | 扫描链表的链表,把每个链表的头结点加入到堆中 45 | 放入堆中的元素是一个二元组,第一个元素是node.val,堆会根据这个值进行排序 46 | 使用虚拟头结点简化计算 47 | 每当出堆一次,就查看出堆的链表节点是否还有下一个节点,如果有,就将其入堆 48 | ''' -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/128. Hash Function.py: -------------------------------------------------------------------------------- 1 | ''' 2 | In data structure Hash, hash function is used to convert a string(or any other type) into an integer smaller than hash size and bigger or equal to zero. The objective of designing a hash function is to "hash" the key as unreasonable as possible. A good hash function can avoid collision as less as possible. A widely used hash function algorithm is using a magic number 33, consider any string as a 33 based big integer like follow: 3 | 4 | hashcode("abcd") = (ascii(a) * 333 + ascii(b) * 332 + ascii(c) *33 + ascii(d)) % HASH_SIZE 5 | 6 | = (97* 333 + 98 * 332 + 99 * 33 +100) % HASH_SIZE 7 | 8 | = 3595978 % HASH_SIZE 9 | 10 | here HASH_SIZE is the capacity of the hash table (you can assume a hash table is like an array with index 0 ~ HASH_SIZE-1). 11 | 12 | Given a string as a key and the size of hash table, return the hash value of this key.f 13 | 14 | 15 | 16 | Example 17 | For key="abcd" and size=100, return 78 18 | ''' 19 | class Solution: 20 | """ 21 | @param key: A String you should hash 22 | @param HASH_SIZE: An integer 23 | @return an integer 24 | """ 25 | def hashCode(self, key, HASH_SIZE): 26 | # write your code here 27 | ans = 0 28 | for x in key: 29 | ans = (ans * 33 + ord(x)) % HASH_SIZE 30 | return ans -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/130. Heapify.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an integer array, heapify it into a min-heap array. 3 | 4 | For a heap array A, A[0] is the root of heap, and for each A[i], A[i * 2 + 1] is the left child of A[i] and A[i * 2 + 2] is the right child of A[i]. 5 | Example 6 | Given [3,2,1,4,5], return [1,2,3,4,5] or any legal heap array. 7 | 8 | Challenge 9 | O(n) time complexity 10 | ''' 11 | class Solution: 12 | # @param A: Given an integer array 13 | # @return: void 14 | def heapify(self, A): 15 | for pos in range((len(A) - 1) / 2, -1, -1): 16 | self.siftdown(A, pos) 17 | 18 | def siftdown(self, A, rootPos): 19 | while rootPos * 2 + 1 < len(A): 20 | son = rootPos * 2 + 1 21 | if son + 1 < len(A) and A[son + 1] < A[son]: 22 | son = son + 1 23 | if A[rootPos] <= A[son]: 24 | break 25 | 26 | A[rootPos], A[son] = A[son], A[rootPos] 27 | rootPos = son 28 | 29 | ''' 30 | 算法武器:建堆 31 | 32 | 本题考查建堆(二叉堆)的实现。建堆的过程如下: 33 | 34 | 从二叉树的最后一个拥有孩子的父节点开始,逐步向上(到树根节点)进行下滑操作,将每个节点为根的子树调整成一个堆,直到整个树成为一个堆。 35 | 下滑操作的过程:从给定的树根节点开始,将树根节点和两个孩子比较,取两个孩子中最小的节点和树根节点比较,如果比根小,那么根节点和该子节点交换,然后递归向下调整,知道该子树成为一个堆。 36 | ''' -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/209. First Unique Character in a String.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Find the first unique character in a given string. You can assume that there is at least one unique character in the string. 3 | 4 | Example 5 | For "abaccdeff", return 'b'. 6 | ''' 7 | class Solution: 8 | """ 9 | @param str: str: the given string 10 | @return: char: the first unique character in a given string 11 | """ 12 | def firstUniqChar(self, str): 13 | # Write your code here 14 | -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/24. LFU Cache.py: -------------------------------------------------------------------------------- 1 | ''' 2 | LFU (Least Frequently Used) is a famous cache eviction algorithm. 3 | 4 | For a cache with capacity k, if the cache is full and need to evict a key in it, the key with the lease frequently used will be kicked out. 5 | 6 | Implement set and get method for LFU cache. 7 | 8 | Example 9 | Given capacity=3 10 | 11 | set(2,2) 12 | set(1,1) 13 | get(2) 14 | >> 2 15 | get(1) 16 | >> 1 17 | get(2) 18 | >> 2 19 | set(3,3) 20 | set(4,4) 21 | get(3) 22 | >> -1 23 | get(2) 24 | >> 2 25 | get(1) 26 | >> 1 27 | get(4) 28 | >> 4 29 | ''' 30 | class LFUCache: 31 | """ 32 | @param: capacity: An integer 33 | """ 34 | def __init__(self, capacity): 35 | # do intialization if necessary 36 | 37 | """ 38 | @param: key: An integer 39 | @param: value: An integer 40 | @return: nothing 41 | """ 42 | def set(self, key, value): 43 | # write your code here 44 | 45 | """ 46 | @param: key: An integer 47 | @return: An integer 48 | """ 49 | def get(self, key): 50 | # write your code here 51 | -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/471. Top K Frequent Words.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a list of words and an integer k, return the top k frequent words in the list. 3 | 4 | Example 5 | Given 6 | 7 | [ 8 | "yes", "lint", "code", 9 | "yes", "code", "baby", 10 | "you", "baby", "chrome", 11 | "safari", "lint", "code", 12 | "body", "lint", "code" 13 | ] 14 | for k = 3, return ["code", "lint", "baby"]. 15 | 16 | for k = 4, return ["code", "lint", "baby", "yes"], 17 | 18 | Challenge 19 | Do it in O(nlogk) time and O(n) extra space. 20 | ''' 21 | from collections import * 22 | class Solution: 23 | # @param {string[]} words a list of string 24 | # @param {int} k an integer 25 | # @return {string[]} a list of string 26 | def topKFrequentWords(self, words, k): 27 | # Write your code here 28 | dict = defaultdict(int) 29 | for word in words: 30 | dict[word] += 1 31 | p = [] 32 | for key, value in dict.items(): 33 | p.append((value, key)) 34 | 35 | p.sort(cmp=self.cmp) 36 | 37 | result = [] 38 | for i in xrange(k): 39 | result.append(p[i][1]) 40 | return result 41 | 42 | def cmp(self, a, b): 43 | if a[0] > b[0] or a[0] == b[0] and a[1] < b[1]: 44 | return -1 45 | elif a[0] == b[0] and a[1] == b[1]: 46 | return 0 47 | else: 48 | return 1 49 | 50 | ''' 51 | 算法武器:哈希表统计 + 排序 52 | 53 | 题目中需要对结果进行特殊排序,所以我们写了一个专门的cmp函数作为排序的依据 54 | ''' -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/486. Merge K Sorted Arrays.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given k sorted integer arrays, merge them into one sorted array. 3 | 4 | Example 5 | Given 3 sorted arrays: 6 | 7 | [ 8 | [1, 3, 5, 7], 9 | [2, 4, 6], 10 | [0, 8, 9, 10, 11] 11 | ] 12 | return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]. 13 | 14 | Challenge 15 | Do it in O(N log k). 16 | 17 | N is the total number of integers. 18 | k is the number of arrays. 19 | ''' 20 | import heapq 21 | class Solution: 22 | # @param {int[][]} arrays k sorted integer arrays 23 | # @return {int[]} a sorted array 24 | 25 | def mergekSortedArrays(self, arrays): 26 | result = [] 27 | heap = [] 28 | for row, array in enumerate(arrays): 29 | if len(array) == 0: 30 | continue 31 | heapq.heappush(heap, (array[0], row, 0)) 32 | 33 | while heap: 34 | val, row, col = heapq.heappop(heap) 35 | result.append(val) 36 | if col + 1 < len(arrays[row]): 37 | heapq.heappush(heap, (arrays[row][col + 1], row, col + 1)) 38 | 39 | return result 40 | 41 | ''' 42 | 算法武器: heap 43 | 44 | 这道题和把k个有序链表合并的思路一样的。都是使用heap,将每个数组的首元素加入heap,然后每次从heap中弹出的元素, 45 | 装入堆的是一个三元组:(元素值,元素在arrays中所在的row, 元素在arrays.col) 46 | 元组第一个分量用于堆排序依据和结果输出,第二个、第三个元素分量用于寻找下一个进入堆的元素的位置。 47 | 每次将元素入堆的时候都要判断元素是否在数组中存在。 48 | ''' -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/495. Implement Stack.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Implement a stack. You can use any data structure inside a stack except stack itself to implement it. 3 | 4 | Example 5 | push(1) 6 | pop() 7 | push(2) 8 | top() // return 2 9 | pop() 10 | isEmpty() // return true 11 | push(3) 12 | isEmpty() // return false 13 | ''' 14 | class Stack: 15 | """ 16 | @param: x: An integer 17 | @return: nothing 18 | """ 19 | def push(self, x): 20 | # write your code here 21 | 22 | """ 23 | @return: nothing 24 | """ 25 | def pop(self): 26 | # write your code here 27 | 28 | """ 29 | @return: An integer 30 | """ 31 | def top(self): 32 | # write your code here 33 | 34 | """ 35 | @return: True if the stack is empty 36 | """ 37 | def isEmpty(self): 38 | # write your code here 39 | -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/540. Zigzag Iterator.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given two 1d vectors, implement an iterator to return their elements alternately. 3 | 4 | Example 5 | Given two 1d vectors: 6 | 7 | v1 = [1, 2] 8 | v2 = [3, 4, 5, 6] 9 | By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1, 3, 2, 4, 5, 6]. 10 | ''' 11 | class ZigzagIterator: 12 | 13 | # @param {int[]} v1 v2 two 1d vectors 14 | def __init__(self, v1, v2): 15 | # initialize your data structure here 16 | self.queue = [v for v in (v1, v2) if v] 17 | # self.stack = [v1, v2] 18 | 19 | def next(self): 20 | v = self.queue.pop(0) 21 | value = v.pop(0) 22 | if v: 23 | self.queue.append(v) 24 | return value 25 | 26 | 27 | def hasNext(self): 28 | # Write your code here 29 | return len(self.queue) > 0 30 | 31 | 32 | # Your ZigzagIterator object will be instantiated and called as such: 33 | # solution, result = ZigzagIterator(v1, v2), [] 34 | # while solution.hasNext(): result.append(solution.next()) 35 | # Output result 36 | 37 | ''' 38 | 算法武器: stack 39 | 40 | 本题有交替输出的需求,交替是改变输出顺序,对于顺序有影响的数据结构我们可以想到栈stack或者queue. 本题使用queue来进行求解。 41 | 42 | 我们可以想象list v1和v2在同一队列中,然后分别出队输出一个元素,再把自己(v1或者v2)放入队中,这样就实现了交替。 43 | 44 | 因为我们是用python的list []来模拟queue,所以我们使用了以下api,对于list v 45 | 46 | v.pop(0)表示出队,发生在list的首部 47 | v.append(item)表示元素入队,发生在list的尾部 48 | 注意初始化部分,我们不想让空list也加入队中,所以我们做了条件限制 49 | 50 | self.queue = [v for v in (v1, v2) if v] 51 | ''' -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/544. Top k Largest Numbers.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an integer array, find the top k largest numbers in it. 3 | 4 | Example 5 | Given [3,10,1000,-99,4,100] and k = 3. 6 | Return [1000, 100, 10]. 7 | ''' 8 | import heapq 9 | 10 | class Solution: 11 | ''' 12 | @param {int[]} nums an integer array 13 | @param {int} k an integer 14 | @return {int[]} the top k largest numbers in array 15 | ''' 16 | 17 | def topk(self, nums, k): 18 | heapq.heapify(nums) 19 | topk = heapq.nlargest(k, nums) 20 | topk.sort() 21 | topk.reverse() 22 | return topk 23 | ''' 24 | 算法武器: heap 25 | 26 | 构建堆结构,直接调api 27 | 堆中元素全局不是有序的,所以得sort一下,然后reverse输出,大数在先 28 | ''' -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/545. Top k Largest Numbers II.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Implement a data structure, provide two interfaces: 3 | 4 | add(number). Add a new number in the data structure. 5 | topk(). Return the top k largest numbers in this data structure. k is given when we create the data structure. 6 | Example 7 | s = new Solution(3); 8 | >> create a new data structure. 9 | s.add(3) 10 | s.add(10) 11 | s.topk() 12 | >> return [10, 3] 13 | s.add(1000) 14 | s.add(-99) 15 | s.topk() 16 | >> return [1000, 10, 3] 17 | s.add(4) 18 | s.topk() 19 | >> return [1000, 10, 4] 20 | s.add(100) 21 | s.topk() 22 | >> return [1000, 100, 10] 23 | ''' 24 | import heapq 25 | 26 | class Solution: 27 | 28 | # @param {int} k an integer 29 | def __init__(self, k): 30 | self.k = k 31 | self.nums = [] 32 | heapq.heapify(self.nums) 33 | 34 | # @param {int} num an integer 35 | def add(self, num): 36 | if len(self.nums) < self.k: 37 | heapq.heappush(self.nums, num) 38 | elif num > self.nums[0]: 39 | heapq.heappop(self.nums) 40 | heapq.heappush(self.nums, num) 41 | 42 | # @return {int[]} the top k largest numbers in array 43 | def topk(self): 44 | return sorted(self.nums, reverse=True) 45 | ''' 46 | 算法武器:固定size的heap 47 | 48 | 求前k大/小的问题都要用到堆,同时本题还限定堆的尺寸,不能超过k。 49 | 求top k大的数,那么我们就维护一个最小堆,这样堆满的情况下,我们总是可以淘汰对顶元素,因为它是最小的,然后加入新的元素(前提:这个加入的元素比对顶元素大,这样我们才会淘汰堆顶) 50 | ''' -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/601. Flatten 2D Vector.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Implement an iterator to flatten a 2d vector. 3 | 4 | Example 5 | Given 2d vector = 6 | 7 | [ 8 | [1,2], 9 | [3], 10 | [4,5,6] 11 | ] 12 | By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,2,3,4,5,6]. 13 | ''' 14 | class Vector2D(object): 15 | 16 | # @param vec2d {List[List[int]]} 17 | def __init__(self, vec2d): 18 | # Initialize your data structure here 19 | self.row, self.col, self.vec2d = 0, -1, vec2d 20 | 21 | 22 | # @return {int} a next element 23 | def next(self): 24 | # Write your code here 25 | # self.col += 1 26 | return self.vec2d[self.row][self.col] 27 | 28 | 29 | # @return {boolean} true if it has next element 30 | # or false 31 | def hasNext(self): 32 | # Write your code here 33 | self.col += 1 34 | while self.row < len(self.vec2d) and \ 35 | self.col >= len(self.vec2d[self.row]): 36 | self.row, self.col = self.row + 1, 0 37 | return self.row < len(self.vec2d) 38 | ''' 39 | 算法武器: 数组 + 基础编程能力 40 | 41 | hasNext: 不仅检查是否还有下一个元素,同时移动row和col,使之指向下一个元素的位置。 42 | 数据矩阵中可能有很多空行,hasNext需要把这些空行都跳过,让row和col指向下一个元素的位置 43 | 注意:client在调用next时总是首先调用hasNext方法 44 | 45 | 本题难点: 46 | 47 | iterator重点在于控制游标,对于二维情况就是指row,col 48 | hasNext方法不仅检测是否有下一个元素,同时移动游标指向下一个元素 49 | 考虑到边界条件:一个数据矩阵中的行数据可能是空的,并且可能存在多个空行,那么在移动游标时就需要跳过这些空行 50 | ''' -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/606. Kth Largest Element II.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Find K-th largest element in an array. and N is much larger than k. 3 | 4 | Example 5 | In array [9,3,2,4,8], the 3rd largest element is 4. 6 | 7 | In array [1,2,3,4,5], the 1st largest element is 5, 2nd largest element is 4, 3rd largest element is 3 and etc. 8 | ''' 9 | class Solution: 10 | # @param nums {int[]} an integer unsorted array 11 | # @param k {int} an integer from 1 to n 12 | # @return {int} the kth largest element 13 | 14 | 15 | def kthLargestElement2(self, nums, k): 16 | # Write your code here 17 | import heapq 18 | heap = [] 19 | 20 | 21 | for num in nums: 22 | heapq.heappush(heap, num) 23 | if len(heap) > k: 24 | heapq.heappop(heap) 25 | 26 | return heapq.heappop(heap) 27 | ''' 28 | 算法武器: heap 29 | 30 | 本题意图实在考堆 31 | 相求第k大元素,那么就把数组中元素全部入堆,维持一个size为k的最小堆,该堆pop一下即是第k大元素 32 | 之所以维持最小堆的原因是我们堆的size为k,当堆的元素个数大于k时,我们就需要移除一个,这个时候我们希望移除最小的一个,所以我们使用最小堆 33 | 34 | 堆构建完成之后,堆中的元素是k个最大元素 35 | 由于是小根堆,所以堆顶元素就是第k大元素 36 | 每当加入一个元素,堆的size改变的时候就检查一下,如果堆中元素超过k时,将最小元素出堆 37 | ''' -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/613. High Five.py: -------------------------------------------------------------------------------- 1 | ''' 2 | There are two properties in the node student id and scores, to ensure that each student will have at least 5 points, find the average of 5 highest scores for each person. 3 | 4 | Example 5 | Given results = [[1,91],[1,92],[2,93],[2,99],[2,98],[2,97],[1,60],[1,58],[2,100],[1,61]] 6 | 7 | Return 8 | ''' 9 | ''' 10 | Definition for a Record 11 | class Record: 12 | def __init__(self, id, score): 13 | self.id = id 14 | self.score = score 15 | ''' 16 | import heapq 17 | class Solution: 18 | # @param {Record[]} results a list of 19 | # @return {dict(id, average)} find the average of 5 highest scores for each person 20 | # (student_id, average_score) 21 | def highFive(self, results): 22 | # Write your code here 23 | hash = dict() 24 | for r in results: 25 | if r.id not in hash: 26 | hash[r.id] = [] 27 | 28 | heapq.heappush(hash[r.id], r.score) 29 | if len(hash[r.id]) > 5: 30 | heapq.heappop(hash[r.id]) 31 | 32 | # answer = dict() 33 | for id, scores in hash.items(): 34 | hash[id] = sum(scores) / 5.0 35 | 36 | return hash 37 | ''' 38 | 算法武器:hash + heap 39 | 40 | 本题考查哈希表的使用方法 41 | 哈希表键值为id,值为成绩数组 42 | 最后遍历这个哈希表,利用成绩数组,计算成绩均值 43 | 44 | 学会遍历哈希表的键值队,使用hash.items()这个函数 45 | ''' -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/642. Moving Average from Data Stream.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a stream of integers and a window size, calculate the moving average of all integers in the sliding window. 3 | 4 | Example 5 | MovingAverage m = new MovingAverage(3); 6 | m.next(1) = 1 // return 1.00000 7 | m.next(10) = (1 + 10) / 2 // return 5.50000 8 | m.next(3) = (1 + 10 + 3) / 3 // return 4.66667 9 | m.next(5) = (10 + 3 + 5) / 3 // return 6.00000 10 | ''' 11 | class MovingAverage(object): 12 | 13 | def __init__(self, size): 14 | # Initialize your data structure here. 15 | from Queue import Queue 16 | self.queue = Queue() 17 | # window size 18 | self.size = size 19 | # maintain window sum 20 | self.sum = 0.0 21 | 22 | 23 | # @param {int} val an teger 24 | def next(self, val): 25 | # Write your code here 26 | self.sum += val 27 | if self.queue.qsize() == self.size: 28 | self.sum -= self.queue.get() 29 | self.queue.put(val) 30 | return self.sum * 1.0 / self.queue.qsize() 31 | 32 | 33 | 34 | # Your MovingAverage object will be instantiated and called as such: 35 | # obj = MovingAverage(size) 36 | # param = obj.next(val) 37 | 38 | ''' 39 | 求滑动平均问题不难,使用window sum的方式很容求解。 40 | 41 | 对比求滑动最大值、最小值,相对来说就复杂多了,因为我们需要维持两个堆(一个最大堆和最小堆) 42 | ''' -------------------------------------------------------------------------------- /ladder_basic/8_datastructure_stack_queue_hash_heap/685. First Unique Number In Stream.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a continuous stream of numbers, write a function that returns the first unique number whenever terminating number is reached(include terminating number). If there no unique number before terminating number or you can't find this terminating number, return -1. 3 | 4 | Example 5 | Given a stream [1, 2, 2, 1, 3, 4, 4, 5, 6] and a number 5 6 | return 3 7 | 8 | Given a stream [1, 2, 2, 1, 3, 4, 4, 5, 6] and a number 7 9 | return -1 10 | ''' 11 | class Solution: 12 | """ 13 | @param nums: a continuous stream of numbers 14 | @param number: a number 15 | @return: returns the first unique number 16 | """ 17 | def firstUniqueNumber(self, nums, number): 18 | # Write your code here 19 | -------------------------------------------------------------------------------- /lecture_advanced/Lecture1.HotFollowupQuestions/32. Minimum Window Substring.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a string source and a string target, find the minimum window in source which will contain all the characters in target. 3 | 4 | Example 5 | For source = "ADOBECODEBANC", target = "ABC", the minimum window is "BANC" 6 | 7 | Challenge 8 | Can you do it in time complexity O(n) ? 9 | ''' 10 | from collections import defaultdict 11 | 12 | class Solution: 13 | def minWindow(self, source, target): 14 | if source is None or target is None: 15 | return None 16 | 17 | if not source or not target: 18 | return "" 19 | 20 | start, end = 0, 0 21 | minimumLength, windowSubstring = sys.maxsize, "" 22 | sourceHashmap, targetHashmap = defaultdict(int), defaultdict(int) 23 | 24 | for ch in target: 25 | targetHashmap[ch] += 1 26 | 27 | for start in range(len(source)): 28 | while end < len(source) and not self.isSourceHashMapContainsTarget(sourceHashmap, targetHashmap): 29 | sourceHashmap[source[end]] += 1 30 | end += 1 31 | 32 | if self.isSourceHashMapContainsTarget(sourceHashmap, targetHashmap) and end - start < minimumLength: 33 | minimumLength = end - start 34 | windowSubstring = source[start:end] 35 | 36 | sourceHashmap[source[start]] -= 1 37 | if sourceHashmap[source[start]] == 0: 38 | del sourceHashmap[source[start]] 39 | 40 | return windowSubstring -------------------------------------------------------------------------------- /lecture_advanced/Lecture1.HotFollowupQuestions/406. Minimum Size Subarray Sum.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array of n positive integers and a positive integer s, find the minimal length of a subarray of which the sum ≥ s. If there isn't one, return -1 instead. 3 | 4 | Example 5 | Given the array [2,3,1,2,4,3] and s = 7, the subarray [4,3] has the minimal length under the problem constraint. 6 | 7 | Challenge 8 | If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log n). 9 | ''' 10 | class Solution: 11 | def minimumSize(self, nums, s): 12 | if not nums: 13 | return -1 14 | 15 | start, end = 0, 0 16 | length, sum, result = len(nums), 0, sys.maxsize 17 | 18 | for start in range(length): 19 | while end < length and sum < s: 20 | sum += nums[end] 21 | end += 1 22 | 23 | if sum >= s: 24 | result = min(result, end - start) 25 | 26 | sum -= nums[start] 27 | 28 | if result == sys.maxsize: 29 | return -1 30 | 31 | return result 32 | 33 | ''' 34 | 算法武器:双指针(不回溯) 35 | 本题的类型是窗口类 + 窗口尺寸不固定+双指针移动型 36 | 思路: 37 | 38 | start变量用于代表窗口的起点,其值可以在[0, n- 1] 39 | end变量代表窗口的终点,在for循环中我们使用while来尝试寻找相对于起点为start的end的位置 40 | while循环中的条件包括对end的边界约束以及根据题目的要求的约束(本题中这个约束为子数组的和>=s) 41 | 在while循环中,我们先找右指针的位置,再找左指针的可能位置,并且不断更新解 42 | 循环跳出时我们需要对条件做检测,如果符合本题条件我们就更新解 43 | 更新窗口和,然后start指针随着for循环自动加1 44 | 本题的算法复杂度为O(n),因为所有元素都只被访问了2次(i一次,j一次) 45 | 虽然是嵌套的两个循环,但是因为两个指针都是一直向前走,没有回溯,所以时间复杂度可以维持在O(n) 46 | ''' -------------------------------------------------------------------------------- /lecture_advanced/Lecture1.HotFollowupQuestions/543. Kth Largest in N Arrays.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Find K-th largest element in N arrays. 3 | 4 | Example 5 | In n=2 arrays [[9,3,2,4,7],[1,2,3,4,8]], the 3rd largest element is 7. 6 | 7 | In n=2 arrays [[9,3,2,4,8],[1,2,3,4,2]], the 1st largest element is 9, 2nd largest element is 8, 3rd largest element is 7 and etc. 8 | ''' 9 | import heapq 10 | 11 | class Solution: 12 | def KthInArrays(self, arrays, k): 13 | if not arrays or k < 1: 14 | raise Exception("Invalid parameter!") 15 | 16 | heap = [] 17 | for arr in arrays: 18 | for ele in arr: 19 | heapq.heappush(heap, ele) 20 | if len(heap) > k: 21 | heapq.heappop(heap) 22 | 23 | return heap[0] 24 | 25 | ''' 26 | 算法武器:堆 27 | 第k大元问题,还是一下子就要想到用堆,维护一个size为k的最小堆。因为本题数组没有排序,所以我们必须要用两个for循环将所有元素一次放入堆中。 28 | 29 | 放入元素的时候要注意: 30 | 31 | 对于每一个遍历到的元素直接放入 32 | 放置完元素之后检查尺寸,如果已经满尺寸k,则需要pop一个元素出去。因为我们建立的是小根堆,所以最小的元素会被淘汰。 33 | 当所有元素遍历完之后,堆中存放的元素就是最大的k个元素,我们要求的最大的k个元素就是堆顶元素 34 | 注意元素不断流入小根堆(尺寸为k)中,最终我们可以获得最大的k个元素。因为小根堆总是不断淘汰最小的元素 35 | 36 | 同理,如果元素不断流入尺寸为k的大根堆中,最终我们获得的是最小的k个元素,因为大根堆总是淘汰最大元素 37 | 38 | 所以以后根据题意,如果求第k大元,我们就建立维护k的小根堆 39 | 如果求第k小元,我们就建立维护k的大根堆 40 | 41 | 怎么建立大根堆? 42 | 43 | 只要将放入堆中的元素取反就行 44 | ''' -------------------------------------------------------------------------------- /lecture_advanced/Lecture2.DataStructure1/589. Connecting Graph.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given n nodes in a graph labeled from 1 to n. There is no edges in the graph at beginning. 3 | 4 | You need to support the following method: 5 | 6 | connect(a, b), add an edge to connect node a and node b`. 7 | query(a, b), check if two nodes are connected 8 | Example 9 | 5 // n = 5 10 | query(1, 2) return false 11 | connect(1, 2) 12 | query(1, 3) return false 13 | connect(2, 4) 14 | query(1, 4) return true 15 | ''' 16 | class ConnectingGraph: 17 | def __init__(self, n): 18 | self.father = [ i for i in range(n + 1)] 19 | 20 | def find(self, x): 21 | if self.father[x] == x: 22 | return x 23 | 24 | self.father[x] = self.find(self.father[x]) 25 | return self.father[x] 26 | 27 | def connect(self, a, b): 28 | fathera = self.find(a) 29 | fatherb = self.find(b) 30 | if fathera != fatherb: 31 | self.father[fatherb] = fathera 32 | 33 | def query(self, a, b): 34 | return self.find(a) == self.find(b) 35 | 36 | ''' 37 | 算法武器:并查集 38 | ''' 39 | -------------------------------------------------------------------------------- /lecture_advanced/Lecture2.DataStructure1/590. Connecting Graph II.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given n nodes in a graph labeled from 1 to n. There is no edges in the graph at beginning. 3 | 4 | You need to support the following method: 5 | 6 | connect(a, b), an edge to connect node a and node b 7 | query(a), Returns the number of connected component nodes which include node a. 8 | Example 9 | 5 // n = 5 10 | query(1) return 1 11 | connect(1, 2) 12 | query(1) return 2 13 | connect(2, 4) 14 | query(1) return 3 15 | connect(1, 4) 16 | query(1) return 3 17 | ''' 18 | class ConnectingGraph2: 19 | def __init__(self, n): 20 | self.father = [i for i in range(n + 1)] 21 | self.size = [1 for _in range(n + 1)] 22 | 23 | def find(self, x): 24 | if self.father[x] == x: 25 | return x 26 | 27 | self.father[x] = self.find(father[x]) 28 | return self.father[x] 29 | 30 | def connect(self, a, b): 31 | roota = self.find(a) 32 | rootb = self.find(b) 33 | if roota != rootb: 34 | self.father[rootb] = roota 35 | self.size[roota] += self.size[rootb] 36 | 37 | def query(self, a): 38 | roota = self.find(a) 39 | return self.size[roota] 40 | 41 | ''' 42 | 算法武器:并查集 + size数组 43 | ''' -------------------------------------------------------------------------------- /lecture_advanced/Lecture2.DataStructure1/591. Connecting Graph III.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given n nodes in a graph labeled from 1 to n. There is no edges in the graph at beginning. 3 | 4 | You need to support the following method: 5 | 6 | connect(a, b), an edge to connect node a and node b 7 | query(), Returns the number of connected component in the graph 8 | Example 9 | 5 // n = 5 10 | query() return 5 11 | connect(1, 2) 12 | query() return 4 13 | connect(2, 4) 14 | query() return 3 15 | connect(1, 4) 16 | query() return 3 17 | ''' 18 | class ConnectingGraph3: 19 | def __init__(self, n): 20 | self.father = [i for i in range(n + 1)] 21 | self.count = n 22 | 23 | def find(self, x): 24 | if self.father[x] == x: 25 | return x 26 | 27 | self.father[x] = self.find(self.father[x]) 28 | return self.father[x] 29 | 30 | def connect(self, a, b): 31 | roota = self.find(a) 32 | rootb = self.find(b) 33 | if roota != rootb!: 34 | self.father[rootb] = roota 35 | self.count -= 1 36 | 37 | def query(self): 38 | return self.count 39 | 40 | ''' 41 | 算法武器:并查集 + 成员变量count(维护联通块的个数) 42 | 43 | 注意: 44 | 45 | connect方法在调用时,只有在root_a != root_b的情况下才进行合并,才会修改self.count。 46 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture2.Binary_Search/14. First Position of Target.py: -------------------------------------------------------------------------------- 1 | ''' 2 | For a given sorted array (ascending order) and a target number, find the first index of this number in O(log n) time complexity. 3 | 4 | If the target number does not exist in the array, return -1. 5 | 6 | Example 7 | If the array is [1, 2, 3, 3, 4, 5, 10], for given target 3, return 2. 8 | 9 | Challenge 10 | If the count of numbers is bigger than 2^32, can your code work properly? 11 | ''' 12 | class Solution: 13 | def binarySearch(self, nums, target): 14 | if not nums: 15 | return -1 16 | 17 | start, end = 0, len(nums) - 1 18 | while start + 1 < end: 19 | mid = start + (end - start) // 2 20 | if nums[mid] >= target: 21 | end = mid 22 | else: 23 | start = mid 24 | 25 | if nums[start] == target: 26 | return start 27 | 28 | if nums[end] == target: 29 | return end 30 | 31 | return -1 -------------------------------------------------------------------------------- /lecture_basic/Lecture2.Binary_Search/141. Sqrt(x).py: -------------------------------------------------------------------------------- 1 | ''' 2 | Implement int sqrt(int x). 3 | 4 | Compute and return the square root of x. 5 | 6 | Example 7 | sqrt(3) = 1 8 | 9 | sqrt(4) = 2 10 | 11 | sqrt(5) = 2 12 | 13 | sqrt(10) = 3 14 | 15 | Challenge 16 | O(log(x)) 17 | ''' 18 | class Solution: 19 | def sqrt(self, x): 20 | start, end = 0, x 21 | while start + 1 < end: 22 | mid = start + (end - start) // 2 23 | if mid ** 2 == x: 24 | return mid 25 | elif mid ** 2 < x: 26 | start = id 27 | else: 28 | end = mid 29 | 30 | if end ** 2 <= x: 31 | return end 32 | 33 | return start 34 | -------------------------------------------------------------------------------- /lecture_basic/Lecture2.Binary_Search/159. Find Minimum in Rotated Sorted Array.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Suppose a sorted array is rotated at some pivot unknown to you beforehand. 3 | 4 | (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). 5 | 6 | Find the minimum element. 7 | 8 | Example 9 | Given [4, 5, 6, 7, 0, 1, 2] return 0 10 | ''' 11 | class Solution: 12 | def findMin(self, nums): 13 | if not nums: 14 | return -1 15 | 16 | start, end = 0, len(nums) - 1 17 | target = nums[-1] 18 | 19 | while start + 1 < end: 20 | mid = start + (end - start) // 2 21 | if nums[mid] >= target: 22 | start = mid 23 | else: 24 | end = mid 25 | 26 | # 注意:最后结果返回时我们取最小的那个 27 | return min(nums[start], nums[end]) -------------------------------------------------------------------------------- /lecture_basic/Lecture2.Binary_Search/183. Wood Cut.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given n pieces of wood with length L[i] (integer array). Cut them into small pieces to guarantee you could have equal or more than k pieces with the same length. What is the longest length you can get from the n pieces of wood? Given L & k, return the maximum length of the small pieces. 3 | 4 | Example 5 | For L=[232, 124, 456], k=7, return 114. 6 | 7 | Challenge 8 | O(n log Len), where Len is the longest length of the wood. 9 | ''' 10 | class Solution: 11 | def woodCut(self, L, k): 12 | if not L or k < 0: 13 | return 0 14 | 15 | start, end = 1, max(L) 16 | while start + 1 < end: 17 | mid = start + (end - start) // 2 18 | if self.calculatePieces(L, mid) >= k: 19 | start = mid 20 | else: 21 | end = mid 22 | 23 | if self.calculatePieces(L, end) >= k: 24 | return end 25 | 26 | if self.calculatePieces(L, start) >= k: 27 | return start 28 | 29 | return 0 30 | 31 | 32 | def calculatePieces(self, L, pieceLenght): 33 | if not L: 34 | return 0 35 | 36 | return sum(map(lambda x: x // pieceLenght, L)) 37 | -------------------------------------------------------------------------------- /lecture_basic/Lecture2.Binary_Search/28. Search a 2D Matrix.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write an efficient algorithm that searches for a value in an m x n matrix. 3 | 4 | This matrix has the following properties: 5 | 6 | Integers in each row are sorted from left to right. 7 | The first integer of each row is greater than the last integer of the previous row. 8 | Example 9 | Consider the following matrix: 10 | 11 | [ 12 | [1, 3, 5, 7], 13 | [10, 11, 16, 20], 14 | [23, 30, 34, 50] 15 | ] 16 | Given target = 3, return true. 17 | 18 | Challenge 19 | O(log(n) + log(m)) time 20 | ''' 21 | class Solution: 22 | def searchMatrix(self, matrix, target): 23 | if not matrix: 24 | return False 25 | 26 | m, n = len(matrix), len(matrix[0]) 27 | start, end = 0, m * n - 1 28 | 29 | while start + 1 < end: 30 | mid = start + (end - start) // 2 31 | x, y = mid // n, mid % n 32 | if matrix[x][y] == target: 33 | return True 34 | elif matrix[x][y] > target: 35 | end = mid 36 | else: 37 | start = mid 38 | 39 | if matrix[start // n][start % n] == target: 40 | return True 41 | if matrix[end // n][end % n] = target: 42 | return True 43 | 44 | return False -------------------------------------------------------------------------------- /lecture_basic/Lecture2.Binary_Search/39. Recover Rotated Sorted Array.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a rotated sorted array, recover it to sorted array in-place. 3 | 4 | Example 5 | [4, 5, 1, 2, 3] -> [1, 2, 3, 4, 5] 6 | 7 | Challenge 8 | In-place, O(1) extra space and O(n) time. 9 | ''' 10 | class Solution: 11 | def recoverRotateSortedArray(self, nums): 12 | if len(nums) < 2: 13 | return nums 14 | 15 | for index in range(len(nums) - 1): 16 | if nums[index] > nums[index + 1]: 17 | self.reverse(nums, 0, index) 18 | self.reverse(nums, index + 1, len(nums) - 1) 19 | self.reverse(nums, 0, len(nums) - 1) 20 | 21 | def reverse(self, nums, start, end): 22 | if len(nums) < 2: 23 | return nums 24 | 25 | while start < end: 26 | nums[start], nums[end] = nums[end], nums[start] 27 | start += 1 28 | end -= 1 -------------------------------------------------------------------------------- /lecture_basic/Lecture2.Binary_Search/447. Search in a Big Sorted Array.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a big sorted array with positive integers sorted by ascending order. The array is so big so that you can not get the length of the whole array directly, and you can only access the kth number by ArrayReader.get(k) (or ArrayReader->get(k) for C++). Find the first index of a target number. Your algorithm should be in O(log k), where k is the first index of the target number. 3 | 4 | Return -1, if the number doesn't exist in the array. 5 | 6 | Example 7 | Given [1, 3, 6, 9, 21, ...], and target = 3, return 1. 8 | 9 | Given [1, 3, 6, 9, 21, ...], and target = 4, return -1. 10 | 11 | Challenge 12 | O(log k), k is the first index of the given target number. 13 | ''' 14 | class Solution: 15 | def searchBigSortedArray(self, reader, target): 16 | if not reader: 17 | raise Exception('Invalid parameter!') 18 | 19 | index = 1 20 | while reader.get(index) < target: 21 | index *= 2 22 | 23 | start, end = index // 2, index 24 | while start + 1 < end: 25 | mid = start + (end - start) // 2 26 | if reader.get(mid) >= target: 27 | end = mid 28 | else: 29 | start = mid 30 | 31 | if reader.get(start) == target: 32 | return start 33 | 34 | if reader.get(end) == target: 35 | return end 36 | 37 | return -1 -------------------------------------------------------------------------------- /lecture_basic/Lecture2.Binary_Search/457. Classical Binary Search.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Find any position of a target number in a sorted array. Return -1 if target does not exist. 3 | 4 | Example 5 | Given [1, 2, 2, 4, 5, 5]. 6 | 7 | For target = 2, return 1 or 2. 8 | 9 | For target = 5, return 4 or 5. 10 | 11 | For target = 6, return -1. 12 | 13 | Challenge 14 | O(logn) time 15 | ''' 16 | class Solution: 17 | def findPosition(self, A, target): 18 | if not A: 19 | return -1 20 | 21 | start, end = 0, len(A) - 1 22 | 23 | while start + 1 < end: 24 | mid = start + (end - start) // 2 25 | if A[mid] == target: 26 | return mid 27 | elif A[mid] < target: 28 | start = mid 29 | else: 30 | end = mid 31 | 32 | if A[start] == target: 33 | return A[start] 34 | 35 | if A[end] == target: 36 | return A[end] 37 | 38 | return -1 -------------------------------------------------------------------------------- /lecture_basic/Lecture2.Binary_Search/458. Last Position of Target.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Find the last position of a target number in a sorted array. Return -1 if target does not exist. 3 | 4 | Example 5 | Given [1, 2, 2, 4, 5, 5]. 6 | 7 | For target = 2, return 2. 8 | 9 | For target = 5, return 5. 10 | 11 | For target = 6, return -1. 12 | ''' 13 | class Solution: 14 | def lastPosition(self, A, target): 15 | if not A or not target: 16 | return -1 17 | 18 | start, end = 0, len(A) - 1 19 | 20 | while start + 1 < end: 21 | mid = start + (end - start) // 2 22 | if A[mid] <= target: 23 | start = mid 24 | else: 25 | end = mid 26 | 27 | if A[end] == target: 28 | return end 29 | 30 | if A[start] == target: 31 | return start 32 | 33 | return -1 -------------------------------------------------------------------------------- /lecture_basic/Lecture2.Binary_Search/60. Search Insert Position.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order. 3 | 4 | You may assume NO duplicates in the array. 5 | 6 | Example 7 | [1,3,5,6], 5 → 2 8 | 9 | [1,3,5,6], 2 → 1 10 | 11 | [1,3,5,6], 7 → 4 12 | 13 | [1,3,5,6], 0 → 0 14 | 15 | Challenge 16 | O(log(n)) time 17 | ''' 18 | class Solution: 19 | def searchInsert(self, A, target): 20 | if not A or A[0] >= target: 21 | return 0 22 | 23 | if A[-1] < target: 24 | return len(A) 25 | 26 | start, end = 0, len(A) - 1 27 | 28 | while start + 1 < end: 29 | mid = start + (end - start) // 2 30 | if A[mid] >= target: 31 | end = mid 32 | else: 33 | start = mid 34 | 35 | if A[start] >= target: 36 | return start 37 | 38 | return end 39 | -------------------------------------------------------------------------------- /lecture_basic/Lecture2.Binary_Search/62. Search in Rotated Sorted Array.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Suppose a sorted array is rotated at some pivot unknown to you beforehand. 3 | 4 | (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). 5 | 6 | You are given a target value to search. If found in the array return its index, otherwise return -1. 7 | 8 | You may assume no duplicate exists in the array. 9 | 10 | Example 11 | For [4, 5, 1, 2, 3] and target=1, return 2. 12 | 13 | For [4, 5, 1, 2, 3] and target=0, return -1. 14 | 15 | Challenge 16 | O(logN) time 17 | ''' 18 | class Solution: 19 | def search(self, A, target): 20 | if not A: 21 | return -1 22 | 23 | start, end = 0, len(A) - 1 24 | while start + 1 < end: 25 | mid = start + (end - start) // 2 26 | if A[mid] == target: 27 | return mid 28 | 29 | # 通过start和mid处元素的值,我们推知我们的mid中线处在哪个图形段中(如果画图可以看到有两端) 30 | if A[start] < A[mid]: 31 | # 我们我们确定target在start和mid之间,我们则可以放心地更新end 32 | if A[start] <= target <= A[mid]: 33 | end = mid 34 | # 否则我们排除start左边的解空间 35 | else: 36 | start = mid 37 | else: 38 | if A[mid] <= target <= A[end]: 39 | start = mid 40 | else: 41 | end = mid 42 | 43 | if A[start] == target: 44 | return start 45 | 46 | if A[end] == target: 47 | return end 48 | 49 | return -1 -------------------------------------------------------------------------------- /lecture_basic/Lecture2.Binary_Search/75. Find Peak Element.py: -------------------------------------------------------------------------------- 1 | ''' 2 | There is an integer array which has the following features: 3 | 4 | The numbers in adjacent positions are different. 5 | A[0] < A[1] && A[A.length - 2] > A[A.length - 1]. 6 | We define a position P is a peak if: 7 | 8 | A[P] > A[P-1] && A[P] > A[P+1] 9 | Find a peak element in this array. Return the index of the peak. 10 | 11 | Example 12 | Given [1, 2, 1, 3, 4, 5, 7, 6] 13 | 14 | Return index 1 (which is number 2) or 6 (which is number 7) 15 | 16 | Challenge 17 | Time complexity O(logN) 18 | ''' 19 | class Solution: 20 | def findPeak(self, A): 21 | if not A or len(A) < 3: 22 | return 0 23 | 24 | start, end = 1, len(A) - 2 25 | while start + 1 < end: 26 | mid = start + (end - start) // 2 27 | if A[mid] < A[mid - 1]: 28 | end = mid 29 | elif A[mid] < A[mid + 1]: 30 | start = mid 31 | elif A[mid] > A[mid - 1] and A[mid] > A[mid + 1]: 32 | return mid 33 | 34 | return end if A[start] < A[end] else start -------------------------------------------------------------------------------- /lecture_basic/Lecture3.Binary_Tree__Divide_Conquer/448. Inorder Successor in BST.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a binary search tree and a node in it, find the in-order successor of that node in the BST. 3 | 4 | If the given node has no in-order successor in the tree, return null. 5 | 6 | Example 7 | Given tree = [2,1] and node = 1: 8 | 9 | 2 10 | / 11 | 1 12 | return node 2. 13 | 14 | Given tree = [2,1,3] and node = 2: 15 | 16 | 2 17 | / \ 18 | 1 3 19 | return node 3. 20 | 21 | Challenge 22 | O(h), where h is the height of the BST. 23 | ''' 24 | class Solution: 25 | def inorderSuccessor(self, root, p): 26 | if root is None or p is None: 27 | return None 28 | 29 | curt, successor = root, None 30 | 31 | # 注意:我们在查找p元素的同时,我们记录successor(当我们向左走的时候) 32 | while curt and curt.val != p.val: 33 | if curt.val > p.val: 34 | successor = curt 35 | curt = curt.left 36 | else: 37 | curt = curt.right 38 | 39 | if curt is None: 40 | return None 41 | 42 | # 如果右子树不存在,那么前驱节点一定是successor所指节点 43 | if curt.right is None: 44 | return successor 45 | 46 | # 如果右子树存在,我们需要走到右子树的最左 47 | curt = curt.right 48 | while curt.left: 49 | curt = curt.left 50 | 51 | return curt -------------------------------------------------------------------------------- /lecture_basic/Lecture3.Binary_Tree__Divide_Conquer/475. Binary Tree Maximum Path Sum II.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a binary tree, find the maximum path sum from root. 3 | 4 | The path may end at any node in the tree and contain at least one node in it. 5 | 6 | Example 7 | Given the below binary tree: 8 | 9 | 1 10 | / \ 11 | 2 3 12 | return 4. (1->3) 13 | ''' 14 | class Solution: 15 | def maxPathSum2(self, root): 16 | if root is None: 17 | return 0 18 | 19 | # divide 20 | leftSum = self.maxPathSum2(root.left) 21 | rightSum = self.maxPathSum2(root.right) 22 | 23 | # conquer 24 | return max(leftSum, rightSum, 0) + root.val 25 | -------------------------------------------------------------------------------- /lecture_basic/Lecture3.Binary_Tree__Divide_Conquer/66. Binary Tree Preorder Traversal.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a binary tree, return the preorder traversal of its nodes' values. 3 | 4 | Example 5 | Given: 6 | 7 | 1 8 | / \ 9 | 2 3 10 | / \ 11 | 4 5 12 | return [1,2,4,5,3]. 13 | ''' 14 | class Solution: 15 | def preorderTraversal(self, root): 16 | if root is None: 17 | return [] 18 | 19 | stack = [] 20 | preorder = [] 21 | 22 | while stack: 23 | node = stack.pop() 24 | preorder.append(node.val) 25 | # 因为stack中的顺序是反的,所以我们如果想以根左右的方式访问,我们就必须先把右子树入栈,然后左子树入栈 26 | if node.right: 27 | stack.append(node.right) 28 | if node.left: 29 | stack.append(node.left) 30 | 31 | return preorder 32 | -------------------------------------------------------------------------------- /lecture_basic/Lecture3.Binary_Tree__Divide_Conquer/68. Binary Tree Postorder Traversal.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a binary tree, return the postorder traversal of its nodes' values. 3 | 4 | Example 5 | Given binary tree {1,#,2,3}, 6 | 7 | 1 8 | \ 9 | 2 10 | / 11 | 3 12 | 13 | 14 | return [3,2,1]. 15 | 16 | Challenge 17 | Can you do it without recursion? 18 | ''' 19 | class Solution: 20 | def postorderTraversal(self, root): 21 | result = [] 22 | self.posttraverse(root, result) 23 | return result 24 | 25 | def posttraverse(self, root, result): 26 | if not root: 27 | return 28 | 29 | self.posttraverse(root.left, result) 30 | self.posttraverse(root.right, result) 31 | result.append(root.val) -------------------------------------------------------------------------------- /lecture_basic/Lecture3.Binary_Tree__Divide_Conquer/69. Binary Tree Level Order Traversal.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level). 3 | 4 | Example 5 | Given binary tree {3,9,20,#,#,15,7}, 6 | 7 | 3 8 | / \ 9 | 9 20 10 | / \ 11 | 15 7 12 | 13 | 14 | return its level order traversal as: 15 | 16 | [ 17 | [3], 18 | [9,20], 19 | [15,7] 20 | ] 21 | Challenge 22 | Challenge 1: Using only 1 queue to implement it. 23 | 24 | Challenge 2: Use DFS algorithm to do it. 25 | ''' 26 | from collections import deque 27 | 28 | class Solution: 29 | def levelOrder(self, root): 30 | if not root: 31 | return [] 32 | 33 | result, queue = [], deque([root]) 34 | 35 | while queue: 36 | # 因为需要记录每一层结果,所以首先求出当前层的size,然后在遍历当前层元素 37 | size = len(queue) 38 | layerRes = [] 39 | for i in range(size): 40 | node = queue.popleft() 41 | layerRes.append(node) 42 | if node.left: 43 | queue.append(node.left) 44 | if node.right: 45 | queue.append(node.right) 46 | result.append(layerRes) 47 | 48 | return [map(lambda node: node.val, l) for l in result] -------------------------------------------------------------------------------- /lecture_basic/Lecture3.Binary_Tree__Divide_Conquer/70. Binary Tree Level Order Traversal II.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf to root). 3 | 4 | Example 5 | Given binary tree {3,9,20,#,#,15,7}, 6 | 7 | 3 8 | / \ 9 | 9 20 10 | / \ 11 | 15 7 12 | 13 | 14 | return its bottom-up level order traversal as: 15 | 16 | [ 17 | [15,7], 18 | [9,20], 19 | [3] 20 | ] 21 | ''' 22 | <<<<<<< HEAD 23 | ======= 24 | from collections import deque 25 | class Solution: 26 | def levelOrderButtom(self, root): 27 | if root is None: 28 | return [] 29 | 30 | result, queue = [], deque([root]) 31 | 32 | while queue: 33 | size = len(queue) 34 | levelRes = [] 35 | for i in range(size): 36 | node = queue.popleft() 37 | levelRes.append(node.val) 38 | if node.left: 39 | queue.append(node.left) 40 | if node.right: 41 | queue.append(node.right) 42 | result.append(levelRes) 43 | 44 | return list(reversed(result)) 45 | >>>>>>> 8257a656f5eb6e14c98abd41825b9e54c90cc181 46 | -------------------------------------------------------------------------------- /lecture_basic/Lecture3.Binary_Tree__Divide_Conquer/71. Binary Tree Zigzag Level Order Traversal.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between). 3 | 4 | Example 5 | Given binary tree {3,9,20,#,#,15,7}, 6 | 7 | 3 8 | / \ 9 | 9 20 10 | / \ 11 | 15 7 12 | 13 | 14 | return its zigzag level order traversal as: 15 | 16 | [ 17 | [3], 18 | [20,9], 19 | [15,7] 20 | ] 21 | ''' 22 | from collections import deque 23 | def zigzagLevelOrder(self, root): 24 | if root is None: 25 | return [] 26 | 27 | result, queue, currentLevel = [], deque([root]), 1 28 | 29 | while queue: 30 | size = len(queue) 31 | levelRes = [] 32 | for i in range(size): 33 | node = queue.popleft() 34 | levelRes.append(node.val) 35 | if node.left: 36 | queue.append(node.left) 37 | if node.right: 38 | queue.append(node.right) 39 | 40 | if currentLevel % 2 == 0: 41 | levelRes.reverse() 42 | 43 | result.append(levelRes) 44 | currentLevel += 1 45 | 46 | return result -------------------------------------------------------------------------------- /lecture_basic/Lecture3.Binary_Tree__Divide_Conquer/85. Insert Node in a Binary Search Tree.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a binary search tree and a new tree node, insert the node into the tree. You should keep the tree still be a valid binary search tree. 3 | 4 | Example 5 | Given binary search tree as follow, after Insert node 6, the tree should be: 6 | 7 | 2 2 8 | / \ / \ 9 | 1 4 --> 1 4 10 | / / \ 11 | 3 3 6 12 | Challenge 13 | Can you do it without recursion? 14 | ''' 15 | class Solution: 16 | def insertNode(self, root, node): 17 | if root is None: 18 | return node 19 | 20 | curt = root 21 | 22 | # while 的结束条件是curt == node,也就是我们把node正确插入到树中后这个条件会成立 23 | while curt != node: 24 | if node.val < curt.val: 25 | # 每当我们向左走的时候,我们需要检查是否左侧节点为空,如果为空,那么cur.left就是我们的插入位置 26 | if curt.left is None: 27 | curt.left = node 28 | # 不论cur.left是空与否,我们都需要向左走一步 29 | # 如果curt的left是空,并且我们插入了元素,那么我们向左走一步之后就会使得curt == node,这样循环就可以结束了 30 | curt = curt.left 31 | # 如果要插入的元素就在树中,那么我们直接返回 32 | elif node.val == curt.val: 33 | return curt 34 | else: 35 | if curt.right is None: 36 | curt.right = node 37 | curt = curt.right 38 | 39 | return root 40 | -------------------------------------------------------------------------------- /lecture_basic/Lecture3.Binary_Tree__Divide_Conquer/86. Binary Search Tree Iterator.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Design an iterator over a binary search tree with the following rules: 3 | 4 | Elements are visited in ascending order (i.e. an in-order traversal) 5 | next() and hasNext() queries run in O(1) time in average. 6 | Example 7 | For the following binary search tree, in-order traversal by using iterator is [1, 6, 10, 11, 12] 8 | 9 | 10 10 | / \ 11 | 1 11 12 | \ \ 13 | 6 12 14 | Challenge 15 | Extra memory usage O(h), h is the height of the tree. 16 | 17 | Super Star: Extra memory usage O(1) 18 | ''' 19 | class BSTIterator: 20 | def __init__(self, root): 21 | self.stack = [] 22 | self.curt = root 23 | 24 | # 当curt所指向的待处理子树不为空或者stack不为空,那么我们就可以继续输出下一个中序元素 25 | def hasNext(self): 26 | return self.curt or self.stack 27 | 28 | # 对于curt指向的子树,如果子树存在(cur指针不为空),那么我们就进入for循环,一直扫描到子树的最左节点 29 | def next(self): 30 | while self.curt: 31 | self.stack.append(self.curt) 32 | self.curt = self.curt.left 33 | 34 | # 不论while循环部分执行也好(curt不为空),或是不执行,我们下一个访问的元素一定保存在栈顶,所以要出栈 35 | node = self.stack.pop() 36 | # 更新self.curt指针,指向下一个待处理子树 37 | self.curt = node.right 38 | 39 | return node -------------------------------------------------------------------------------- /lecture_basic/Lecture3.Binary_Tree__Divide_Conquer/87. Remove Node in Binary Search Tree.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a root of Binary Search Tree with unique value for each node. Remove the node with given value. If there is no such a node with given value in the binary search tree, do nothing. You should keep the tree still a binary search tree after removal. 3 | 4 | Example 5 | Given binary search tree: 6 | 7 | 5 8 | / \ 9 | 3 6 10 | / \ 11 | 2 4 12 | Remove 3, you can either return: 13 | 14 | 5 15 | / \ 16 | 2 6 17 | \ 18 | 4 19 | or 20 | 21 | 5 22 | / \ 23 | 4 6 24 | / 25 | 2 26 | ''' 27 | class Solution: 28 | def removeNode(self, root, value): 29 | self.ans = [] 30 | self.inorder(root, value) 31 | return self.build(0, len(self.ans) - 1) 32 | 33 | def inorder(self, root.left, value): 34 | if root is None: 35 | return 36 | 37 | self.inroder(root.left, value) 38 | # 中序遍历的时候过滤我们要删除的元素 39 | if root.val != value: 40 | self.ans.append(root.val) 41 | self.inorder(root.right, value 42 | 43 | # 以分治的方式,递归构建BST 44 | def build(self, l, r): 45 | if l == r: 46 | return TreeNode(self.ans[l]) 47 | 48 | if l > r: 49 | return None 50 | 51 | mid = (l + r) // 2 52 | root = TreeNode(self.ans[mid]) 53 | root.left = self.build(l, mid - 1) 54 | root.right = self.build(mid + 1, r) 55 | 56 | return root -------------------------------------------------------------------------------- /lecture_basic/Lecture3.Binary_Tree__Divide_Conquer/88. Lowest Common Ancestor of a Binary Tree.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given the root and two nodes in a Binary Tree. Find the lowest common ancestor(LCA) of the two nodes. 3 | 4 | The lowest common ancestor is the node with largest depth which is the ancestor of both nodes. 5 | 6 | Example 7 | For the following binary tree: 8 | 9 | 4 10 | / \ 11 | 3 7 12 | / \ 13 | 5 6 14 | LCA(3, 5) = 4 15 | 16 | LCA(5, 6) = 7 17 | 18 | LCA(6, 7) = 7 19 | ''' 20 | class Solutioin: 21 | # 注意本题已经规定给定的节点A和B一定是在树中 22 | def lowestCommonAncestor(self, root, A, B): 23 | if root is None: 24 | return None 25 | 26 | if root == A or root == B: 27 | return root 28 | 29 | leftLCA = self.lowestCommonAncestor(root.left, A, B) 30 | rightLCA = self.lowestCommonAncestor(root.right, A, B) 31 | 32 | if leftLCA and rightLCA: 33 | return root 34 | 35 | if leftLCA is None: 36 | return rightLCA 37 | 38 | if rightLCA is None: 39 | return leftLCA -------------------------------------------------------------------------------- /lecture_basic/Lecture3.Binary_Tree__Divide_Conquer/93. Balanced Binary Tree.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a binary tree, determine if it is height-balanced. 3 | 4 | For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1. 5 | 6 | Example 7 | Given binary tree A = {3,9,20,#,#,15,7}, B = {3,#,20,15,7} 8 | 9 | A) 3 B) 3 10 | / \ \ 11 | 9 20 20 12 | / \ / \ 13 | 15 7 15 7 14 | The binary tree A is a height-balanced binary tree, but B is not. 15 | ''' 16 | class Solution: 17 | ''' 18 | @param root: The root of binary tree 19 | @return: True if this binary tree is balanced, or false 20 | ''' 21 | def isBalanced(self, root): 22 | isBalanced, height = self.helper(root) 23 | return isBalanced 24 | 25 | def helper(self, root): 26 | if root is None: 27 | return True, 0 28 | 29 | # divide 30 | leftIsBalanced, leftHeight = self.helper(root.left) 31 | rightIsBalanced, rightHeight = self.helper(root.right) 32 | 33 | # conquer 34 | if leftIsBalanced and rightIsBalanced and abs(leftHeight - rightHeight) <= 1: 35 | return True, max(leftHeight, rightHeight) + 1 36 | 37 | return False, max(leftHeight, rightHeight) + 1 -------------------------------------------------------------------------------- /lecture_basic/Lecture3.Binary_Tree__Divide_Conquer/97. Maximum Depth of Binary Tree.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a binary tree, find its maximum depth. 3 | 4 | The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. 5 | 6 | Example 7 | Given a binary tree as follow: 8 | 9 | 1 10 | / \ 11 | 2 3 12 | / \ 13 | 4 5 14 | The maximum depth is 3. 15 | ''' 16 | class Solution: 17 | def maxDepth(self, root): 18 | if root is None: 19 | return 0 20 | 21 | # divide 22 | leftDepth = self.maxDepth(root.left) 23 | rightDepth = self.maxDepth(root.right) 24 | 25 | # conquer 26 | return max(leftDepth, rightDepth) + 1 -------------------------------------------------------------------------------- /lecture_basic/Lecture4.Dynamic_Programming/110. Minimum Path Sum.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path. 3 | ''' 4 | class Solution: 5 | ''' 6 | (1) Maxmum 7 | (2) Minmum 8 | (3) Total number of solutions 9 | (4) Feasible or not 10 | 11 | 1. Definition 12 | - dp[i][j]: The minmum path sum from (0,0) to (i, j) 13 | 2. Answer 14 | - dp[m - 1][n - 1] 15 | 3. State transfer equation 16 | - dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j] 17 | - Note: You can only move either down or right at any point in time. 18 | 4. Initialization 19 | - dp[i][0]: dp[i - 1][0] + grid[i][0] 20 | - dp[0][j]: dp[0][j - 1] + grid[0][j] 21 | ''' 22 | def minPathSum(self, grid): 23 | if not grid: 24 | return -1 25 | 26 | m, n = len(grid), len(grid[0]) 27 | dp = [ [0] * n for row in range(m)] 28 | 29 | for row in range(m): 30 | dp[row][0] = dp[row - 1][0] + grid[row][0] 31 | for col in range(n): 32 | dp[0][col] = dp[0][col - 1] + grid[0][col - 1] 33 | 34 | for row in range(1, m): 35 | for col in range(1, n): 36 | dp[row][col] = min(dp[row - 1][col], dp[row][col - 1]) + grid[row][col] 37 | 38 | return dp[m - 1][n - 1] -------------------------------------------------------------------------------- /lecture_basic/Lecture4.Dynamic_Programming/111. Climbing Stairs.py: -------------------------------------------------------------------------------- 1 | ''' 2 | You are climbing a stair case. It takes n steps to reach to the top. 3 | 4 | Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? 5 | 6 | Example 7 | Given an example n=3 , 1+1+1=2+1=1+2=3 8 | 9 | return 3 10 | ''' 11 | class Solution: 12 | ''' 13 | 1. Definition 14 | - dp[i]: how many distinct ways to jump to step i 15 | 2. Answer 16 | - dp[n] 17 | 3. State transfer equation 18 | - dp[i] = dp[i - 1] + dp[i - 2] 19 | 4. Initialization 20 | - dp[0] = 1 21 | - dp[1] = 1 22 | ''' 23 | def climbStairs(self, n): 24 | if n == 0: 25 | return 0 26 | 27 | if n in [1, 2]: 28 | return n 29 | 30 | dp = [0] * (n + 1) 31 | dp[0] = 1 32 | dp[1] = 1 33 | 34 | for i in range(2, n + 1): 35 | dp[i] = dp[i - 1] + dp[i - 2] 36 | 37 | return dp[n] 38 | ''' 39 | 算法武器:动态规划dp 40 | 41 | 因为是求方案数,所以第一时间想到dp 42 | 本题使用的是序列型的动态规划,所以我们的dp[i]代表跳完前i个台阶的方案数。我们的答案是dp[n],即跳完前n个台阶的方案数 43 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture4.Dynamic_Programming/114. Unique Paths.py: -------------------------------------------------------------------------------- 1 | ''' 2 | A robot is located at the top-left corner of a m x n grid. 3 | 4 | The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid. 5 | 6 | How many possible unique paths are there? 7 | 8 | Example 9 | Given m = 3 and n = 3, return 6. 10 | Given m = 4 and n = 5, return 35. 11 | ''' 12 | class Solution: 13 | def uniquePaths(self, m, n): 14 | dp = [ [0] * n for row in range(m)] 15 | 16 | for row in range(m): 17 | dp[row][0] = 1 18 | for col in range(n): 19 | dp[0][col] = 1 20 | 21 | for row in range(1, m): 22 | for col in range(1, n): 23 | dp[row][col] = dp[row - 1][col] + dp[row][col - 1] 24 | 25 | return dp[m - 1][n - 1] -------------------------------------------------------------------------------- /lecture_basic/Lecture4.Dynamic_Programming/116. Jump Game.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 116. Jump Game 3 | Given an array of non-negative integers, you are initially positioned at the first index of the array. 4 | 5 | Each element in the array represents your maximum jump length at that position. 6 | 7 | Determine if you are able to reach the last index. 8 | 9 | Example 10 | A = [2,3,1,1,4], return true. 11 | 12 | A = [3,2,1,0,4], return false. 13 | ''' 14 | class Solution: 15 | def canJump(self, A): 16 | if not A: 17 | return False 18 | 19 | dp = [False] * len(A) 20 | dp = True 21 | 22 | # dp[i]状态的计算是使用dp[0 ~ i - 1]的状态来联合计算的,而不是仅仅靠dp[i-i] 23 | # 只要在0 ~ i - 1个状态中,我们能找到一个状态自己本身可达,同时又能够可达i,那么我们认为dp[i]可达 24 | for i in range(1, len(A)): 25 | for j in range(i): 26 | if dp[j] and j + A[j] >= i: 27 | dp[i] = True 28 | break 29 | 30 | return dp[len(A) - 1] -------------------------------------------------------------------------------- /lecture_basic/Lecture4.Dynamic_Programming/117. Jump Game II.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array of non-negative integers, you are initially positioned at the first index of the array. 3 | 4 | Each element in the array represents your maximum jump length at that position. 5 | 6 | Your goal is to reach the last index in the minimum number of jumps. 7 | 8 | Example 9 | Given array A = [2,3,1,1,4] 10 | 11 | The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.) 12 | ''' 13 | class Solution: 14 | pass 15 | 16 | 17 | ''' 18 | 算法武器: 动态规划 19 | 20 | 本题和Jump Game I的区别是 21 | Jump Game要求求可行性,是否能够从起始点调到最后一个点 22 | Jump Game II要求求出最短跳跃次数 23 | 这个程序大致框架相同,仅在dp[i]求解/赋值方面略有不同 24 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture4.Dynamic_Programming/76. Longest Increasing Subsequence.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a sequence of integers, find the longest increasing subsequence (LIS). 3 | 4 | You code should return the length of the LIS. 5 | 6 | Example 7 | For [5, 4, 1, 2, 3], the LIS is [1, 2, 3], return 3 8 | For [4, 2, 4, 5, 3, 7], the LIS is [2, 4, 5, 7], return 4 9 | 10 | Challenge 11 | Time complexity O(n^2) or O(nlogn) 12 | ''' 13 | class Solution: 14 | ''' 15 | 1.Definition 16 | - dp[i]: jump from index 0 to i, the length of longest LIS 17 | - Note: the end of LIS is num[i] 18 | 2.Answer 19 | - max(dp): longest LIS could end with any index, so we use max to get the longest LIS length 20 | 3.State transfer equation 21 | - for index i, if num[j] < num[i] then dp[i] = max(dp[j] + 1, dp[i]) 22 | 4.Initialization 23 | - dp[i] = 1 24 | ''' 25 | def longestIncreasingSubsequence(self, nums): 26 | if not nusm: 27 | return 0 28 | 29 | dp = [1] * len(nums) 30 | 31 | for i in range(len(nums)): 32 | for j in range(i): 33 | if nums[j] < nums[i]: 34 | dp[i] = max(dp[i], dp[j] + 1) 35 | 36 | return max(dp) 37 | 38 | ''' 39 | 算法武器: 动规 40 | 41 | dp[i]定义:数组以i位置处的nums[i]作为最大值的区间的最长递增子序列长度 42 | 43 | 这是一道经典的使用中间状态dp[j]求解dp[i], 而不是使用前一个状态dp[i-1] 44 | 状态转移方程描述的是dp[i] 和 中间状态dp[j]的状态变迁 45 | 46 | 注意:本题是subsequence,是讲顺序的,所以我们不能给数组排序 47 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture5.0.BFS/readme.txt: -------------------------------------------------------------------------------- 1 | test -------------------------------------------------------------------------------- /lecture_basic/Lecture5.1.DFS_Binary_Tree_Based/175. Invert Binary Tree.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Invert a binary tree. 3 | 4 | Example 5 | 1 1 6 | / \ / \ 7 | 2 3 => 3 2 8 | / \ 9 | 4 4 10 | Challenge 11 | Do it in recursion is acceptable, can you do it without recursion? 12 | ''' 13 | class Solution: 14 | def invertBinaryTree(self, root): 15 | if node is None: 16 | return node 17 | 18 | # divide 19 | invertedLeft = self.invertBinaryTree(self.left) 20 | invertedRight = self.invertBinaryTree(self.right) 21 | 22 | # conquer 23 | node.left, node.right = invertedRight, invertedLeft 24 | 25 | return node -------------------------------------------------------------------------------- /lecture_basic/Lecture5.1.DFS_Binary_Tree_Based/596. Minimum Subtree.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a binary tree, find the subtree with minimum sum. Return the root of the subtree. 3 | 4 | Example 5 | Given a binary tree: 6 | 7 | 1 8 | / \ 9 | -5 2 10 | / \ / \ 11 | 0 2 -4 -5 12 | return the node 1. 13 | ''' 14 | class Solution: 15 | def findSubtree(self, root): 16 | self.targetNode, self.minsum = None, sys.maxsize 17 | self.helper(root) 18 | return self.targetNode 19 | 20 | def helper(self, root): 21 | if not root: 22 | return 0 23 | 24 | # divide 25 | leftsum = self.helper(root.left) 26 | rightsum = self.helper(root.right) 27 | 28 | # conquer 29 | treesum = leftsum + rightsum + root.val 30 | if treesum < self.minsum: 31 | self.minsum = treesum 32 | self.targetNode = root 33 | 34 | return treesum 35 | ''' 36 | 算法武器:分治法(递归函数使用了返回值) + 遍历法(使用了全局变量,打擂台) 37 | 38 | 概念: 39 | 40 | 分治法的特点是使用了返回函数 41 | 遍历法的特点是使用了全局变量,用打擂台的形式进行计算 42 | 因为本题需要同时用到这两个特点,所以本题是分治法和遍历法的结合 43 | 算法思路: 44 | 45 | 使用分治法求给定树根的子树和。 46 | 分治函数的思路是首先计算左子树和,然后计算右子树和,最后加上根节点的值,三者之和构成了当前给定树根的子树和 47 | 同时在分治函数中使用打擂台的方式更新全局最小子树和以及子树根 48 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture5.1.DFS_Binary_Tree_Based/597. Subtree with Maximum Average.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a binary tree, find the subtree with maximum average. Return the root of the subtree. 3 | 4 | Example 5 | Given a binary tree: 6 | 7 | 1 8 | / \ 9 | -5 11 10 | / \ / \ 11 | 1 2 4 -2 12 | return the node 11. 13 | ''' 14 | class Solution: 15 | def findSubtree2(self, root): 16 | self.targetNode, self.average = None, 0 17 | self.helper(root) 18 | return self.targetNode 19 | 20 | # @return {(sum, average)}: the sum of the given tree, the average value of the given tree 21 | def helper(self, root): 22 | if root is None: 23 | return 0, 0 24 | 25 | # divide 26 | leftSum, leftSize = self.helper(root.left) 27 | rightSum, rightSize = self.helper(root.right) 28 | 29 | # conquer 30 | treesum = leftsum + rightsum + root.val 31 | size = leftSize + rightSize + 1 32 | average = treesum * 1.0 / size 33 | 34 | # 更新全局结果 35 | if self.targetNode is None or self.average < average: 36 | self.targetNode = root 37 | self.average = average 38 | 39 | # 返回本颗树的计算结果 40 | return treesum, size 41 | 42 | # 算法武器: 分治法 + 递归 + 全局变量更新 43 | -------------------------------------------------------------------------------- /lecture_basic/Lecture5.1.DFS_Binary_Tree_Based/902. Kth Smallest Element in a BST.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a binary search tree, write a function kthSmallest to find the kth smallest element in it. 3 | 4 | Example 5 | Given root = {1,#,2}, k = 2, return 2. 6 | 7 | Challenge 8 | What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine? 9 | ''' 10 | """ 11 | Definition of TreeNode: 12 | class TreeNode: 13 | def __init__(self, val): 14 | self.val = val 15 | self.left, self.right = None, None 16 | """ 17 | 18 | class Solution: 19 | """ 20 | @param root: the given BST 21 | @param k: the given k 22 | @return: the kth smallest element in BST 23 | """ 24 | def kthSmallest(self, root, k): 25 | # write your code here -------------------------------------------------------------------------------- /lecture_basic/Lecture5.2.DFS_Combination_Based/135. Combination Sum.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. 3 | 4 | The same repeated number may be chosen from C unlimited number of times. 5 | 6 | Example 7 | Given candidate set [2,3,6,7] and target 7, a solution set is: 8 | 9 | [7] 10 | [2, 2, 3] 11 | ''' 12 | class Solution: 13 | def combinationSum(self, candidates, target): 14 | self.result = [] 15 | candidates.sort() 16 | self.dfs(candidates, target, 0, []) 17 | return self.result 18 | 19 | def dfs(self, candidates, target, start, valuelist): 20 | if target == 0: 21 | self.result.append(valuelist[:]) 22 | return 23 | 24 | for i in range(start, len(candidates)): 25 | if i > start and candidates[i] == candidates[i - 1]: 26 | continue 27 | 28 | if target < candidates[i]: 29 | return 30 | 31 | valuelist.append(candidates[i]) 32 | self.dfs(candidates, target - candidates[i], i, valuelist) 33 | valuelist.pop() 34 | -------------------------------------------------------------------------------- /lecture_basic/Lecture5.3.DFS_Permutation_Based/readme.txt: -------------------------------------------------------------------------------- 1 | test -------------------------------------------------------------------------------- /lecture_basic/Lecture6.Linked_List/102. Linked List Cycle.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a linked list, determine if it has a cycle in it. 3 | 4 | 5 | 6 | Example 7 | Given -21->10->4->5, tail connects to node index 1, return true 8 | 9 | Challenge 10 | Follow up: 11 | Can you solve it without using extra space? 12 | ''' 13 | class Solution: 14 | def hasCycle(self, head): 15 | if head is None or head.next is None: 16 | return False 17 | 18 | # 注意:这里的slow和fast指针初始化时是不一样的 19 | # 因为后面的while的条件是当slow != fast, 所以我们不能把slow和fast初始化成相同的值 20 | # 反正只要快慢指针存在,并且有环,那么快指针一定会和慢指针重合即slow == fast 21 | slow, fast = head, head.next 22 | 23 | while slow != fast: 24 | if fast is None or fast.next is None: 25 | return False 26 | 27 | slow = slow.next 28 | fast = fast.next.next 29 | 30 | return True -------------------------------------------------------------------------------- /lecture_basic/Lecture6.Linked_List/104. Merge K Sorted Lists.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Merge k sorted linked lists and return it as one sorted list. 3 | 4 | Analyze and describe its complexity. 5 | 6 | Example 7 | Given lists: 8 | 9 | [ 10 | 2->4->null, 11 | null, 12 | -1->null 13 | ], 14 | return -1->2->4->null. 15 | ''' 16 | import heapq 17 | class Solution: 18 | def mergeKLists(self, lists): 19 | if not lists: 20 | return None 21 | 22 | heap = [] 23 | for listHead in lists: 24 | if listHead: 25 | heapq.heappush(heap, (listHead.val, listHead)) 26 | 27 | dummyHead = ListNode(0) 28 | cur = dummyHead 29 | 30 | while heap: 31 | val, node = heapq.heappop(heap) 32 | cur.next = node 33 | cur = cur.next 34 | if node.next: 35 | heapq.heappush(heap, (node.next.val, node.next)) 36 | 37 | return dummyHead.next 38 | ''' 39 | 算法武器: heap + list + dummy head 40 | 41 | 我们使用堆的方式和使用队列的模式有相同模式,即我们使用一个while循环,一次从堆中取出元素,进行操作,同时随着操作右不断地向堆中加入元素,知道堆中的元素被处理完毕。 42 | 43 | 思路和求解过程: 44 | 45 | 合并多个链表的问题一定是使用堆 46 | 扫描链表的链表,把每个链表的头结点加入到堆中 47 | 放入堆中的元素是一个二元组,第一个元素是node.val,堆会根据这个值进行排序 48 | 使用虚拟头结点简化计算 49 | 每当出堆一次,就查看出堆的链表节点是否还有下一个节点,如果有,就将其入堆 50 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture6.Linked_List/106. Convert Sorted List to Binary Search Tree.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST. 3 | 4 | Example 5 | 2 6 | 1->2->3 => / \ 7 | 1 3 8 | ''' 9 | """ 10 | Definition of ListNode 11 | class ListNode(object): 12 | 13 | def __init__(self, val, next=None): 14 | self.val = val 15 | self.next = next 16 | 17 | Definition of TreeNode: 18 | class TreeNode: 19 | def __init__(self, val): 20 | self.val = val 21 | self.left, self.right = None, None 22 | """ 23 | class Solution: 24 | def sortedListToBST(self, head): 25 | pass 26 | 27 | -------------------------------------------------------------------------------- /lecture_basic/Lecture6.Linked_List/113. Remove Duplicates from Sorted List II.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list. 3 | 4 | Example 5 | Given 1->2->3->3->4->4->5, return 1->2->5. 6 | Given 1->1->1->2->3, return 2->3. 7 | ''' 8 | class DoublyListNode: 9 | def __init__(self, val, next = None): 10 | self.val = val 11 | self.next = self.prev = next 12 | 13 | class Solution: 14 | def bstToDoublyList(self, root): 15 | inorder = [] 16 | self.inorderTraverse(root, inorder) 17 | if not inorder: 18 | return None 19 | 20 | dummyHead = DoublyListNode(0) 21 | prev = dummyHead 22 | 23 | # 形成一个链表,我们选择尾插法 24 | # 插入一个元素,我们需要借助前驱节点 25 | for val in inorder: 26 | node = DoublyListNode(val) 27 | prev.next = node 28 | node.prev = prev 29 | prev = node 30 | 31 | return dummyHead.next 32 | 33 | def inorderTraverse(self, root, inorder): 34 | if root is None: 35 | return 36 | 37 | self.inorderTraverse(root.left, inorder) 38 | inorder.append(root.val) 39 | self.inorderTraverse(root.right, inorder) 40 | 41 | ''' 42 | 算法武器:二叉树中序遍历 + 双向链表构成 43 | 双向链表的构建需要使用到prev节点,同时使用dummy节点使头的处理简单 44 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture6.Linked_List/170. Rotate List.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a list, rotate the list to the right by k places, where k is non-negative. 3 | 4 | Example 5 | Given 1->2->3->4->5 and k = 2, return 4->5->1->2->3. 6 | ''' 7 | class Solution: 8 | ''' 9 | 1.求整个链表长度 10 | 2.对k进行取模,得到有效的k值(k可能比整个链表长度长) 11 | 3.扫描链表直到size - k,找到新的链表头nhead的前驱 12 | - 将前驱的next置为空 13 | 4.从nhead扫描,直到链表结尾,让结尾节点指向元链表head,构成一条新链 14 | ''' 15 | def rotateRight(self, head, k): 16 | if not head or not head.next or not k: 17 | return head 18 | 19 | size, curNode = 0, head 20 | while curNode: 21 | size += 1 22 | curNode = curNode.next 23 | 24 | k = k % size 25 | # 如果k是链表长度的整个倍数,那么就相当于没有rotate 26 | if k == 0: 27 | return head 28 | 29 | # 因为我们的curNode指向的是head,所以我们把当前的curLength初始化为1 30 | curLength, curNode = 1, head 31 | while curLength < size - k: 32 | curNode = curNode.next 33 | curLength += 1 34 | 35 | # curNode跳出循环后刚好指向新链表头的前驱 36 | nhead = curNode.next 37 | curNode.next = None 38 | curNode = nhead 39 | 40 | while curNode.next: 41 | curNode = curNode.next 42 | 43 | curNode.next = head 44 | 45 | return nhead 46 | -------------------------------------------------------------------------------- /lecture_basic/Lecture6.Linked_List/35. Reverse Linked List.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Reverse a linked list. 3 | 4 | Example 5 | For linked list 1->2->3, the reversed linked list is 3->2->1 6 | 7 | Challenge 8 | Reverse it in-place and in one-pass 9 | ''' 10 | class Solution: 11 | def reverse(self, head): 12 | prev, curr, next = None, head, None 13 | 14 | while curr: 15 | next = curr.next 16 | curr.next = prev 17 | prev = curr 18 | curr = next 19 | 20 | return prev 21 | 22 | ''' 23 | 算法武器:链表 + 三个游标指针(prev, curr, next) 24 | 25 | 算法思路: 26 | 27 | 定义三个指针进行翻转操作(prev, curr, next) 28 | 使用一个while循环进行列表翻转 29 | while的循环条件为curr不为空 30 | while退出后,prev指向翻转后的列表的头结点 31 | 翻转4部曲 32 | 33 | 保存next指针 34 | 当前指针后继指向前驱 35 | 前驱向后移动,指向当前 36 | 当前向后移动,指向next 37 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture6.Linked_List/372. Delete Node in a Linked List.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Implement an algorithm to delete a node in the middle of a singly linked list, given only access to that node. 3 | 4 | Example 5 | Linked list is 1->2->3->4, and given node 3, delete the node in place 1->2->4 6 | ''' 7 | class Solution: 8 | def deleteNode(self, node): 9 | if node is None or node.next is None: 10 | return 11 | 12 | next = node.next 13 | node.val = next.val 14 | node.next = next.next 15 | 16 | return 17 | 18 | ''' 19 | 本题的难点在于我们只给定了要删除的节点,并且该链表是单向链表 20 | 解决方案: 我们改变当前需要删除节点的val和next,达到删除当前节点的目的 21 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture6.Linked_List/96. Partition List.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x. 3 | 4 | You should preserve the original relative order of the nodes in each of the two partitions. 5 | 6 | Example 7 | Given 1->4->3->2->5->2->null and x = 3, 8 | return 1->2->2->4->3->5->null. 9 | ''' 10 | class Solution: 11 | def partition(self, head, x): 12 | if head is None: 13 | return head 14 | 15 | aHead, bHead = ListNode(0), ListNode(0) 16 | aTail, bTail = aHead, bHead 17 | 18 | cur = head 19 | while cur: 20 | if cur.val < x: 21 | aTail.next = cur 22 | aTail = aTail.next 23 | else: 24 | bTail.next = cur 25 | bTail = bTail.next 26 | cur = cur.next 27 | 28 | bTail.next = None 29 | aTail.next = bHead.next 30 | 31 | return aHead.next 32 | 33 | ''' 34 | 算法武器:链表 + dummyNode + 双链表头指针 + 双链表尾指针 + 双链表连接 35 | 36 | 算法思路: 37 | 38 | 定义两个链表的dummy头结点aHead, bHead 39 | 定义两个聊表的尾指针aTail, bTail, 其初值为头结点 40 | 定义当前游标指针,用于遍历整个给定链表 41 | aTail和bTail是游标指针,aTail指向node节点值小于x的链表 42 | bTail指向node节点值大于等于x的链表 43 | 使用while循环遍历整个链表,对于扫描到的每一个节点元素 44 | 如果cur.val < x, 则把它加入到aHead的链表中,即让aTail.next = cur, 然后移动aTail, aTail = aTail.next 45 | 如果cur.val >=x, 则把它加入到bHead的链表中,即让bTail.next = cur, 然后移动bTail, bTail = bTail.next 46 | 移动游标指针,让其指向下一个元素 47 | 让aHead链表和bHead链表进行拼接, aTail.next = bHead.next 48 | 不要忘记将aTail.next置空, aTail.next = 0 49 | 返回aHead.next 50 | ''' 51 | -------------------------------------------------------------------------------- /lecture_basic/Lecture6.Linked_List/98. Sort List.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Sort a linked list in O(n log n) time using constant space complexity. 3 | 4 | Example 5 | Given 1->3->2->null, sort it to 1->2->3->null. 6 | 7 | Challenge 8 | Solve it by merge sort & quick sort separately. 9 | ''' 10 | class Solution: 11 | def sortList(self, head): 12 | vals = [] 13 | 14 | cur = head 15 | while cur: 16 | vals.append(cur.val) 17 | cur = cur.next 18 | 19 | vals.sort() 20 | 21 | cur = head 22 | for val in vals: 23 | cur.val = val 24 | cur = cur.next 25 | 26 | return head 27 | ''' 28 | 算法武器:排序 29 | 30 | 算法思路: 31 | 定义一个数组,用于保存链表元素 32 | 扫描链表,将数据收集到定义的数组中 33 | 对数组中元素进行排序 34 | 扫描链表,按照数组中的值更新链表的节点值 35 | ''' 36 | -------------------------------------------------------------------------------- /lecture_basic/Lecture6.Linked_List/99. Reorder List.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a singly linked list L: L0 → L1 → … → Ln-1 → Ln 3 | 4 | reorder it to: L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → … 5 | 6 | Example 7 | Given 1->2->3->4->null, reorder it to 1->4->2->3->null. 8 | 9 | Challenge 10 | Can you do this in-place without altering the nodes' values? 11 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture7.Array__Numbers/149. Best Time to Buy and Sell Stock.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Say you have an array for which the ith element is the price of a given stock on day i. 3 | 4 | If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit. 5 | 6 | Example 7 | Given array [3,2,3,1,2], return 1. 8 | ''' 9 | class Solution: 10 | def maxProfit(self, prices): 11 | if not prices: 12 | return 0 13 | 14 | profit = 0 15 | low = prices[0] 16 | 17 | for price in prices: 18 | profit = max(profit, price - low) 19 | low = min(low, price) 20 | 21 | return profit 22 | 23 | ''' 24 | 算法武器:数组 + 一次遍历(打擂台法) 25 | 26 | http://www.cnblogs.com/felixfang/p/3644768.html 27 | 股票问题: 28 | 想要最大化收益就是buy low sell high 29 | 扫描价格数组,不断用当前价格减去历史最低点计算收益,如果大于历史收益,则将其更新 30 | 31 | 如果发现新的股票新低就将其更新 32 | 33 | 因为题目只要求进行一次交易,所以total不是累加的,而是在不同的收益中选取某次交易最大的收益🉐 34 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture7.Array__Numbers/150. Best Time to Buy and Sell Stock II.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Say you have an array for which the ith element is the price of a given stock on day i. 3 | 4 | Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again). 5 | 6 | Example 7 | Given an example [2,1,2,0,1], return 2 8 | ''' 9 | class Solution: 10 | if not prices: 11 | return 0 12 | 13 | profit = 0 14 | for i in range(1, len(prices)): 15 | if prices[i] > prices[i - 1]: 16 | profit += prices[i] - prices[i - 1] 17 | 18 | return profit -------------------------------------------------------------------------------- /lecture_basic/Lecture7.Array__Numbers/41. Maximum Subarray.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array of integers, find a contiguous subarray which has the largest sum. 3 | 4 | Example 5 | Given the array [−2,2,−3,4,−1,2,1,−5,3], the contiguous subarray [4,−1,2,1] has the largest sum = 6. 6 | 7 | Challenge 8 | Can you do it in time complexity O(n)? 9 | ''' 10 | class Solution: 11 | def maxSubArray(self, nums): 12 | if not nums: 13 | return -sys.maxsize 14 | 15 | maxSum, minPreSum, presum = nums[0], 0, 0 16 | for num in nums: 17 | presum += num 18 | maxSum = max(maxSum, presum - minPreSum) 19 | minPreSum = min(minPreSum, presum) 20 | 21 | return maxSum -------------------------------------------------------------------------------- /lecture_basic/Lecture7.Array__Numbers/42. Maximum Subarray II.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array of integers, find two non-overlapping subarrays which have the largest sum. 3 | The number in each subarray should be contiguous. 4 | Return the largest sum. 5 | 6 | Example 7 | For given [1, 3, -1, 2, -1, 2], the two subarrays are [1, 3] and [2, -1, 2] or [1, 3, -1, 2] and [2], they both have the largest sum 7. 8 | 9 | Challenge 10 | Can you do it in time complexity O(n) ? 11 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture7.Array__Numbers/44. Minimum Subarray.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array of integers, find the subarray with smallest sum. 3 | 4 | Return the sum of the subarray. 5 | 6 | Example 7 | For [1, -1, -2, 1], return -3. 8 | ''' 9 | class Solution: 10 | ''' 11 | 题型:求一个数组中的最小子区间和最大子区间问题 12 | 解法:可以使用滚动计算当前位置的presum,实时更新maxpresum 和 minsum的方式求解 13 | 注意:初始化是一个关键,因为我们要求最小区间和,而根据前缀和计算公式: 14 | minsum = presum - maxpresum 15 | 我们的最小和区间可能是从0开始,所以maxpresum需要初始化为0,才能包含这种情况 16 | minsum一定是一个子区间,至少包含一个数,所以我们把minsum初始化为nums[0] 17 | presum初始化为0 18 | ''' 19 | def minSubArray(self, nums): 20 | if not nums: 21 | return 0 22 | 23 | presum, maxPresum, minsum = 0, 0, nums[0] 24 | for num in nums: 25 | presum += num 26 | minsum = min(minsum, presum - maxPresum) 27 | maxPresum = max(maxPresum, presum) 28 | 29 | return minsum -------------------------------------------------------------------------------- /lecture_basic/Lecture7.Array__Numbers/56. Two Sum.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array of integers, find two numbers such that they add up to a specific target number. 3 | 4 | The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are zero-based. 5 | 6 | Example 7 | numbers=[2, 7, 11, 15], target=9 8 | 9 | return [0, 1] 10 | 11 | Challenge 12 | Either of the following solutions are acceptable: 13 | 14 | O(n) Space, O(nlogn) Time 15 | O(n) Space, O(n) Time 16 | ''' 17 | class Solution: 18 | def twoSum(self, nums, target): 19 | cache = {} 20 | for i in range(len(nums)): 21 | if target - num[i] in cache: 22 | return [cache[target - num[i]] + 1, i + 1] 23 | cache[nums[i]] = i 24 | 25 | return [-1, -1] 26 | -------------------------------------------------------------------------------- /lecture_basic/Lecture7.Array__Numbers/64. Merge Sorted Array.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonforce2010/interview-algothims/338d3bc2f2916c5c4936767b07b2fd22b4121049/lecture_basic/Lecture7.Array__Numbers/64. Merge Sorted Array.py -------------------------------------------------------------------------------- /lecture_basic/Lecture8.Data_Structure/104. Merge K Sorted Lists.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Merge k sorted linked lists and return it as one sorted list. 3 | 4 | Analyze and describe its complexity. 5 | 6 | Example 7 | Given lists: 8 | 9 | [ 10 | 2->4->null, 11 | null, 12 | -1->null 13 | ], 14 | return -1->2->4->null. 15 | ''' 16 | class Solution: 17 | def mergeKLists(self, lists): 18 | if not list: 19 | return None 20 | 21 | import heapq 22 | heap = [] 23 | for node in lists: 24 | if node: 25 | heapq.heappush((node.val, node)) 26 | 27 | dummyHead = ListNode(0) 28 | curr = dummyHead 29 | 30 | while heap: 31 | val, node = heapq.heappop(heap) 32 | curr.next = ListNode(val) 33 | curr = curr.next 34 | if node.next: 35 | heapq.heappush(heap, (node.next.val, node.next)) 36 | 37 | return dummy.next 38 | 39 | ''' 40 | 算法武器: heap + list + dummy head 41 | 42 | 我们使用堆的方式和使用队列的模式有相同模式,即我们使用一个while循环,一次从堆中取出元素,进行操作,同时随着操作右不断地向堆中加入元素,知道堆中的元素被处理完毕。 43 | 44 | 思路和求解过程: 45 | 46 | 合并多个链表的问题一定是使用堆 47 | 扫描链表的链表,把每个链表的头结点加入到堆中 48 | 放入堆中的元素是一个二元组,第一个元素是node.val,堆会根据这个值进行排序 49 | 使用虚拟头结点简化计算 50 | 每当出堆一次,就查看出堆的链表节点是否还有下一个节点,如果有,就将其入堆 51 | ''' 52 | -------------------------------------------------------------------------------- /lecture_basic/Lecture8.Data_Structure/12. Min Stack.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Implement a stack with min() function, which will return the smallest number in the stack. 3 | 4 | It should support push, pop and min operation all in O(1) cost. 5 | 6 | Example 7 | push(1) 8 | pop() // return 1 9 | push(2) 10 | push(3) 11 | min() // return 2 12 | push(1) 13 | min() // return 1 14 | ''' 15 | class Solution: 16 | def __init__(self): 17 | self.stack = [] 18 | self.minstack = [] 19 | 20 | def push(self, number): 21 | self.stack.append(number) 22 | if not self.minstack or number <= self.minstack[-1]: 23 | self.minstack.append(number) 24 | 25 | def pop(self): 26 | if self.stack[-1] == self.minstack[-1]: 27 | self.minstack.pop() 28 | 29 | return self.stack.pop() 30 | 31 | def min(self): 32 | return self.minstack[-1] 33 | ''' 34 | 算法武器:最小栈 35 | 36 | 最小栈的使用方法: 37 | 38 | 当数据进入数据栈时,判断最小栈是否有元素或是进入的数据比最小栈的栈顶数据还小,那么就将该数据也推入最小栈 39 | 当进入数据等于最小栈栈顶数据时,我们也将该数据推入最新哦啊哦栈 40 | 当数据出栈时,我们判断出栈的数据是否等于最小栈栈顶的数据,如果相等,则最小栈也需要出栈一个元素 41 | 当查看当前栈中的最小数据时,我们返回最小栈的栈顶数据即可 42 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture8.Data_Structure/122. Largest Rectangle in Histogram.py: -------------------------------------------------------------------------------- 1 | '''https://www.lintcode.com/problem/largest-rectangle-in-histogram/description 2 | Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram. 3 | 4 | histogram 5 | 6 | Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3]. 7 | 8 | histogram 9 | 10 | The largest rectangle is shown in the shaded area, which has area = 10 unit. 11 | 12 | Example 13 | Given height = [2,1,5,6,2,3], 14 | return 10. 15 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture8.Data_Structure/129. Rehashing.py: -------------------------------------------------------------------------------- 1 | ''' 2 | The size of the hash table is not determinate at the very beginning. If the total size of keys is too large (e.g. size >= capacity / 10), we should double the size of the hash table and rehash every keys. Say you have a hash table looks like below: 3 | 4 | size=3, capacity=4 5 | 6 | [null, 21, 14, null] 7 | ↓ ↓ 8 | 9 null 9 | ↓ 10 | null 11 | The hash function is: 12 | 13 | int hashcode(int key, int capacity) { 14 | return key % capacity; 15 | } 16 | here we have three numbers, 9, 14 and 21, where 21 and 9 share the same position as they all have the same hashcode 1 (21 % 4 = 9 % 4 = 1). We store them in the hash table by linked list. 17 | 18 | rehashing this hash table, double the capacity, you will get: 19 | 20 | size=3, capacity=8 21 | 22 | index: 0 1 2 3 4 5 6 7 23 | hash : [null, 9, null, null, null, 21, 14, null] 24 | Given the original hash table, return the new hash table after rehashing . 25 | 26 | Example 27 | Given [null, 21->9->null, 14->null, null], 28 | 29 | return [null, 9->null, null, null, null, 21->null, 14->null, null] 30 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture8.Data_Structure/130. Heapify.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an integer array, heapify it into a min-heap array. 3 | 4 | For a heap array A, A[0] is the root of heap, and for each A[i], A[i * 2 + 1] is the left child of A[i] and A[i * 2 + 2] is the right child of A[i]. 5 | Example 6 | Given [3,2,1,4,5], return [1,2,3,4,5] or any legal heap array. 7 | 8 | Challenge 9 | O(n) time complexity 10 | ''' 11 | class Solution: 12 | def heapify(self, A): 13 | for pos in range((len(A) - 1) // 2, -1, -1): 14 | self.siftdown(A, pos) 15 | 16 | def siftdown(self, A, rootPos): 17 | # 只要还有孩子节点,那么就进行siftdown调整 18 | while rootPos * 2 + 1 < len(A): 19 | son = rootPos * 2 + 1 20 | # 判断右子是否存在,存在并且右子更小,那么久更新son的位置 21 | # 因为我们要选择一个最小的子节点和根进行比较 22 | if son + 1 < len(A) and A[son + 1] < A[son]: 23 | son = son + 1 24 | if A[rootPos] <= A[son]: 25 | break 26 | 27 | A[rootPos], A[son] = A[son], A[rootPos] 28 | rootPos = son 29 | 30 | ''' 31 | 32 | 算法武器:建堆 33 | 34 | 本题考查建堆(二叉堆)的实现。建堆的过程如下: 35 | 36 | 从二叉树的最后一个拥有孩子的父节点开始,逐步向上(到树根节点)进行下滑操作,将每个节点为根的子树调整成一个堆,直到整个树成为一个堆。 37 | 下滑操作的过程:从给定的树根节点开始,将树根节点和两个孩子比较,取两个孩子中最小的节点和树根节点比较,如果比根小,那么根节点和该子节点交换,然后递归向下调整,知道该子树成为一个堆。 38 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture8.Data_Structure/138. Subarray Sum.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an integer array, find a subarray where the sum of numbers is zero. Your code should return the index of the first number and the index of the last number. 3 | 4 | Example 5 | Given [-3, 1, 2, -3, 4], return [0, 2] or [1, 3]. 6 | ''' 7 | class Solution: 8 | def subarraySum(self, A): 9 | if not A: 10 | return [] 11 | 12 | cache = {} 13 | presum = 0 14 | 15 | for i in range(len(A)): 16 | presum += A[i] 17 | if presum in cache: 18 | return [presum[sum] + 1, i] 19 | cache[presum] = i 20 | 21 | return [] -------------------------------------------------------------------------------- /lecture_basic/Lecture8.Data_Structure/40. Implement Queue by Two Stacks.py: -------------------------------------------------------------------------------- 1 | ''' 2 | As the title described, you should only use two stacks to implement a queue's actions. 3 | 4 | The queue should support push(element), pop() and top() where pop is pop the first(a.k.a front) element in the queue. 5 | 6 | Both pop and top methods should return the value of first element. 7 | 8 | Example 9 | push(1) 10 | pop() // return 1 11 | push(2) 12 | push(3) 13 | top() // return 2 14 | pop() // return 2 15 | Challenge 16 | implement it by two stacks, do not use any other data structure and push, pop and top should be O(1) by AVERAGE. 17 | ''' 18 | class MyQueue: 19 | def __init__(self): 20 | self.stack1 = [] 21 | self.stack2 = [] 22 | 23 | def adjust(self): 24 | if not self.stack2: 25 | while self.stack1: 26 | self.stack2.append(self.stack1.pop()) 27 | 28 | def push(self, element): 29 | self.stack1.append(element) 30 | 31 | def top(self, element): 32 | self.adjust() 33 | return self.stack2[-1] 34 | 35 | def pop(self): 36 | self.adjust() 37 | return self.stack2.pop() 38 | 39 | ''' 40 | 算法武器:栈 41 | 42 | 算法思路: 43 | 44 | 使用stack1作为数据栈,保存入栈元素,即push操作全部push到stack1中 45 | 使用stack2作为数据栈,用于出栈元素,即pop元素都从stack2中pop出来 46 | 但是注意,从stack2中pop数据时,我们要做一个判断: 47 | 如果stack2为空,那么我们需要把数据从stack1出栈到stack2中,这样stack1中的数据就可以像队列一样的顺序输出了,因为数据的顺序经过栈的翻转改变了。 48 | 如果stack2不为空,那么就持续从stack2中pop就好,如果有数据push进来,我们依然持续往statck1中push 49 | adjust操作仅发生在stack2中的数据没了,消费完了,我们才从stack1中全部导入一次 50 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture8.Data_Structure/486. Merge K Sorted Arrays.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given k sorted integer arrays, merge them into one sorted array. 3 | 4 | Example 5 | Given 3 sorted arrays: 6 | 7 | [ 8 | [1, 3, 5, 7], 9 | [2, 4, 6], 10 | [0, 8, 9, 10, 11] 11 | ] 12 | return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]. 13 | 14 | Challenge 15 | Do it in O(N log k). 16 | 17 | N is the total number of integers. 18 | k is the number of arrays. 19 | ''' 20 | import heapq 21 | class Solution: 22 | def mergeSortedArrays(self, arry): 23 | result, heap = [] 24 | for row, array in enumerate(arrays): 25 | if array: 26 | heapq.heappush(heap, (array[0], row, 0)) 27 | 28 | while heap: 29 | val, row, col = heapq.heappop(heap) 30 | result.append(val) 31 | if col + 1 < len(arrays[row]): 32 | heapq.heappush(heap, (arrays[row][col + 1], row, col + 1)) 33 | 34 | return sesult 35 | ''' 36 | 算法武器: heap 37 | 38 | 这道题和把k个有序链表合并的思路一样的。都是使用heap,将每个数组的首元素加入heap,然后每次从heap中弹出的元素, 39 | 装入堆的是一个三元组:(元素值,元素在arrays中所在的row, 元素在arrays.col) 40 | 元组第一个分量用于堆排序依据和结果输出,第二个、第三个元素分量用于寻找下一个进入堆的元素的位置。 41 | 每次将元素入堆的时候都要判断元素是否在数组中存在。 42 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture8.Data_Structure/494. Implement Stack by Two Queues.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Implement a stack by two queues. The queue is first in first out (FIFO). That means you can not directly pop the last element in a queue. 3 | 4 | Example 5 | push(1) 6 | pop() 7 | push(2) 8 | isEmpty() // return false 9 | top() // return 2 10 | pop() 11 | isEmpty() // return true 12 | ''' 13 | class Solution: 14 | def __init__(self): 15 | from collections import deque 16 | self.q1 = deque([]) 17 | self.q2 = deque([]) 18 | 19 | def push(self, x): 20 | self.q1.append(x) 21 | 22 | def pop(self): 23 | while len(self.q1) > 1: 24 | self.q2.append(self.q1.popleft()) 25 | ele = self.q1.popleft() 26 | self.q1, self.q2 = self.q2, self.q1 27 | return ele 28 | 29 | def top(self): 30 | while len(self.q1) > 1: 31 | self.q2.append(self.q1.popleft()) 32 | ele = self.q1.popleft() 33 | self.q2.append(ele) 34 | self.q1, self.q2 = self.q2, self.q1 35 | return ele 36 | 37 | def isEmpty(self): 38 | return len(self.q1) > 0 -------------------------------------------------------------------------------- /lecture_basic/Lecture8.Data_Structure/517. Ugly Number.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Write a program to check whether a given number is an ugly number`. 3 | 4 | Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 6, 8 are ugly while 14 is not ugly since it includes another prime factor 7. 5 | 6 | Example 7 | Given num = 8 return true 8 | Given num = 14 return false 9 | ''' 10 | class Solution: 11 | def isUgly(self, num): 12 | if num <= 0: 13 | return False 14 | 15 | if num == 1: 16 | return True 17 | 18 | while num >= 2 and num % 2 == 0: 19 | num /= 2 20 | while num >= 3 and num % 3 == 0: 21 | num /= 3 22 | while num >= 5 and num % 5 == 0: 23 | num /= 5 24 | 25 | return num == 1 26 | ''' 27 | 本题学会了对因数的处理技巧。如果我们想要除去某一个数中的某个因数,那么我们的技能就是不断地连续除以这个因数 28 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture9.Graph_Search/120. Word Ladder.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that: 3 | 4 | Only one letter can be changed at a time 5 | Each intermediate word must exist in the dictionary 6 | Example 7 | Given: 8 | start = "hit" 9 | end = "cog" 10 | dict = ["hot","dot","dog","lot","log"] 11 | As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog", 12 | return its length 5. 13 | ''' 14 | class Solution: 15 | def ladderLength2(self, start, end, dict): 16 | dict.add(end) 17 | wordLen = len(start) 18 | queue = collections.deque([(start, 1)]) 19 | 20 | while queue: 21 | curWord, pathLen = queue.popleft() 22 | if curWord == end: 23 | return pathLen 24 | 25 | for i in range(wordLen): 26 | part1 = curWord[:i] 27 | part2 = curWord[i + 1:] 28 | for j in 'abcdefghijklmnopqrstuvwxyz': 29 | if curWord[i] != j: 30 | nextWord = part1 + j + part2 31 | if nextWord in dict: 32 | queue.append((nextWord, pathLen + 1)) 33 | dict.remove(nextWord) 34 | 35 | return 0 -------------------------------------------------------------------------------- /lecture_basic/Lecture9.Graph_Search/136. Palindrome Partitioning.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a string s, partition s such that every substring of the partition is a palindrome. 3 | 4 | Return all possible palindrome partitioning of s. 5 | 6 | Example 7 | Given s = "aab", return: 8 | 9 | [ 10 | ["aa","b"], 11 | ["a","a","b"] 12 | ] 13 | ''' 14 | class Solution: 15 | def partition(self, s): 16 | self.res = [] 17 | self.dfs(s, []) 18 | return self.res 19 | 20 | def dfs(self, s, stringlist): 21 | if not s: 22 | self.res.append(stringlist[:]) 23 | return 24 | 25 | for i in range(1, len(s) + 1): 26 | if self.isPalindrome(s[:i]): 27 | stringlist.append(s[:i]) 28 | self.dfs(s[i:], stringlist) 29 | stringlist.pop() 30 | 31 | def isPalindrome(self, s): 32 | for i in range(len(s) / 2): 33 | if s[i] != s[len(s) - 1 - i]: 34 | return False 35 | 36 | return True -------------------------------------------------------------------------------- /lecture_basic/Lecture9.Graph_Search/15. Permutations.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a list of numbers, return all possible permutations. 3 | 4 | Example 5 | For nums = [1,2,3], the permutations are: 6 | 7 | [ 8 | [1,2,3], 9 | [1,3,2], 10 | [2,1,3], 11 | [2,3,1], 12 | [3,1,2], 13 | [3,2,1] 14 | ] 15 | Challenge 16 | Do it without recursion. 17 | ''' 18 | class Solution: 19 | def permute(self, nums): 20 | if nums is None: 21 | return [] 22 | 23 | self.result = [] 24 | self.dfs(sorted(nums), []) 25 | return self.result 26 | 27 | def dfs(self, nums, seq): 28 | if not nums: 29 | self.result.append(seq[:]) 30 | return 31 | 32 | for i in range(len(nums)): 33 | if i > 0 and nums[i] == nums[i - 1]: 34 | continue 35 | 36 | seq.append(nums[i]) 37 | nums.pop(i) # delete element at index i 38 | self.dfs(nums, seq) 39 | nums.insert(i, nums[i]) # insert element at index i 40 | seq.pop() 41 | ''' 42 | 算法武器:排序(方便去重) + dfs深度优先搜索 + 递归 43 | 44 | 这道题目和subset的解题过程很类似,都是对于一个给定的nums集合,我们用for循环遍历一遍nums,对于每个遍历到的元素,我们都尝试将其加入到局部解中或者不加入局部解。两道题输出的解的个数都是相同的,都是2^n. 45 | 只不过两题使用的缩小递归子问题的规模的方式不同。subsets使用startIndex控制传入数组的有效作用范围,本题是直接传入一个更小的数组到子递归函数中,所以回溯也略有不同。 46 | ''' -------------------------------------------------------------------------------- /lecture_basic/Lecture9.Graph_Search/153. Combination Sum II.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. 3 | 4 | Each number in C may only be used once in the combination. 5 | 6 | Example 7 | Given candidate set [10,1,6,7,2,1,5] and target 8, 8 | 9 | A solution set is: 10 | 11 | [ 12 | [1,7], 13 | [1,2,5], 14 | [2,6], 15 | [1,1,6] 16 | ] 17 | ''' 18 | class Solution: 19 | def combinationSum2(self, candidates, target): 20 | self.result = [] 21 | self.dfs(sorted(candidates), target, 0, []) 22 | return self.result 23 | 24 | def dfs(self, candidates, target, start, valuelist): 25 | if target == 0: 26 | self.result.append(valuelist[:]) 27 | return 28 | 29 | for i in range(start, len(candidates)): 30 | if i > start and candidates[i] == candidates[i - 1]: 31 | continue 32 | 33 | if candidates[i] > target: 34 | return 35 | 36 | valuelist.append(candidate[i]) 37 | self.dfs(candidates, target - candidates[i], i + 1, valuelist) 38 | valuelist.pop() -------------------------------------------------------------------------------- /monos_tack/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonforce2010/interview-algothims/338d3bc2f2916c5c4936767b07b2fd22b4121049/monos_tack/readme.md -------------------------------------------------------------------------------- /monostack/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dragonforce2010/interview-algothims/338d3bc2f2916c5c4936767b07b2fd22b4121049/monostack/readme.md -------------------------------------------------------------------------------- /none_ladder/104. Merge K Sorted Lists.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Merge k sorted linked lists and return it as one sorted list. 3 | 4 | Analyze and describe its complexity. 5 | 6 | Example 7 | Given lists: 8 | 9 | [ 10 | 2->4->null, 11 | null, 12 | -1->null 13 | ], 14 | return -1->2->4->null. 15 | ''' 16 | """ 17 | Definition of ListNode 18 | class ListNode(object): 19 | 20 | def __init__(self, val, next=None): 21 | self.val = val 22 | self.next = next 23 | """ 24 | class Solution: 25 | """ 26 | @param lists: a list of ListNode 27 | @return: The head of one sorted list. 28 | """ 29 | def mergeKLists(self, lists): 30 | # write your code here 31 | if not lists: 32 | return None 33 | 34 | import heapq 35 | # 因为我们想要按照node.val的值进行排序,所以这里我们把node.val放在元组的第一个位置 36 | heap = [ (node.val, node) for node in lists if node] 37 | # 构建堆的过程中要尤为注意堆化的操作,如果我们初始化数组时,数组中额数据不止一个,那么我们就要使用 38 | # heapq的heapify()函数将当前堆进行堆化 39 | heapq.heapify(heap) 40 | 41 | dummyhead = cur = ListNode(0) 42 | while heap: 43 | val, node = heapq.heappop(heap) 44 | cur.next = node 45 | cur = cur.next 46 | if node.next: 47 | heapq.heappush(heap, (node.next.val, node.next)) 48 | 49 | return dummyhead.next 50 | -------------------------------------------------------------------------------- /none_ladder/134. LRU Cache.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set. 3 | 4 | get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. 5 | set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item. 6 | ''' -------------------------------------------------------------------------------- /none_ladder/138. Subarray Sum.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an integer array, find a subarray where the sum of numbers is zero. Your code should return the index of the first number and the index of the last number. 3 | 4 | Example 5 | Given [-3, 1, 2, -3, 4], return [0, 2] or [1, 3]. 6 | ''' 7 | class Solution: 8 | """ 9 | @param nums: A list of integers 10 | @return: A list of integers includes the index of the first number and the index of the last number 11 | """ 12 | def subarraySum(self, nums): 13 | # write your code here 14 | if not nums: 15 | return [] 16 | 17 | # 使用presum对当前[0, index]的前缀和进行计算 18 | # - 如果前缀和为0,这是一种特殊情况,我们直接返回[0, index],就不用查hashmap了 19 | # - 如果前缀和在hashmap中,那么我们就找到了两个有相同值得前缀和,根据推理,和为0的子区间就是[hashmap[presum] + 1, index] 20 | # 这个是基于公式presumeArr[i + 1, j] = presumArr[j] - presumArr[i] 21 | # 注意,上面的公式使用了前缀和数组,但本题比较简单我们不需要计算和保留前缀和数组(其实某种程度上也算是保留了,因为我们把前缀和都存在了hashmap中) 22 | # 本题直接使用滚动更新的前缀和presum来进行计算 23 | # - 如果我们没有在hashmap中找到前缀和,那么我就将当前前缀和推入到hashmap 24 | presum, hashmap = 0, {} 25 | for index, num in enumerate(nums): 26 | presum += num 27 | if presum == 0: 28 | return [0, index] 29 | 30 | if presum in hashmap: 31 | return [hashmap[presum] + 1, index] 32 | else: 33 | hashmap[presum] = index 34 | 35 | return [] -------------------------------------------------------------------------------- /none_ladder/156. Merge Intervals.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given a collection of intervals, merge all overlapping intervals. 3 | 4 | Example 5 | Given intervals => merged intervals: 6 | 7 | [ [ 8 | (1, 3), (1, 6), 9 | (2, 6), => (8, 10), 10 | (8, 10), (15, 18) 11 | (15, 18) ] 12 | ] 13 | Challenge 14 | O(n log n) time and O(1) extra space. 15 | ''' 16 | """ 17 | Definition of Interval. 18 | class Interval(object): 19 | def __init__(self, start, end): 20 | self.start = start 21 | self.end = end 22 | """ 23 | 24 | class Solution: 25 | """ 26 | @param intervals: interval list. 27 | @return: A new interval list. 28 | """ 29 | def merge(self, intervals): 30 | # write your code here 31 | if not intervals: 32 | return [] 33 | 34 | # 对区间进行排序 35 | sortedIntervals = sorted(intervals, key = lambda interval: interval.start) 36 | result = [] 37 | 38 | for interval in sortedIntervals: 39 | # 对于没有区间冲突的情形,只需单纯加入新区间 40 | if not result or result[-1].end < interval.start: 41 | result.append(interval) 42 | # 如果有区间冲突,该冲突会影响到上一个区间的end,需要对其更新 43 | # 不需要担心更新start,因为我们的区间是按start进行排序的 44 | else: 45 | result[-1].end = max(result[-1].end, interval.end) 46 | 47 | return result 48 | -------------------------------------------------------------------------------- /none_ladder/15_permutations.py: -------------------------------------------------------------------------------- 1 | '''Description: 2 | Given a list of numbers, return all possible permutations. 3 | 4 | Notice 5 | You can assume that there is no duplicate numbers in the list. 6 | 7 | Example 8 | For nums = [1,2,3], the permutations are: 9 | 10 | [ 11 | [1,2,3], 12 | [1,3,2], 13 | [2,1,3], 14 | [2,3,1], 15 | [3,1,2], 16 | [3,2,1] 17 | ] 18 | ''' 19 | 20 | class Solution: 21 | """ 22 | @param: nums: A list of integers. 23 | @return: A list of permutations. 24 | """ 25 | def permute(self, nums): 26 | # write your code here 27 | if not nums: 28 | return [[]] 29 | 30 | self.results = [] 31 | self.dfs(nums, []) 32 | return self.results 33 | 34 | # 定义:计算nums的全排列,使用seq数组保存局部结果,局部结果集满足一定条件将加入到最终结果集:self.results数组中 35 | # 遍历nums中的每一个元素,选择一个加入到seq之中,然后递归进行,直到nums数组为空 36 | def dfs(self, nums, seq): 37 | if not nums: 38 | # 将seq数组复制一份,放到全局结果集中 39 | self.results.append(seq[:]) 40 | return 41 | 42 | for i in range(len(nums)): 43 | ele = nums.pop(i) 44 | seq.append(ele) 45 | self.dfs(nums, seq) 46 | # 回溯过程,非常重要 47 | seq.pop() 48 | nums.insert(i, ele) 49 | 50 | 51 | '''Summary 52 | 算法武器:排序(方便去重) + dfs深度优先搜索 + 递归 53 | 这道题目和subset的解题过程很类似,都是对于一个给定的nums集合,我们用for循环遍历一遍nums,对于每个遍历到的元素,我们都尝试将其加入到局部解中或者不加入局部解。两道题输出的解的个数都是相同的,都是2^n. 54 | 只不过两题使用的缩小递归子问题的规模的方式不同。subsets使用startIndex控制传入数组的有效作用范围,本题是直接传入一个更小的数组到子递归函数中,所以回溯也略有不同。 55 | ''' 56 | -------------------------------------------------------------------------------- /none_ladder/3_Digit_Counts.py: -------------------------------------------------------------------------------- 1 | '''Description: 2 | Count the number of k's between 0 and n. k can be 0 - 9. 3 | 4 | Example 5 | if n = 12, k = 1 in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 6 | we have FIVE 1's (1, 10, 11, 12) 7 | ''' 8 | 9 | class Solution: 10 | """ 11 | @param: : An integer 12 | @param: : An integer 13 | @return: An integer denote the count of digit k in 1..n 14 | """ 15 | 16 | def digitCounts(self, k, n): 17 | # write your code here 18 | assert(n >= 0 and 0 <= k <= 9) 19 | count = 0 20 | for num in range(n + 1): 21 | digits = num 22 | # 对每个数字的每一位的遍历使用的是取余除10法 23 | while True: 24 | if digits % 10 == k: 25 | count += 1 26 | # /: 返回float类型数字 27 | # //: 返回整数 28 | digits //= 10 29 | if digits == 0: 30 | break 31 | 32 | return count -------------------------------------------------------------------------------- /none_ladder/41. Maximum Subarray.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array of integers, find a contiguous subarray which has the largest sum. 3 | 4 | Example 5 | Given the array [−2,2,−3,4,−1,2,1,−5,3], the contiguous subarray [4,−1,2,1] has the largest sum = 6. 6 | 7 | Challenge 8 | Can you do it in time complexity O(n)? 9 | ''' 10 | class Solution: 11 | """ 12 | @param nums: A list of integers 13 | @return: A integer indicate the sum of max subarray 14 | """ 15 | ''' 16 | 题型:求一个数组中的最小子区间和最大子区间问题 17 | 解法:可以使用滚动计算当前位置的presum,实时更新maxsum和 minPresum的方式求解 18 | 注意:初始化是一个关键,因为我们要求最小区间和,而根据前缀和计算公式: 19 | maxsum = presum - minPresum 20 | 我们的最大和区间可能是从0开始,所以minPresum需要初始化为0,才能包含这种情况 21 | maxsum一定是一个子区间,至少包含一个数,所以我们把maxsum初始化为nums[0] 22 | presum初始化为0 23 | ''' 24 | ''' 25 | def maxSubArray(self, nums): 26 | # write your code here 27 | if not nums: 28 | raise Exception("Input nums can not be None or Empty!") 29 | 30 | presum, maxsum, minPresum = 0, nums[0], 0 31 | for num in nums: 32 | presum += num 33 | maxsum = max(maxsum, presum - minPresum) 34 | minPresum = min(minPresum, presum) 35 | 36 | return maxsum 37 | 38 | 39 | -------------------------------------------------------------------------------- /none_ladder/44. Minimum Subarray.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given an array of integers, find the subarray with smallest sum. 3 | 4 | Return the sum of the subarray. 5 | 6 | Example 7 | For [1, -1, -2, 1], return -3. 8 | ''' 9 | class Solution: 10 | """ 11 | @param: nums: a list of integers 12 | @return: A integer indicate the sum of minimum subarray 13 | """ 14 | ''' 15 | 题型:求一个数组中的最小子区间和最大子区间问题 16 | 解法:可以使用滚动计算当前位置的presum,实时更新maxpresum 和 minsum的方式求解 17 | 注意:初始化是一个关键,因为我们要求最小区间和,而根据前缀和计算公式: 18 | minsum = presum - maxpresum 19 | 我们的最小和区间可能是从0开始,所以maxpresum需要初始化为0,才能包含这种情况 20 | minsum一定是一个子区间,至少包含一个数,所以我们把minsum初始化为nums[0] 21 | presum初始化为0 22 | ''' 23 | def minSubArray(self, nums): 24 | # write your code here 25 | if not nums: 26 | return 0 27 | 28 | presum, maxsum, minsum = 0, 0, nums[0] 29 | for num in nums: 30 | presum += num 31 | minsum = min(minsum, presum - maxsum) 32 | maxsum = max(maxsum, presum) 33 | 34 | return minsum -------------------------------------------------------------------------------- /none_ladder/545. Top k Largest Numbers II.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Implement a data structure, provide two interfaces: 3 | 4 | add(number). Add a new number in the data structure. 5 | topk(). Return the top k largest numbers in this data structure. k is given when we create the data structure. 6 | Example 7 | s = new Solution(3); 8 | >> create a new data structure. 9 | s.add(3) 10 | s.add(10) 11 | s.topk() 12 | >> return [10, 3] 13 | s.add(1000) 14 | s.add(-99) 15 | s.topk() 16 | >> return [1000, 10, 3] 17 | s.add(4) 18 | s.topk() 19 | >> return [1000, 10, 4] 20 | s.add(100) 21 | s.topk() 22 | >> return [1000, 100, 10] 23 | ''' 24 | import heapq 25 | class Solution: 26 | """ 27 | @param: k: An integer 28 | """ 29 | def __init__(self, k): 30 | # do intialization if necessary 31 | self.k = k 32 | self.heap = [] 33 | 34 | """ 35 | @param: num: Number to be added 36 | @return: nothing 37 | """ 38 | # 维护一个大小为k的堆,这样堆定元素就是我们要求的topk 39 | def add(self, num): 40 | # write your code here 41 | if len(self.heap) < self.k: 42 | heapq.heappush(self.heap, num) 43 | return 44 | 45 | if self.heap and num > self.heap[0]: 46 | heapq.heappush(self.heap, num) 47 | heapq.heappop(self.heap) 48 | 49 | 50 | """ 51 | @return: Top k element 52 | """ 53 | def topk(self): 54 | # write your code here 55 | return sorted(self.heap, reverse=True) 56 | -------------------------------------------------------------------------------- /none_ladder/56_towsum.py: -------------------------------------------------------------------------------- 1 | '''Summary 2 | Given an array of integers, find two numbers such that they add up to a specific target number. 3 | 4 | The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are zero-based. 5 | 6 | Notice 7 | You may assume that each input would have exactly one solution 8 | ''' 9 | class Solution: 10 | """ 11 | @param numbers: An array of Integer 12 | @param target: target = numbers[index1] + numbers[index2] 13 | @return: [index1 + 1, index2 + 1] (index1 < index2) 14 | """ 15 | def twoSum(self, numbers, target): 16 | # write your code here 17 | if not numbers: 18 | return [-1, -1] 19 | 20 | myhash = {} 21 | for index, num in enumerate(numbers): 22 | if target - num in myhash: 23 | return [myhash[target - num], index] 24 | 25 | myhash[num] = index 26 | 27 | return [-1, -1] 28 | 29 | '''Summary 30 | 算法武器:哈希表 31 | ''' -------------------------------------------------------------------------------- /none_ladder/5_kth_largest_element.py: -------------------------------------------------------------------------------- 1 | '''Description: 2 | Find K-th largest element in an array. 3 | 4 | Notice 5 | You can swap elements in the array 6 | ''' 7 | 8 | 9 | import heapq 10 | 11 | class Solution: 12 | # @param k & A a integer and an array 13 | # @return ans a integer 14 | def kthLargestElement(self, k, A): 15 | if k <= 0: 16 | raise Exception('Invalid parameter! k should be > 0') 17 | 18 | heap = [] 19 | for ele in A: 20 | heapq.heappush(heap, ele) 21 | if len(heap) > k: 22 | heapq.heappop(heap) 23 | 24 | 25 | return heapq.heappop(heap) #return heap[0] -------------------------------------------------------------------------------- /none_ladder/659_string_serialization.py: -------------------------------------------------------------------------------- 1 | '''Descript 2 | Design an algorithm to encode a list of strings to a string. The encoded string is then sent over the network and is decoded back to the original list of strings. 3 | Please implement encode and decode 4 | ''' 5 | 6 | class Solution: 7 | """ 8 | @param: strs: a list of strings 9 | @return: encodes a list of strings to a single string. 10 | """ 11 | def encode(self, strs): 12 | # write your code here 13 | return ''.join(['%d$%s' % (len(word), word) for word in strs]) 14 | 15 | """ 16 | @param: str: A string 17 | @return: dcodes a single string to a list of strings 18 | """ 19 | def decode(self, s): 20 | # write your code here 21 | result, start = [], 0 22 | while start < len(s): 23 | index = s.find('$', start) 24 | word_length = int(s[start:index]) 25 | start = index + 1 + word_length 26 | result.append(s[index + 1:start]) 27 | 28 | return result 29 | 30 | solution = Solution() 31 | encoded_string = solution.encode(['I', 'love', 'lint', 'code']) 32 | decoded_str_arr = solution.decode(encoded_string) 33 | 34 | 35 | '''Summary 36 | 掌握python的string操作函数 37 | ''.join('%d$' % len(s) + s for s in strs) 38 | s.find('$', i) 39 | 40 | 掌握字符串编码和解码的基本方法 41 | 编解码的重要作用是能够区分传输的每个单词 42 | 43 | 本题使用的是通过编码长度和编码标记$符号来完成编码,通过编码标记能够找到编码长度,通过编码长度能够正确取出编码的字符。 44 | 注:即使编码单词中含有编码标记也没有关系,因为编码长度能够帮我们取到正确的编码单词,同时我们在下一次寻找编码标记$时,我们会跳过已经找过的单词,这样单词的内容就不会影响我们的解码 45 | ''' 46 | -------------------------------------------------------------------------------- /other/string_xor.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def sxor(self, str1, str2): 3 | if not str1 or not str2: 4 | return None 5 | 6 | return ''.join([(a + b) if (ord(a) ^ ord(b)) else '' for a, b in zip(str1, str2)]) 7 | 8 | def sxor2(self, str1): 9 | if not str1: 10 | return None 11 | 12 | 13 | 14 | '''Test''' 15 | solution = Solution() 16 | result = solution.sxor('abbc', 'abbc') 17 | print(result) --------------------------------------------------------------------------------