├── .classpath
├── .gitignore
├── .project
├── LICENSE
├── README.md
├── bash
├── 192_word_count.sh
└── 192_words.txt
├── c_plus_plus
├── findPeakElement.cpp
└── rotateImage.cpp
├── input
└── IntegerArray.txt
├── java
├── 130_Surrounded_Regions.java
├── 332_Reconstruct_Itinerary.java
├── 431_Encode_n-ary-Tree_to_Binary_Tree.java
├── Anagram.java
├── Atoi.java
├── BSTIterator.java
├── BinaryTree.java
├── BitOps.java
├── BucketSort.java
├── BuyAndSellStock.java
├── Candy.java
├── ClimbStairs.java
├── CloneGraph.java
├── Combination.java
├── CombinationSum.java
├── CopyRandomList.java
├── CountInversion.java
├── CourseSchedule.java
├── DungeonGame.java
├── EvaluateNotation.java
├── FactorialTrailingZeros.java
├── FindMedianFromDataStream_295.java
├── FindPeakElement.java
├── GameOfLife.java
├── GasStation.java
├── GenerateParenthese.java
├── GreyCode.java
├── HammingWeight.java
├── Histogram.java
├── InsertionSort.java
├── IntegerOps.java
├── Interval.java
├── JumpGame.java
├── JumpGameIV_1345.java
├── LRUCache.java
├── LargestNumber.java
├── LinkedListCycle.java
├── LinkedListDuplicate.java
├── LinkedListIntersection.java
├── ListNode.java
├── LongestCommonPrefix.java
├── LongestConsecutiveSequence.java
├── LongestSubstring.java
├── MajorityElement.java
├── MatrixSearch.java
├── MaxPoints.java
├── MaximalRectangle.java
├── MaximumGap.java
├── MaximumSubarray.java
├── MedianFinder.java
├── MergeIntervals.java
├── MergeKSortedList.java
├── MergeSort.java
├── MergeTwoLists.java
├── MinStack.java
├── MissingPositive.java
├── NQueen.java
├── NetworkDelayTime_743.java
├── NextPermutation.java
├── NimGame.java
├── NumberOfBST.java
├── Palindrome.java
├── PartitionList.java
├── PascalTriangle.java
├── PathSum.java
├── PeekingIterator.java
├── PermutationsII.java
├── PlusOne.java
├── Pow.java
├── QuickSort.java
├── RadixSort.java
├── RandomListNode.java
├── RemoveDuplicates.java
├── RemoveNthNode.java
├── ReorderList.java
├── ReverseLinkedList.java
├── ReverseWords.java
├── RotateList.java
├── RotatedArray.java
├── SearchRange.java
├── SingleNumber.java
├── SortColor.java
├── StackOps.java
├── StrStr.java
├── Subsequences.java
├── Subsets.java
├── SubstringOps.java
├── Sudoku.java
├── Sum.java
├── SurroundedRegion.java
├── SwapNodes.java
├── TextJustification.java
├── TreeNode.java
├── Triangle.java
├── TwoSum.java
├── UndirectedGraphNode.java
├── UniquePath.java
├── Utils.java
├── ValidNumber.java
├── WildcardMatching.java
└── WordBreak.java
└── python
├── 1009_complement_of_base_10_integer.py
├── 1010_combination_sum_divisible_by_60.py
├── 1011_minimal_capacity_to_ship_packages_in_D_days.py
├── 1013_partition_array_into_three_parts_with_equal_sum.py
├── 101_symmetric_tree.py
├── 1020_Number_of_Enclaves.py
├── 1021_remove_outermost_parentheses.py
├── 1026_Maximum_Difference_Between_Node_and_Ancestor.py
├── 102_binary_tree_BFS.py
├── 103_binary_zigzag_level_traversal.py
├── 1046_Last_Stone_Weight.py
├── 1047_remove_all_adjacent_duplicates_in_string.py
├── 1055_shortest_way_to_form_string.py
├── 1057_campus_bikes.py
├── 1060_missing_element_in_sorted_array.py
├── 1061_lexicographically_smallest_equivalent_string.py
├── 1066_campus_bikes_II.py
├── 1073_add_two_negabinary_numbers.py
├── 1081_Smallest_Subsequence_of_Distinct_Letters.py
├── 1087_brace_expansion.py
├── 1091_shortest_path_in_binary_matrix.py
├── 1093_statistics_from_a_large_sample.py
├── 1094_car_pooling.py
├── 1100_find_k-length_substrings_with_no_repeated_characters.py
├── 1101_earliest_moment_when_everyone_becomes_friends.py
├── 110_Balanced_Binary_Tree.py
├── 1114_Print_in_Order.py
├── 1120_maximum_average_subtree.py
├── 1135_connecting_cities_with_minimal_cost.py
├── 1150_check_majority_element_in_sorted_array.py
├── 1151_minimal_swaps_to_group_all_ones_together.py
├── 1155_number_of_dice_rolls_with_target_sum.py
├── 1162_as_far_from_land_as_possible.py
├── 1166_design_file_system.py
├── 1167_minimum_costs_to_connect_sticks.py
├── 1168_optimize_water_distribution_in_a_village.py
├── 116_populate_next_right_pointers.py
├── 1178_number_of_valid_words_in_each_puzzle.py
├── 1197_minimum_knight_moves.py
├── 1198_find_smallest_common_element_in_all_rows.py
├── 11_container_with_most_water.py
├── 1202_smallest_strings_with_swaps.py
├── 1209_remove_all_adjacent_duplicates_in_a_string_II.py
├── 1239_max_length_of_concatenated_string_with_unique_characters.py
├── 1249_minimum_remove_to_make_valid_parentheses.py
├── 1254_number_of_closed_islands.py
├── 1257_smallest_common_region.py
├── 1261_Find_Elements_in_Contaminated_Binary_Tree.py
├── 1288_remove_covered_intervals.py
├── 1293_shortest_path_in_grid_with_obstacles_elimination.py
├── 129_sum_root_to_leaf_numbers.py
├── 1302_deepest_leaves_sum.py
├── 1306_jump_game_III.py
├── 131_palindrome_partition.py
├── 1325_delete_leaves_nodes_with_a_given_value.py
├── 1328_break_a_palindrome.py
├── 132_Palindrome_Partition_II.py
├── 1345_Jump_Game_IV.py
├── 1353_maximum_number_of_events_that_can_be_attended.py
├── 1366_rank_teams_by_votes.py
├── 1372_longest_zigzag_path.py
├── 1376_time_needed_to_inform_all_employee.py
├── 1383_maximum_performance_of_team.py
├── 139_Word_Break.py
├── 140_Word_Break_II.py
├── 141_linked_list_cycle.py
├── 1420_build_arrays.py
├── 1439_find_kth_smallest_sum_of_matrix_with_sorted_row.py
├── 1448_count_good_nodes_in_binary_tree.py
├── 1456_maximum_number_of_vowels_in_a_substring_of_given_length.py
├── 145_binary_tree_postorder_traversal.py
├── 1469_Find_All_Lonely_Nodes.py
├── 147_Insertion_Sort_List.py
├── 148_sort_list.py
├── 1490_clone_N_ary_tree.py
├── 14_longest_common_prefix.py
├── 1506_find_root_of_N-ary_tree.py
├── 1508_range_sum_of_sorted_subarray_sums.py
├── 1510_Stone_Game_IV.py
├── 151_find_minimum_in_rotated_sorted_array.py
├── 1522_diameter_of_N-ary_tree.py
├── 152_Maximum_Product_Subarray.py
├── 1539_Kth_Missing_Positive_Number.py
├── 154_Find_Minimum_in_Rotated_Sorted_Array_II.py
├── 1559_detect_cycles_in_2D_grid.py
├── 1570_dot_product_of_two_sparse_vectors.py
├── 161_one_edit_distance.py
├── 1626_best_team_with_no_conflicts.py
├── 1631_path_with_minimal_efforts.py
├── 163_missing_ranges.py
├── 1650_lowest_common_ancestor_of_a_binary_tree_III.py
├── 1658_Maximum_Operations_to_Reduce_X_to_Zero.py
├── 165_compare_version_number.py
├── 1676_lowest_common_ancestor_for_multiple_nodes.py
├── 169_major_element.py
├── 1701_average_waiting_time.py
├── 170_Two_Sum_III_data_structure.py
├── 1710_maximum_capacity_on_truck.py
├── 1721_swapping_nodes_in_a_linked_list.py
├── 1722_minimum_hamming_distance_after_swapping_operations.py
├── 1730_shortest_path_to_get_food.py
├── 174_dungeon_game.py
├── 1751_maximum_number_of_events_that_can_be_attended_II.py
├── 1754_largest_merge_of_two_strings.py
├── 1759_count_number_of_homogenous_substrings.py
├── 176_Excel_Sheet_Column_Number.py
├── 17_letter_combination_of_a_phone_number.py
├── 1804_implement_trie_II.py
├── 189_Rotate_Array.py
├── 1953_maximum_number_of_weeks_for_which_you_can_work.py
├── 198_House_Robber.py
├── 199_Binary_Tree_with_Right_Side_View.py
├── 19_remove_nth_node_from_end_of_list.py
├── 1_two_sum.py
├── 200_Number_Of_Islands.py
├── 2034_stock_price_fluctuation.py
├── 206_reverse_linked_list.py
├── 2073_time_needed_to_buy_tickets.py
├── 207_course_schedule.py
├── 208_Implement_Trie_(Prefix_Tree).py
├── 20_Valid_Parentheses.py
├── 211_Add_and_Search_Word.py
├── 212_Word_Search_II.py
├── 215_kth_largest_element.py
├── 216_combination_sum_III.py
├── 220_Contains_Duplicates_III.py
├── 221_maximal_square.py
├── 224_basic_calculator.py
├── 227_Basic_Calculator_II.py
├── 228_summary_range.py
├── 229_major_elements_II.py
├── 229_minimum_size_subarray_sum.py
├── 230_kth_smallest_element_in_BST.py
├── 235_lowest_common_ancestor_in_a_binary_search_tree.py
├── 236_lowest_common_ancestor_of_a_binary_tree_no_parent_pointer.py
├── 238_product_of_array_except_self.py
├── 242_valid_anagrams.py
├── 249_group_shifted_strings.py
├── 252_meeting_room.py
├── 253_meeting_rooms_II.py
├── 257_binary_tree_paths.py
├── 261_graph_valid_tree.py
├── 265_paint_houses_II.py
├── 266_Palindrome_Permutation.py
├── 267_Palindrome_Permutations_II.py
├── 270_closest_binary_search_tree_value.py
├── 276_Paint_Fence.py
├── 279_perfect_squares.py
├── 283_move_zeroes.py
├── 285_Inorder_Successor_in_BST.py
├── 286_walls_and_gates.py
├── 289_game_of_life.py
├── 295_Find_Median_From_Data_Stream.py
├── 300_Longest_Increasing_Subsequence.py
├── 301_remove_invalid_parentheses.py
├── 306_Additive_Number.py
├── 309_Buy_and_Sell_Stock_with_Cooldown.py
├── 310_minimum_height_tree.py
├── 311_Sparse_Matrix_Multiplication.py
├── 314_binary_tree_vertical_order_traversal.py
├── 317_shortest_distance_from_all_buildings.py
├── 31_next_permutation.py
├── 320_Generalized_Abbreviation.py
├── 322_coin_change.py
├── 323_number_of_connected_components_in_graph.py
├── 325_maximum_size_subarray_sum_equals_K.py
├── 329_longest_increasing_path_in_matrix.py
├── 332_Reconstruct_Itinerary.py
├── 333_largest_BST_size.py
├── 337_house_robber_III.py
├── 339_Nest_List_Weight_Sum.py
├── 342_power_of_four.py
├── 345_reverse_vowels_of_string.py
├── 346_moving_average_from_data_stream.py
├── 347_Top_K_Frequent_Elements.py
├── 350_intersection_of_two_arrays_II.py
├── 353_design_snake_game.py
├── 359_logger_rate_limiter.py
├── 361_bomb_enemy.py
├── 364_Nested_List_Weight_Sum_II.py
├── 366_Find_Leaves_of_Binary_Tree.py
├── 367_valid_perfect_square.py
├── 370_range_addition.py
├── 375_Guess_Higher_or_Lower_Number_II.py
├── 377_combination_sum_IV.py
├── 382_Linked_List_Random_Node.py
├── 383_ransom_note.py
├── 384_Shuffle_Array.py
├── 38_count_and_say.py
├── 392_Is_Subsequence.py
├── 399_evaluate_division.py
├── 39_combination_sum.py
├── 402_Remove_K_Digits.py
├── 404_sum_of_left_leaves.py
├── 415_add_strings.py
├── 416_partition_equal_subset_sum.py
├── 419_battleships_in_a_board.py
├── 425_word_squares.py
├── 426_convert_binary_search_tree_to_sorted_doubly_linked_list.py
├── 42_trapping_rain_water.py
├── 430_flatten_multilevel_doubly_linked_list.py
├── 431_encode_n-ary-tree_to_binary_tree.py
├── 435_non_overlapping_intervals.py
├── 437_Path_Sum_III.py
├── 442_find_duplicates_in_an_array.py
├── 450_delete_node_in_BST.py
├── 452_minimal_number_of_arrows_to_burst_ballons.py
├── 456_132_pattern.py
├── 458_poor_pigs.py
├── 45_Jump_Game_II.py
├── 461_hamming_distance.py
├── 463_Island_Perimeter.py
├── 46_permutations.py
├── 470_implement_rand10_using_rand7.py
├── 47_permutations.py
├── 480_sliding_window_median.py
├── 490_The_Maze.py
├── 497_random_point_in_non-overlapping_rectangles.py
├── 513_find_bottom_left_tree_value.py
├── 516_longest_palindromic_subsequence.py
├── 518_coin_change_II.py
├── 523_Continuous_Subarray_Sum.py
├── 524_longest_word_in_a_dictionary_through_deleting.py
├── 526_beautiful_arrangement.py
├── 528_random_pick_with_weight.py
├── 530_min_absolute_difference_in_BST.py
├── 536_construct_binary_tree_from_string.py
├── 539_minimum_time_difference.py
├── 53_Maximum_Subarray.py
├── 542_01_matrix.py
├── 543_diameter_of_binary_tree.py
├── 547_number_of_provinces.py
├── 559_maximum_depth_N-ary_tree.py
├── 560_subarray_sum_equals_K.py
├── 562_longest_line_of_consecutive_one_in_a_matrix.py
├── 565_Nesting_Array.py
├── 56_merge_intervals.py
├── 572_subtree_of_another_tree.py
├── 583_delete_operation_for_two_strings.py
├── 593_valid_square.py
├── 5_longest_palindromic_substring.py
├── 606_constructing_string_from_binary_tree.py
├── 611_valid_triangle_number.py
├── 621_task_scheduler.py
├── 622_Design_Circular_Queue.py
├── 628_maximum_product_of_three_numbers.py
├── 637_average_of_levels_in_binary_tree.py
├── 641_Design_Circular_Deque.py
├── 647_palindromic_substrings.py
├── 648_replace_words.py
├── 64_minimum_path_sum.py
├── 652_find_duplicated_subtrees.py
├── 664_Strange_Printer.py
├── 667_Beautiful_Arrangements_II.py
├── 669_Trim_Binary_Search_Tree.py
├── 670_maximum_swap.py
├── 676_implement_magic_dictionary.py
├── 680_valid_palindrome_II.py
├── 684_Redundant_Connection.py
├── 696_count_binary_substrings.py
├── 697_degree_of_array.py
├── 698_Partition_To_K_Equal_Sum_Subsets.py
├── 69_sqrt.py
├── 701_Insert_into_a_Binary_Search_Tree.py
├── 705_design_hashset.py
├── 708_Insert_into_cyclic_sorted_list.py
├── 713_Subarray_Product_Less_Than_K.py
├── 718_maximum_length_repeated_subarray.py
├── 71_simplify_path.py
├── 720_longest_word_in_dictionary.py
├── 721_accounts_merge.py
├── 72_edit_distance.py
├── 735_asteroids_collision.py
├── 739_daily_temperatures.py
├── 73_set_matrix_zeroes.py
├── 743_Network_Delay_Time.py
├── 763_Partition_Labels.py
├── 767_reorganize_string.py
├── 772_basic_calculator_III.py
├── 774_Minimize_Maximum_Distance_to_Gas_Station.py
├── 783_min_difference_between_BST_nodes.py
├── 784_letter_case_permutation.py
├── 785_is_graph_bipartite.py
├── 787_Cheapest_Flights_within_K_stops.py
├── 78_subsets.py
├── 791_custom_sort_string.py
├── 792_number_of_matching_subsequence.py
├── 796_ratate_string.py
├── 79_Word_Search.py
├── 81_search_in_rotated_sorted_array_II.py
├── 821_shorest_distance_to_a_character.py
├── 826_most_profit_assign_work.py
├── 835_Image_Overlap.py
├── 841_rooms_and_keys.py
├── 844_backspace_string_compare.py
├── 849_maximize_distance_to_closest_person.py
├── 863_All_Nodes_Distance_K_in_Binary_Tree.py
├── 867_transpose_matrix.py
├── 897_Increasing_Order_Search_Tree.py
├── 89_gray_code.py
├── 905_sort_by_parity.py
├── 91_decode_ways.py
├── 921_minimal_add_to_make_parentheses_valid.py
├── 925_long_pressed_name.py
├── 92_reverse_linked_list_II.py
├── 931_minimum_falling_path_sum.py
├── 933_number_of_recent_calls.py
├── 938_range_sum_of_BST.py
├── 946_validate_stack_sequences.py
├── 949_Lagest_Time_for_Given_Digits.py
├── 94_binary_tree_inorder_traversal.py
├── 952_Largest_Component_Size_By_Common_Factor.py
├── 953_verifying_an_alien_dictionary.py
├── 956_tallest_billboard.py
├── 957_Prison_Cells_After_N_Days.py
├── 95_uniqueBST.py
├── 967_Numbers_With_Same_Consecutive_Differences.py
├── 969_pancake_sorting.py
├── 96_numberOfUniqueBST.py
├── 973_k_closest_points_to_origin.py
├── 974_Subarray_Sums_Divisable_by_K.py
├── 977_squares_of_a_sorted_array.py
├── 980_Unique_Paths_III.py
├── 981_time_based_key-value_store.py
├── 983_minimum_costs_for_tickets.py
├── 990_satisfiability_of_equality_equations.py
├── 994_rotting_oranges.py
├── 99_recovery_binary_search_tree.py
├── Search.py
├── SearchInsert.py
├── findPeakElement.py
├── insert_digit_5.py
├── lengthOfLongestSubstring.py
├── minimal_coin_changes.py
├── rotateMatrix.py
└── searchMatrix.py
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .gitignore
3 |
4 | /bin/
5 |
6 | *.class
7 |
8 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | LeetCode
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Lisong
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LeetCode Solutions #
2 |
3 | This is a project that I created to attempt some solutions for the questions on the LeetCode site.
4 | At the beginning, most of my solutions are coded in Java, though nowadays more and more are implemented in Python.
5 |
6 |
7 | ### Organization ###
8 |
9 | * A source file corresponds to a single question, which can contain several solutions.
10 |
11 | * In some cases, I aggregated several solutions into a single file to several questions that share the same context or spirit.
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/bash/192_word_count.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cat 192_words.txt | perl -pe 's/\\n//g' | perl -pe 's/\s+/\n/g' | sed '/^$/d' | sort | uniq -c | sort -k2 -n -r |awk '{print $2" "$1}'
4 |
5 |
6 | ## Breakdown of commands
7 |
8 | # 1. first perl, remove the '\n' strings
9 | # 2. second perl, replace the space with newline
10 | # 3. sed remove the empty lines
11 | # 4. sort the words
12 | # 5. uniq count the repeated words in adjacent lines
13 | # 6. sort the word counts
14 | # 7. print with format
15 |
16 |
17 |
--------------------------------------------------------------------------------
/bash/192_words.txt:
--------------------------------------------------------------------------------
1 | a a b
2 |
--------------------------------------------------------------------------------
/c_plus_plus/findPeakElement.cpp:
--------------------------------------------------------------------------------
1 | /**
2 |
3 | A peak element is an element that is greater than its neighbors.
4 |
5 | Given an input array nums, where nums[i] ≠ nums[i+1],
6 | find a peak element and return its index.
7 |
8 | The array may contain multiple peaks, in that case return the index
9 | to any one of the peaks is fine.
10 |
11 | You may imagine that nums[-1] = nums[n] = -∞.
12 |
13 | @author: Lisong Guo
21 | #include
22 | using namespace std;
23 |
24 | class Solution {
25 | public:
26 | int findPeakElement(vector& nums) {
27 |
28 | int low = 0, high = nums.size()-1;
29 |
30 | if(high == -1){
31 | // empty list
32 | return -1;
33 | }
34 |
35 | while(low < high){
36 | int mid = (low + high)/2;
37 | if(nums[mid] > nums[mid+1]){
38 | high = mid;
39 | } else {
40 | low = mid + 1;
41 | }
42 | }
43 |
44 | return low;
45 | }
46 | };
47 |
48 | int main(){
49 | Solution * s = new Solution();
50 |
51 | int a [] = {1,2,3,1};
52 | std::vector nums (a, a+sizeof(a)/sizeof(*a));
53 |
54 | cout << s->findPeakElement(nums) << endl;
55 |
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/java/Atoi.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | *
4 | * Convert a string that represents a decimal number to an integer.
5 | *
6 | * Note: overflow isse
7 | *
8 | * @author Lisong Guo
9 | * @date Dec 30, 2014
10 | *
11 | */
12 |
13 | public class Atoi {
14 | private static int maxDiv10 = Integer.MAX_VALUE/10;
15 |
16 | public int atoi(String s){
17 | int num = 0;
18 | int i = 0;
19 | boolean isPos = true;
20 |
21 | while(s.charAt(i) == ' ') ++i;
22 |
23 | if(s.charAt(i) == '-') isPos = false;
24 |
25 | while(i < s.length()){
26 | int digit = s.charAt(i) - '0';
27 |
28 | if(0 <= digit && digit <= 9){
29 | // overflow check
30 | if(num > maxDiv10 || (num == maxDiv10 && digit >= 8)){
31 | return isPos ? Integer.MAX_VALUE : Integer.MIN_VALUE;
32 | }
33 |
34 | num = num * 10 + digit;
35 | }
36 |
37 | ++i;
38 | }
39 |
40 | return isPos ? num : -num;
41 | }
42 |
43 |
44 | public static void main(String[] args) {
45 | String s = "-13333323";
46 | Atoi solution = new Atoi();
47 |
48 | System.out.println(solution.atoi(s));
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/java/ClimbStairs.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | *
4 | You are climbing a stair case. It takes n steps to reach to the top.
5 |
6 | Each time you can either climb 1 or 2 steps.
7 |
8 | In how many distinct ways can you climb to the top?
9 |
10 | * @author Lisong Guo
11 | * @date Nov 22, 2014
12 | *
13 | */
14 | public class ClimbStairs {
15 |
16 | /**
17 | * 1 2
18 | * 1 2 3
19 | * 1 2 3 5
20 | * @param n
21 | * @return
22 | */
23 | public int climbStairs(int n) {
24 | if(n <= 0) return 0;
25 |
26 | if(n == 1) return 1;
27 | if(n == 2) return 2;
28 |
29 | int one_step_before = 1;
30 | int two_steps_before = 2;
31 | int all_ways = 0;
32 |
33 | // basically, it becomes fibonacci...
34 | for(int i=2; i
18 | * @date Jan 15, 2015
19 | *
20 | */
21 | public class FindPeakElement {
22 |
23 | public int findPeakElement(int[] num) {
24 | int low=0, high=num.length, mid = 0;
25 |
26 | while(low < high){
27 | mid = (low+high)/2;
28 |
29 | if(num[mid] > num[mid-1]){
30 |
31 | }
32 | }
33 |
34 | return mid;
35 | }
36 |
37 | public static void main(String[] args) {
38 |
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/java/HammingWeight.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | *
4 | * @author Lisong Guo
5 | * @date Mar 15, 2015
6 | */
7 | public class HammingWeight {
8 |
9 | // you need to treat n as an unsigned value
10 | public int hammingWeight(int n) {
11 | int c = 0;
12 | int mask = 1;
13 |
14 | while (n != 0) {
15 | if ((n & mask) == 1) {
16 | ++c;
17 | }
18 | //Should use the logical shift >>>,
19 | // instead of arithmetic shift >>, which puts 1 for left most bit,
20 | // if the number is negative.
21 | n >>>= 1;
22 | }
23 |
24 | return c;
25 | }
26 |
27 | public static void main(String[] args) {
28 | //int n = 2147483648;
29 | int n = 1;
30 | HammingWeight hw = new HammingWeight();
31 |
32 | System.out.println(hw.hammingWeight(n));
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/java/IntegerOps.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Integer operations
4 | *
5 | * @author Lisong Guo
6 | * @date Dec 09, 2014
7 | *
8 | */
9 | public class IntegerOps {
10 |
11 | /**
12 | *
13 | * Reverse digits of an integer.
14 |
15 | Example1: x = 123, return 321
16 | Example2: x = -123, return -321
17 |
18 | * @return
19 | */
20 | public int reverse(int x) {
21 | long newInt = 0;
22 |
23 | while(x != 0){
24 | int digit = x % 10;
25 |
26 | if(newInt != 0){
27 | newInt *= 10;
28 | if(newInt > Integer.MAX_VALUE)
29 | return 0; // overflow;
30 | else if(newInt < Integer.MIN_VALUE)
31 | return 0; // underflow;
32 | }
33 |
34 | newInt += digit;
35 | x = x / 10;
36 | }
37 |
38 | return (int)newInt;
39 | }
40 |
41 | /**
42 | * @param args
43 | */
44 | public static void main(String[] args) {
45 | //int x = 1534236469; // overflow test case
46 | int x = -2147483648; // underflow test case
47 |
48 | IntegerOps solution = new IntegerOps();
49 |
50 | System.out.println(solution.reverse(x));
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/java/Interval.java:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | /** Definition for an interval.
5 | *
6 | */
7 |
8 | public class Interval {
9 | int start;
10 | int end;
11 |
12 | Interval() {
13 | start = 0;
14 | end = 0;
15 | }
16 |
17 | Interval(int s, int e) {
18 | start = s;
19 | end = e;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/java/ListNode.java:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | /**
5 | *
6 | * Definition for singly-linked list.
7 | *
8 | */
9 | public class ListNode {
10 | int val;
11 | ListNode next;
12 |
13 | ListNode(int x) {
14 | val = x;
15 | next = null;
16 | }
17 |
18 |
19 | /**
20 | * Reverse a linked list in place
21 | *
22 | * 1 -> 2 -> 3 -> NULL
23 | * 3 -> 2 -> 1 -> NULL
24 | *
25 | * @param head
26 | * @return
27 | */
28 | public static ListNode reverse(ListNode head){
29 | ListNode preIter = head, postIter = null;
30 | if(preIter == null)
31 | return null;
32 |
33 | postIter = preIter.next;
34 |
35 | while(postIter != null){
36 | ListNode nextIter = postIter.next;
37 | postIter.next = preIter; // reverse the link
38 |
39 | // move on
40 | preIter = postIter;
41 | postIter = nextIter;
42 | }
43 |
44 | head.next = null; // end the list
45 | return preIter;
46 | }
47 |
48 | }
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/java/LongestCommonPrefix.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | *
4 | * Write a function to find the longest common prefix string amongst an array of strings.
5 | *
6 | * @author Lisong Guo
7 | * @date Jan 1, 2015
8 | *
9 | */
10 | public class LongestCommonPrefix {
11 |
12 | public String longestCommonPrefix(String[] strs) {
13 | if(strs == null || strs.length == 0){
14 | return "";
15 | }
16 |
17 | int minLen = Integer.MAX_VALUE;
18 | for(String str : strs){
19 | minLen = Math.min(minLen, str.length());
20 | }
21 |
22 | boolean isFound = false;
23 | int pc = 0;
24 |
25 | while(! isFound && pc < minLen){
26 |
27 | int c = strs[0].charAt(pc);
28 |
29 | for(int i=1; i
11 | * @date Dec 24, 2014
12 | *
13 | */
14 | public class MajorityElement {
15 |
16 |
17 | public int majorityElement(int[] num) {
18 | if(num == null || num.length == 0)
19 | return 0;
20 |
21 | int count = 1;
22 | int iter = num[0];
23 | int N = num.length;
24 |
25 | for(int i=1; i N/2)
40 | return iter; // early exit. Good for the performance.
41 | }
42 |
43 | return iter;
44 | }
45 |
46 |
47 | public static void main(String[] args) {
48 | int [] num = {2, 2, 1, 1, 1, 1};
49 |
50 | MajorityElement solution = new MajorityElement();
51 |
52 | System.out.println(solution.majorityElement(num));
53 | }
54 |
55 | }
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/java/MaxPoints.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Given n points on a 2D plane,
4 | * find the maximum number of points that lie on the same straight line.
5 | *
6 | * @author Lisong Guo
7 | * @date Jan 12, 2014
8 | *
9 | */
10 | public class MaxPoints {
11 |
12 |
13 | public static void main(String[] args) {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/java/MaximumGap.java:
--------------------------------------------------------------------------------
1 | import java.util.Arrays;
2 |
3 | /**
4 | *
5 | * @author Lisong Guo
6 | * @date Jan 02, 2014
7 | *
8 | */
9 | public class MaximumGap {
10 |
11 |
12 | public int maximumGap(int[] num) {
13 | if(num.length < 2){
14 | return 0;
15 | }
16 |
17 | Arrays.sort(num);
18 |
19 | int max_gap = Integer.MIN_VALUE;
20 | for(int i=1; i max_gap ? gap : max_gap;
23 | }
24 |
25 | return max_gap;
26 | }
27 |
28 | // another solution would be bucket sort.
29 |
30 | public static void main(String[] args) {
31 | int [] num = {1, 4, 5, 3};
32 |
33 | MaximumGap solution = new MaximumGap();
34 | System.out.println(solution.maximumGap(num));
35 |
36 | }
37 |
38 | }
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/java/MaximumSubarray.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | /**
4 | *
5 | * Find the contiguous subarray within an array (containing at least one number)
6 | * which has the largest sum.
7 |
8 | For example, given the array [−2,1,−3,4,−1,2,1,−5,4],
9 |
10 | j=1 -2 1 -3 4 -1 2 1 -5 4 A
11 |
12 | j=2 -1 -2 1 3 1 3 -4 -1
13 | j=3 -4 2 0 5 2 -2 0
14 | j=4
15 |
16 | the contiguous subarray [4,−1,2,1] has the largest sum = 6.
17 | *
18 | * @author Lisong Guo
19 | * @date Dec 11, 2014
20 | *
21 | */
22 | public class MaximumSubarray {
23 |
24 |
25 | /**
26 | * dynamic programming.
27 | */
28 | public int maxSubArray(int[] A) {
29 | if(A.length == 0){
30 | return 0;
31 | }
32 |
33 | int [] dp = new int[A.length];
34 |
35 | int max_sum = A[0];
36 | dp[0] = A[0];
37 |
38 | for(int i=1; i
13 | * @date Nov 12, 2014
14 | *
15 | *
16 | */
17 |
18 | public class MergeSort {
19 |
20 | public ListNode mergeSort(ListNode head){
21 |
22 | return head;
23 | }
24 |
25 | /**
26 | * @param args
27 | */
28 | public static void main(String[] args) {
29 | // TODO Auto-generated method stub
30 |
31 | }
32 |
33 | }
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/java/MissingPositive.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | *
4 | Given an unsorted integer array, find the first missing positive integer.
5 |
6 | For example,
7 | Given [1,2,0] return 3,
8 | and [3,4,-1,1] return 2.
9 |
10 | Your algorithm should run in O(n) time and uses constant space.
11 |
12 | * @author Lisong Guo
13 | * @date Dec 28, 2014
14 | *
15 | */
16 | public class MissingPositive {
17 |
18 | /**
19 | * https://oj.leetcode.com/discuss/4220/a-very-nice-solution-from-ants-aasma-%40stackoverflow
20 | *
21 | */
22 | public int firstMissingPositive(int[] A) {
23 | int n = A.length;
24 |
25 | for(int i=0; i 0 && num < n && A[num-1] != num){
30 | // swap the values between A[i] and A[num-1]
31 | int temp = A[i];
32 | A[i] = A[num-1];
33 | A[num-1] = temp;
34 |
35 | num = A[i];
36 | }
37 | }
38 |
39 | for(int i=0; i
7 | * @date Jan 04, 2015
8 | *
9 | */
10 | public class Pow {
11 |
12 | public double pow(double x, int n) {
13 | boolean isNeg = false;
14 |
15 | if(n == 0){
16 | return 1;
17 | }else if(n == 1 || x == 0){
18 | return x;
19 | }else if(n < 0){
20 | isNeg = true;
21 | n = -n;
22 | }
23 |
24 | double res = 1.0;
25 | if(n % 2 == 1){
26 | res = x;
27 | }
28 |
29 | double half = pow(x*x, n/2);
30 | res = res * half;
31 |
32 | if(isNeg){
33 | return 1/res;
34 | }else{
35 | return res;
36 | }
37 | }
38 |
39 | public static void main(String[] args) {
40 | Pow solution = new Pow();
41 |
42 | System.out.println(solution.pow(0, -1));
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/java/RandomListNode.java:
--------------------------------------------------------------------------------
1 |
2 | class RandomListNode {
3 | int label;
4 | RandomListNode next, random;
5 |
6 | RandomListNode(int x) {
7 | this.label = x;
8 | }
9 | };
10 |
--------------------------------------------------------------------------------
/java/RemoveDuplicates.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | /**
4 | *
5 | Given a sorted array, remove the duplicates in place
6 | such that each element appear only once and return the new length.
7 |
8 | Do not allocate extra space for another array,
9 | you must do this in place with constant memory.
10 |
11 | For example,
12 | Given input array A = [1,1,2],
13 | Your function should return length = 2, and A is now [1,2].
14 |
15 | *
16 | * @author Lisong Guo
17 | * @date Dec 29, 2014
18 | *
19 | */
20 | public class RemoveDuplicates {
21 |
22 | public int removeDuplicates(int[] A) {
23 | if(A.length == 0){
24 | return 0;
25 | }
26 |
27 | int fillCur = 0, iterCur = 1;
28 |
29 | for(; iterCur < A.length; ++iterCur){
30 | if(A[iterCur] != A[fillCur]){
31 | A[++fillCur] = A[iterCur];
32 | }
33 | }
34 |
35 | return fillCur+1;
36 | }
37 |
38 | public static void main(String[] args) {
39 | //int [] A = {1, 1, 1, 2, 2};
40 | int [] A = {};
41 |
42 | RemoveDuplicates solution = new RemoveDuplicates();
43 |
44 | int newLen = solution.removeDuplicates(A);
45 | System.out.println(newLen);
46 |
47 | for(int i=0; i
13 | * @date Dec 27, 2014
14 | *
15 | */
16 | public class SingleNumber {
17 |
18 | public int singleNumber(int[] A) {
19 | int single = 0x0;
20 |
21 | for(int i=0; i
18 | * @date Dec 30, 2014
19 | *
20 | */
21 |
22 | public class TwoSum {
23 |
24 | public int[] twoSum(int[] numbers, int target) {
25 | Hashtable numTable =
26 | new Hashtable();
27 | int [] res = new int[2];
28 |
29 | for(int i=0; i neighbors;
9 |
10 | UndirectedGraphNode(int x) {
11 | label = x;
12 | neighbors = new ArrayList();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/python/1009_complement_of_base_10_integer.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def bitwiseComplement(self, n: int) -> int:
4 | bitmask = 1
5 | result, remain = n, n
6 |
7 | # exception
8 | if n == 0:
9 | return 1
10 |
11 | while remain:
12 | result = result ^ bitmask
13 |
14 | bitmask = bitmask << 1
15 | remain = remain >> 1
16 |
17 | return result
--------------------------------------------------------------------------------
/python/1010_combination_sum_divisible_by_60.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def numPairsDivisibleBy60(self, time: List[int]) -> int:
3 |
4 | count = 0
5 |
6 | modulo_table = defaultdict(int)
7 |
8 | for num in time:
9 | modulo_table[num % 60] += 1
10 |
11 | for factor in [0, 30]:
12 | if factor in modulo_table:
13 | count += int(modulo_table[factor] * (modulo_table[factor]-1) / 2)
14 |
15 | for factor in range(1, 30):
16 | if factor in modulo_table:
17 | count += modulo_table[factor] * modulo_table[60 - factor]
18 |
19 | return count
20 |
--------------------------------------------------------------------------------
/python/1011_minimal_capacity_to_ship_packages_in_D_days.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def shipWithinDays(self, weights: List[int], D: int) -> int:
3 |
4 | def possible(capacity):
5 | ship_weight = 0
6 | ship_count = 1
7 | for weight in weights:
8 | if weight > capacity:
9 | return False
10 | elif ship_weight + weight <= capacity:
11 | ship_weight += weight
12 | elif ship_count > D:
13 | return False
14 | else:
15 | # add a new ship
16 | ship_count += 1
17 | ship_weight = weight
18 | return (ship_count <= D)
19 |
20 |
21 | low = max(weights)
22 | high = sum(weights)
23 | while low < high:
24 | mid = (low + high) // 2
25 | is_ok = possible(mid)
26 | if is_ok:
27 | high = mid
28 | else:
29 | low = mid + 1
30 |
31 | return low
--------------------------------------------------------------------------------
/python/1013_partition_array_into_three_parts_with_equal_sum.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def canThreePartsEqualSum(self, arr: List[int]) -> bool:
4 |
5 | total_sum = sum(arr)
6 |
7 | if total_sum % 3 != 0:
8 | return False
9 |
10 | subarray_sum = total_sum / 3
11 | group_sum, group_count = 0, 0
12 |
13 | for num in arr:
14 | group_sum += num
15 | if group_sum == subarray_sum:
16 | group_count += 1
17 | group_sum = 0
18 |
19 | return group_count >= 3
20 |
--------------------------------------------------------------------------------
/python/1020_Number_of_Enclaves.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def numEnclaves(self, A: List[List[int]]) -> int:
3 |
4 | rows, cols = len(A), len(A[0])
5 |
6 | borders = []
7 | total_land = 0
8 |
9 | def isBoundary(row, col):
10 | return (row == 0) or (row==rows-1) or (col==0) or (col==cols-1)
11 |
12 | for row in range(rows):
13 | for col in range(cols):
14 | if A[row][col] == 1:
15 | total_land += 1
16 | if isBoundary(row, col):
17 | borders.append((row, col))
18 | A[row][col] = -1
19 |
20 | queue = deque(borders)
21 | total_land -= len(borders)
22 |
23 | # BFS traversal, starting from the borders
24 | # reaching the inner land.
25 | while queue:
26 | row, col = queue.popleft()
27 | for ro, co in [(-1, 0), (0, 1), (1, 0), (0, -1)]:
28 | new_row, new_col = row + ro, col + co
29 | if (0 <= new_row < rows) and (0 <= new_col < cols):
30 | if A[new_row][new_col] == 1:
31 | queue.append((new_row, new_col))
32 | A[new_row][new_col] = -1
33 | total_land -= 1
34 |
35 | return total_land
36 |
37 |
38 |
--------------------------------------------------------------------------------
/python/1021_remove_outermost_parentheses.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def removeOuterParentheses(self, s: str) -> str:
3 |
4 | stack = []
5 | start = 0
6 | primitives = []
7 | # retrieve all the primitives
8 | for index, letter in enumerate(s):
9 | if letter == "(":
10 | stack.append(letter)
11 | else:
12 | stack.pop()
13 | if len(stack) == 0:
14 | primitives.append(s[start:index+1])
15 | start = index + 1
16 |
17 | # strip the outermost parentheses
18 | stripped = []
19 | for primitive in primitives:
20 | stripped.append(primitive[1:-1])
21 |
22 | return "".join(stripped)
23 |
24 |
--------------------------------------------------------------------------------
/python/1046_Last_Stone_Weight.py:
--------------------------------------------------------------------------------
1 | """
2 | We have a collection of rocks, each rock has a positive integer weight.
3 |
4 | Each turn, we choose the two heaviest rocks and smash them together.
5 | Suppose the stones have weights x and y with x <= y. The result of this smash is:
6 |
7 | If x == y, both stones are totally destroyed;
8 | If x != y, the stone of weight x is totally destroyed,
9 | and the stone of weight y has new weight y-x.
10 |
11 | At the end, there is at most 1 stone left.
12 | Return the weight of this stone (or 0 if there are no stones left.)
13 |
14 | """
15 |
16 | class Solution:
17 | def lastStoneWeight(self, stones: List[int]) -> int:
18 | import heapq
19 |
20 | # Since in Python, the heap is implemented as minimum heap,
21 | # in order to have the maximum heap, we applied a trick here,
22 | # i.e. we applied the negation on the original values.
23 | neg_stones = [-stone for stone in stones]
24 | heapq.heapify(neg_stones)
25 |
26 | while len(neg_stones) > 1:
27 | y = heapq.heappop(neg_stones)
28 | x = heapq.heappop(neg_stones)
29 | if x != y:
30 | #new_weight = -((-y) - (-x))
31 | new_weight = y - x
32 |
33 | heapq.heappush(neg_stones, new_weight)
34 |
35 | if neg_stones:
36 | return - neg_stones[0]
37 | else:
38 | return 0
--------------------------------------------------------------------------------
/python/1047_remove_all_adjacent_duplicates_in_string.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def removeDuplicates(self, s: str) -> str:
3 | stack = []
4 | for letter in s:
5 | if not stack:
6 | stack.append(letter)
7 | else:
8 | top = stack[-1]
9 | if top == letter:
10 | stack.pop()
11 | else:
12 | stack.append(letter)
13 |
14 | return "".join(stack)
15 |
--------------------------------------------------------------------------------
/python/1061_lexicographically_smallest_equivalent_string.py:
--------------------------------------------------------------------------------
1 | class LetterUnionFind:
2 |
3 | def __init__(self):
4 | self.parent = [i for i in range(26)]
5 | self.base = ord('a')
6 |
7 | def find(self, letter):
8 | lid = ord(letter) - self.base
9 | if lid != self.parent[lid]:
10 | parent_letter = chr(self.base + self.parent[lid])
11 | self.parent[lid] = self.find(parent_letter)
12 | return self.parent[lid]
13 |
14 | def union(self, la, lb):
15 | ga = self.find(la)
16 | gb = self.find(lb)
17 | if ga != gb:
18 | # join the group with larger letter to the one with smaller one
19 | if ga > gb:
20 | self.parent[ga] = gb
21 | else:
22 | self.parent[gb] = ga
23 |
24 |
25 | class Solution:
26 | def smallestEquivalentString(self, s1: str, s2: str, baseStr: str) -> str:
27 |
28 | luf = LetterUnionFind()
29 |
30 | for la, lb in zip(s1, s2):
31 | luf.union(la, lb)
32 |
33 | ret = []
34 | base = ord('a')
35 | for letter in baseStr:
36 | parent_id = luf.find(letter)
37 | to_letter = chr(parent_id + base)
38 | ret.append(to_letter)
39 |
40 | return "".join(ret)
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/python/1073_add_two_negabinary_numbers.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def addNegabinary(self, arr1: List[int], arr2: List[int]) -> List[int]:
3 |
4 | p1, p2 = len(arr1)-1, len(arr2)-1
5 | carry = 0
6 | result = []
7 |
8 | while p1 >= 0 or p2 >= 0 or carry:
9 |
10 | bit_sum = 0
11 |
12 | if p1 >= 0:
13 | bit_sum += arr1[p1]
14 | p1 -= 1
15 |
16 | if p2 >= 0:
17 | bit_sum += arr2[p2]
18 | p2 -= 1
19 |
20 | bit_sum += carry
21 | result.append(bit_sum % 2)
22 |
23 | # the difference between base 2 and base -2
24 | # The parenthese (bit_sum // 2) is absolutely necessary!
25 | carry = - (bit_sum // 2)
26 |
27 | # remove the leading zeros
28 | while len(result) > 1 and result[-1] == 0:
29 | result.pop()
30 |
31 | return result[::-1]
32 |
--------------------------------------------------------------------------------
/python/1081_Smallest_Subsequence_of_Distinct_Letters.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def smallestSubsequence(self, text: str) -> str:
3 |
4 | final_list = []
5 | seen = set()
6 |
7 | last_seen = defaultdict(int)
8 | for index, letter in enumerate(text):
9 | last_seen[letter] = index
10 |
11 | for index, letter in enumerate(text):
12 |
13 | if letter in seen:
14 | continue
15 |
16 | # greedily deduplicate the redundant letters
17 | while final_list:
18 | prev_letter = final_list[-1]
19 | if letter < prev_letter and last_seen[prev_letter] > index:
20 | final_list.pop()
21 | seen.discard(prev_letter)
22 | else:
23 | break
24 |
25 | final_list.append(letter)
26 | seen.add(letter)
27 |
28 | return "".join(final_list)
--------------------------------------------------------------------------------
/python/1091_shortest_path_in_binary_matrix.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def shortestPathBinaryMatrix(self, grid: List[List[int]]) -> int:
3 |
4 | N = len(grid)
5 |
6 | def bfs():
7 |
8 | queue = [(0, 0)]
9 | distance = 0
10 | is_found = False
11 |
12 | while queue:
13 | next_queue = []
14 | distance += 1
15 |
16 | while queue:
17 | row, col = queue.pop()
18 |
19 | for ro, co in [(1, 1), (1, 0), (0, 1), (-1, 0),
20 | (0, -1), (1, -1), (-1, -1), (-1, 1)]:
21 | new_row, new_col = row + ro, col + co
22 | if new_row < 0 or new_row >= N or \
23 | new_col < 0 or new_col >= N:
24 | continue
25 |
26 | if row == N-1 and col == N-1:
27 | return distance
28 |
29 | if grid[new_row][new_col] == 0:
30 | grid[new_row][new_col] = 1
31 | next_queue.append((new_row, new_col))
32 | queue = next_queue
33 |
34 | return -1
35 |
36 | if grid[0][0] != 0:
37 | return -1
38 |
39 | if N == 1:
40 | return 1
41 |
42 | grid[0][0] = 1
43 | distance = bfs()
44 | return distance
45 |
--------------------------------------------------------------------------------
/python/1094_car_pooling.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def carPooling(self, trips: List[List[int]], capacity: int) -> bool:
4 |
5 |
6 | capacity_changes = []
7 |
8 | for psg, start, end in trips:
9 | # capacity decrease at pickup and increase at dropoff
10 | # for overlapping intervals, we should drop-off first then pickup.
11 | # as a result, the second element should also play a role in ordering
12 | # Note: we must priroitize the dropoff before pickup
13 | capacity_changes.append((start, psg))
14 | capacity_changes.append((end, -psg))
15 |
16 | heapq.heapify(capacity_changes)
17 |
18 | used_capacity = 0
19 | while capacity_changes:
20 | timestamp, capacity_delta = heapq.heappop(capacity_changes)
21 | used_capacity += capacity_delta
22 |
23 | if used_capacity > capacity:
24 | return False
25 |
26 | return True
27 |
--------------------------------------------------------------------------------
/python/1100_find_k-length_substrings_with_no_repeated_characters.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def numKLenSubstrNoRepeats(self, s: str, k: int) -> int:
3 | if len(s) < k:
4 | return 0
5 | count = 0
6 |
7 | slide_window = defaultdict(int)
8 | for index, letter in enumerate(s):
9 | if index < k:
10 | slide_window[letter] += 1
11 | else:
12 | slide_window[letter] += 1
13 | popped = s[index-k]
14 | slide_window[popped] -= 1
15 | if slide_window[popped] == 0:
16 | del slide_window[popped]
17 |
18 | # check the characters once the sliding window is fully filled.
19 | if index >= k-1 and len(slide_window) == k:
20 | count += 1
21 |
22 | return count
--------------------------------------------------------------------------------
/python/1135_connecting_cities_with_minimal_cost.py:
--------------------------------------------------------------------------------
1 | class DisjointSet:
2 |
3 | def __init__(self, N):
4 | # the id starts from 1, instead of 0
5 | self.parent = [i for i in range(N+1)]
6 |
7 | def find(self, a):
8 | if self.parent[a] != a:
9 | self.parent[a] = self.find(self.parent[a])
10 | return self.parent[a]
11 |
12 | def union(self, a, b):
13 | pa, pb = self.find(a), self.find(b)
14 | if pa != pb:
15 | # attach the group of pb to pa
16 | self.parent[pb] = pa
17 | return pa
18 |
19 |
20 | class Solution:
21 | def minimumCost(self, N: int, connections: List[List[int]]) -> int:
22 |
23 | # at least we need N-1 edges to connect N vetex
24 | if len(connections) < N-1:
25 | return -1
26 |
27 | connections.sort(key = lambda x: x[2])
28 | ds = DisjointSet(N)
29 |
30 | components = N
31 | total_cost = 0
32 | for (city1, city2, cost) in connections:
33 | if components == 1:
34 | break
35 |
36 | group1, group2 = ds.find(city1), ds.find(city2)
37 | if group1 != group2:
38 | ds.union(group1, group2)
39 | components -= 1
40 | total_cost += cost
41 |
42 | return -1 if components != 1 else total_cost
43 |
44 |
--------------------------------------------------------------------------------
/python/1150_check_majority_element_in_sorted_array.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def isMajorityElement(self, nums: List[int], target: int) -> bool:
3 |
4 | # locate the target with the binary search
5 | low, high = 0, len(nums)
6 | while low < high:
7 | mid = (high - low) // 2 + low
8 | if nums[mid] < target:
9 | low = mid + 1
10 | elif nums[mid] > target:
11 | high = mid
12 | else:
13 | break
14 |
15 | if nums[mid] != target:
16 | return False
17 |
18 | # search around the located target for duplicate elements
19 | count = 1
20 | low, high = mid - 1, mid + 1
21 | while low >= 0:
22 | if nums[low] != target:
23 | break
24 | low -= 1
25 | count += 1
26 |
27 | while high < len(nums):
28 | if nums[high] != target:
29 | break
30 | high += 1
31 | count += 1
32 |
33 | return count > len(nums) / 2
34 |
35 |
--------------------------------------------------------------------------------
/python/1151_minimal_swaps_to_group_all_ones_together.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def minSwaps(self, data: List[int]) -> int:
3 |
4 | ones = 0
5 | for bit in data:
6 | if bit == 1:
7 | ones += 1
8 |
9 | if ones in [0, 1, len(data)]:
10 | return 0
11 |
12 | swaps = 0
13 | slide_window = deque(data[0:ones])
14 | for bit in slide_window:
15 | if bit == 0:
16 | swaps += 1
17 |
18 | min_swaps = swaps
19 | for bit in data[ones:]:
20 |
21 | slide_window.append(bit)
22 | if bit == 0:
23 | swaps += 1
24 |
25 | if slide_window.popleft() == 0:
26 | swaps -= 1
27 |
28 | min_swaps = min(min_swaps, swaps)
29 |
30 | return min_swaps
31 |
--------------------------------------------------------------------------------
/python/1155_number_of_dice_rolls_with_target_sum.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def numRollsToTarget(self, d: int, f: int, target: int) -> int:
3 |
4 | modulo = 10 ** 9 + 7
5 |
6 | @functools.lru_cache(maxsize=None)
7 | def dp(dice_index, remain):
8 |
9 | if dice_index == d:
10 | return (remain == 0)
11 | elif remain < 0:
12 | return 0
13 |
14 | combs = 0
15 | for curr_dice in range(1, f+1):
16 | increment = dp(dice_index+1, remain - curr_dice)
17 | combs = (combs + increment) % modulo
18 |
19 | return combs
20 |
21 | return dp(0, target)
22 |
23 |
24 | class SolutionListComprehension:
25 | def numRollsToTarget(self, d: int, f: int, target: int) -> int:
26 |
27 | modulo = 10 ** 9 + 7
28 |
29 | @functools.lru_cache(maxsize=None)
30 | def dp(dice_index, remain):
31 |
32 | if dice_index == d:
33 | return (remain == 0)
34 | elif remain < 0:
35 | return 0
36 |
37 | return sum([dp(dice_index+1, remain - num) for num in range(1, f+1)]) % modulo
38 |
39 | return dp(0, target)
40 |
--------------------------------------------------------------------------------
/python/1162_as_far_from_land_as_possible.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def maxDistance(self, grid: List[List[int]]) -> int:
3 | rows, cols = len(grid), len(grid[0])
4 |
5 | queue = deque([])
6 | visited = [[False] * cols for _ in range(rows)]
7 |
8 | # treat all lands as a Unit
9 | # run BFS from all lands, the water that is reached at the end is the farest one
10 | for row in range(rows):
11 | for col in range(cols):
12 | if grid[row][col] == 1:
13 | queue.append((row, col, 0))
14 | visited[row][col] = True
15 |
16 | if len(queue) == rows * cols:
17 | # all lands, no water
18 | return -1
19 |
20 | steps = - 1
21 | while queue:
22 | row, col, steps = queue.popleft()
23 |
24 | for r_offset, c_offset in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
25 | new_row, new_col = row + r_offset, col + c_offset
26 | if new_row < 0 or new_row >= rows or new_col < 0 or new_col >= cols:
27 | continue
28 |
29 | if not visited[new_row][new_col] and grid[new_row][new_col] == 0:
30 | visited[new_row][new_col] = True
31 | queue.append((new_row, new_col, steps + 1))
32 |
33 | return steps
34 |
--------------------------------------------------------------------------------
/python/1166_design_file_system.py:
--------------------------------------------------------------------------------
1 | class FileSystem:
2 |
3 | def __init__(self):
4 | self.path_map = {}
5 |
6 | def createPath(self, path: str, value: int) -> bool:
7 | if path == "" or path == "/" or path[0] != "/" or path in self.path_map:
8 | # invalid path or path exists already
9 | return False
10 |
11 | folders = path.split("/")
12 | parent_path = ""
13 | for folder in folders[1:-1]:
14 | parent_path = parent_path + "/" + folder
15 | if parent_path not in self.path_map:
16 | return False
17 |
18 | self.path_map[path] = value
19 | return True
20 |
21 | def get(self, path: str) -> int:
22 | if path in self.path_map:
23 | return self.path_map[path]
24 | else:
25 | return -1
26 |
27 |
28 | # Your FileSystem object will be instantiated and called as such:
29 | # obj = FileSystem()
30 | # param_1 = obj.createPath(path,value)
31 | # param_2 = obj.get(path)
--------------------------------------------------------------------------------
/python/1167_minimum_costs_to_connect_sticks.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def connectSticks(self, sticks: List[int]) -> int:
3 |
4 | heapq.heapify(sticks)
5 |
6 | # Greedily merge two sticks together
7 | # since the sticks merged earlier would accumulate the costs over the time
8 | costs = 0
9 | while len(sticks) > 1:
10 | x = heapq.heappop(sticks)
11 | y = heapq.heappop(sticks)
12 | new_stick = x + y
13 | heapq.heappush(sticks, new_stick)
14 | costs += new_stick
15 |
16 | return costs
17 |
--------------------------------------------------------------------------------
/python/116_populate_next_right_pointers.py:
--------------------------------------------------------------------------------
1 |
2 | """
3 | # Definition for a Node.
4 | class Node:
5 | def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
6 | self.val = val
7 | self.left = left
8 | self.right = right
9 | self.next = next
10 | """
11 |
12 | class Solution:
13 | def connect(self, root: 'Node') -> 'Node':
14 |
15 | if not root:
16 | return root
17 |
18 | queue = deque([root, None])
19 | while len(queue) > 1:
20 |
21 | tail = queue.pop()
22 | next_queue = deque([None])
23 |
24 | for _ in range(len(queue)):
25 | curr = queue.pop()
26 | curr.next = tail
27 |
28 | if curr.right:
29 | next_queue.appendleft(curr.right)
30 | next_queue.appendleft(curr.left)
31 | # move the tail pointer
32 | tail = curr
33 |
34 | queue = next_queue
35 |
36 | return root
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/python/11_container_with_most_water.py:
--------------------------------------------------------------------------------
1 |
2 | class SolutionTLE:
3 | def maxArea(self, height: List[int]) -> int:
4 |
5 | length = len(height)
6 |
7 | max_size = float('-inf')
8 | for start in range(length):
9 | for end in range(start+1, length):
10 | new_size = min(height[start], height[end]) * (end - start)
11 | max_size = max(max_size, new_size)
12 |
13 | return max_size
14 |
15 |
16 | class SolutionTwoPointer:
17 | def maxArea(self, height: List[int]) -> int:
18 |
19 | left, right = 0, len(height) - 1
20 | max_size = float('-inf')
21 | while left < right:
22 | new_size = min(height[left], height[right]) * (right - left)
23 | max_size = max(max_size, new_size)
24 |
25 | if height[left] < height[right]:
26 | left += 1
27 | else:
28 | right -= 1
29 |
30 | return max_size
--------------------------------------------------------------------------------
/python/1202_smallest_strings_with_swaps.py:
--------------------------------------------------------------------------------
1 | class UnionFind:
2 | def __init__(self, size):
3 | self.parent = [i for i in range(size)]
4 |
5 | def find(self, a):
6 | if self.parent[a] != a:
7 | self.parent[a] = self.find(self.parent[a])
8 | return self.parent[a]
9 |
10 | def union(self, a, b):
11 | ga = self.find(a)
12 | gb = self.find(b)
13 | if ga != gb:
14 | self.parent[ga] = self.parent[gb]
15 |
16 |
17 | class Solution:
18 | def smallestStringWithSwaps(self, s: str, pairs: List[List[int]]) -> str:
19 |
20 | uf = UnionFind(len(s))
21 |
22 | for a, b in pairs:
23 | uf.union(a, b)
24 |
25 | letter_groups = defaultdict(list)
26 | for index in range(len(s)):
27 | parent_id = uf.find(index)
28 | letter_groups[parent_id].append(index)
29 |
30 | output = [''] * len(s)
31 | for parent_id, group_index in letter_groups.items():
32 | letters = [s[index] for index in group_index]
33 | letters.sort()
34 | for li, index in enumerate(group_index):
35 | output[index] = letters[li]
36 |
37 | return "".join(output)
38 |
39 |
--------------------------------------------------------------------------------
/python/1209_remove_all_adjacent_duplicates_in_a_string_II.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def removeDuplicates(self, s: str, k: int) -> str:
4 | stack = []
5 |
6 | for letter in s:
7 | if not stack:
8 | stack.append((letter, 1))
9 | else:
10 | prev_letter, count = stack[-1]
11 | if letter == prev_letter:
12 | if count == k - 1:
13 | for _ in range(k-1):
14 | stack.pop()
15 | else:
16 | stack.append((letter, count+1))
17 | else:
18 | stack.append((letter, 1))
19 |
20 | return "".join([l for (l, c) in stack])
21 |
--------------------------------------------------------------------------------
/python/1249_minimum_remove_to_make_valid_parentheses.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def minRemoveToMakeValid(self, s: str) -> str:
3 |
4 | to_remove = set()
5 | stack = []
6 | for index, letter in enumerate(s):
7 | if letter == "(":
8 | stack.append((index, letter))
9 | elif letter == ")":
10 | if stack:
11 | stack.pop()
12 | else:
13 | # invalid parenthese
14 | to_remove.add(index)
15 |
16 | # list of unmatched (invalid) parentheses
17 | for index, letter in stack:
18 | to_remove.add(index)
19 |
20 | output = []
21 | for index, letter in enumerate(s):
22 | if index not in to_remove:
23 | output.append(letter)
24 |
25 | return "".join(output)
--------------------------------------------------------------------------------
/python/1257_smallest_common_region.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def findSmallestRegion(self, regions: List[List[str]], region1: str, region2: str) -> str:
4 |
5 | parents = dict()
6 |
7 | for region in regions:
8 | parent_region = region[0]
9 | for subregion in region[1:]:
10 | parents[subregion] = parent_region
11 |
12 | """
13 | 1 ------o---| 1 + 2: ------o---|--o---
14 | 2 --o---| 2 + 1: --o---|------o---
15 |
16 | lengths after o (o---) are always same, so 2 pointers finally meet at the same node
17 | """
18 | p1 = region1
19 | p2 = region2
20 | while p1 != p2:
21 | p1 = region2 if p1 not in parents else parents[p1]
22 | p2 = region1 if p2 not in parents else parents[p2]
23 |
24 | return p1
25 |
--------------------------------------------------------------------------------
/python/1261_Find_Elements_in_Contaminated_Binary_Tree.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class FindElements:
8 |
9 | def __init__(self, root: TreeNode):
10 | self.value_set = set()
11 |
12 | def populate(node, value):
13 | if node is None:
14 | return
15 |
16 | node.val = value
17 | self.value_set.add(value)
18 | populate(node.left, 2 * value + 1)
19 | populate(node.right, 2 * value + 2)
20 |
21 | populate(root, 0)
22 | self.root = root
23 |
24 | def find(self, target: int) -> bool:
25 |
26 | # def dfs(node):
27 | # if node is None:
28 | # return False
29 | # if target == node.val:
30 | # return True
31 | # if dfs(node.left):
32 | # return True
33 | # return dfs(node.right)
34 |
35 | return (target in self.value_set)
36 |
37 |
38 | # Your FindElements object will be instantiated and called as such:
39 | # obj = FindElements(root)
40 | # param_1 = obj.find(target)
--------------------------------------------------------------------------------
/python/1288_remove_covered_intervals.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def removeCoveredIntervals(self, intervals: List[List[int]]) -> int:
4 |
5 | # Order intervals first by the starting in ascending order,
6 | # if two intervals have the same starting point, then order the ends in descending order.
7 | # Since we check the inclusion in the reserved ordre,
8 | # i.e. for intervals[i], check if it is included by any of the previous intervals[0...i-1]
9 | intervals.sort(key = lambda x: (x[0], -x[1]))
10 |
11 | remaining_intervals = len(intervals)
12 |
13 | for curr in range(len(intervals)-1, 0, -1):
14 | is_covered = False
15 |
16 | _, curr_end = intervals[curr]
17 |
18 | for prev in range(curr-1, -1, -1):
19 | _, prev_end = intervals[prev]
20 | if prev_end >= curr_end:
21 | is_covered = True
22 | break
23 |
24 | if is_covered:
25 | remaining_intervals -= 1
26 |
27 | return remaining_intervals
28 |
--------------------------------------------------------------------------------
/python/129_sum_root_to_leaf_numbers.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def sumNumbers(self, root: TreeNode) -> int:
9 |
10 | total_sum = 0
11 |
12 | def dfs(node, curr_num):
13 | nonlocal total_sum
14 |
15 | if node is None:
16 | return 0
17 |
18 | next_num = curr_num * 10 + node.val
19 | if node.left:
20 | dfs(node.left, next_num)
21 |
22 | if node.right:
23 | dfs(node.right, next_num)
24 |
25 | if node.left is None and node.right is None:
26 | # leaf node
27 | total_sum += next_num
28 |
29 | dfs(root, 0)
30 | return total_sum
31 |
--------------------------------------------------------------------------------
/python/131_palindrome_partition.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def partition(self, s: str) -> List[List[str]]:
3 |
4 | def isPalindrome(ss):
5 | if len(ss) == 1: return True
6 | ss_size = len(ss)
7 | for i in range(ss_size//2):
8 | if ss[i] != ss[ss_size-i-1]:
9 | return False
10 | return True
11 |
12 | results = []
13 |
14 | def backtrack(curr, comb):
15 | if curr == len(s):
16 | results.append(list(comb))
17 | return
18 |
19 | for end in range(curr+1, len(s)+1):
20 | substr = s[curr:end]
21 | if isPalindrome(substr):
22 | comb.append(substr)
23 | backtrack(curr + len(substr), comb)
24 | comb.pop()
25 |
26 | backtrack(0, [])
27 |
28 | return results
--------------------------------------------------------------------------------
/python/1325_delete_leaves_nodes_with_a_given_value.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def removeLeafNodes(self, root: TreeNode, target: int) -> TreeNode:
9 |
10 | def dfs(node):
11 | if node is None:
12 | return True
13 |
14 | remove_left = dfs(node.left)
15 | if remove_left:
16 | node.left = None
17 |
18 | remove_right = dfs(node.right)
19 | if remove_right:
20 | node.right = None
21 |
22 | if node.val == target:
23 | return (remove_left and remove_right)
24 |
25 | return False
26 |
27 | pseudo_head = TreeNode(val=0, left=root)
28 | dfs(pseudo_head)
29 |
30 | return pseudo_head.left
31 |
--------------------------------------------------------------------------------
/python/1328_break_a_palindrome.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 |
3 | def breakPalindrome(self, palindrome: str) -> str:
4 | """
5 | Greedy strategy to build the first non-palindrome string.
6 | 3 rules in total:
7 | - the string is of one letter
8 | - find the first non-a letter in the first half of the palindrome string,
9 | and replace it with the letter 'a'.
10 | - otherwise replace the last letter with 'a'.
11 | """
12 | if len(palindrome) == 1:
13 | return ""
14 |
15 | mid = len(palindrome) // 2
16 |
17 | for index in range(mid):
18 | if palindrome[index] != 'a':
19 | return palindrome[0:index] + "a" + palindrome[index+1:]
20 |
21 | return palindrome[:-1] + "b"
22 |
--------------------------------------------------------------------------------
/python/132_Palindrome_Partition_II.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def minCut(self, s: str) -> int:
3 |
4 | # element indicates the minimal number of partitions
5 | # we need to divide the corresponding substring
6 | dp = [0] * (len(s)+1)
7 |
8 | for right in range(1, len(s)+1):
9 | num_parts = float('inf')
10 |
11 | for left in range(0, right):
12 | substr = s[left:right]
13 | # isPalindrome(s[left:right])
14 | if substr == substr[::-1]:
15 | num_parts = min(num_parts, dp[left]+1)
16 | if left == 0:
17 | # cannot have less than one partition
18 | break
19 |
20 | dp[right] = num_parts
21 |
22 | return dp[len(s)] - 1
23 |
--------------------------------------------------------------------------------
/python/1366_rank_teams_by_votes.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def rankTeams(self, votes: List[str]) -> str:
3 |
4 | rank_counts = {}
5 |
6 | total_votes = len(votes)
7 | num_teams = len(votes[0])
8 |
9 | for vote in votes:
10 | for rank, name in enumerate(vote):
11 | if name not in rank_counts:
12 | rank_counts[name] = defaultdict(int)
13 | keys = rank_counts[name]
14 | keys[rank] += 1
15 |
16 | rank_keys = []
17 | for name, counts in rank_counts.items():
18 | compound_key = []
19 | for position in range(num_teams):
20 | compound_key.append(str(total_votes - counts[position]))
21 | compound_key.append(name)
22 |
23 | rank_keys.append(("".join(compound_key), name))
24 |
25 | final_rank = sorted(rank_keys, key = lambda x:x[0])
26 | return "".join([name for _, name in final_rank])
27 |
28 |
--------------------------------------------------------------------------------
/python/1376_time_needed_to_inform_all_employee.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def numOfMinutes(self, n: int, headID: int, manager: List[int], informTime: List[int]) -> int:
4 |
5 | subordinates = dict()
6 | for employee_id, manager_id in enumerate(manager):
7 | if manager_id not in subordinates:
8 | subordinates[manager_id] = []
9 |
10 | if manager_id == -1:
11 | # pseudo head
12 | subordinates[manager_id].append((employee_id, 0))
13 | else:
14 | subordinates[manager_id].append((employee_id, informTime[manager_id]))
15 |
16 |
17 | max_time = float('-inf')
18 | def dfs(curr, time_elapse):
19 | nonlocal max_time
20 |
21 | if curr not in subordinates:
22 | # bottom
23 | max_time = max(max_time, time_elapse)
24 | return
25 |
26 | for employee_id, added_time in subordinates[curr]:
27 | dfs(employee_id, added_time + time_elapse)
28 |
29 | dfs(-1, 0)
30 |
31 | return max_time
32 |
33 |
--------------------------------------------------------------------------------
/python/1383_maximum_performance_of_team.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def maxPerformance(self, n: int, speed: List[int], efficiency: List[int], k: int) -> int:
3 | modulo = 10 ** 9 + 7
4 |
5 | # (efficiency, speed)
6 | metrics = zip(efficiency, speed)
7 | metrics = sorted(metrics, key=lambda t:t[0], reverse=True)
8 |
9 | speed_heap = []
10 | speed_sum, perf = 0, 0
11 |
12 | for curr_efficiency, curr_speed in metrics:
13 |
14 | if len(speed_heap) > k-1:
15 | speed_sum -= heapq.heappop(speed_heap)
16 |
17 | speed_sum += curr_speed
18 | heapq.heappush(speed_heap, curr_speed)
19 | perf = max(perf, speed_sum * curr_efficiency)
20 |
21 | return perf % modulo
22 |
--------------------------------------------------------------------------------
/python/141_linked_list_cycle.py:
--------------------------------------------------------------------------------
1 | # Definition for singly-linked list.
2 | # class ListNode:
3 | # def __init__(self, x):
4 | # self.val = x
5 | # self.next = None
6 |
7 | class Solution:
8 | def hasCycle(self, head: ListNode) -> bool:
9 |
10 | slow, fast = head, head
11 |
12 | while fast and fast.next:
13 |
14 | fast = fast.next.next
15 | slow = slow.next
16 |
17 | if fast == slow:
18 | return True
19 |
20 | return False
--------------------------------------------------------------------------------
/python/1439_find_kth_smallest_sum_of_matrix_with_sorted_row.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def kthSmallest(self, mat: List[List[int]], k: int) -> int:
3 |
4 | queue = []
5 | col_index = 0
6 | n_rows, n_cols = len(mat), len(mat[0])
7 |
8 | col_array = [0] * n_rows
9 |
10 | queue_sum = sum([mat[row][0] for row in range(n_rows)])
11 |
12 | queue.append((queue_sum, col_array))
13 | heapq.heapify(queue)
14 |
15 | seen = set(tuple(col_array))
16 |
17 | while k:
18 | curr_sum, col_array = heapq.heappop(queue)
19 | k -= 1
20 |
21 | for row_index, col_index in enumerate(col_array):
22 | if col_index + 1 < n_cols:
23 | new_sum = curr_sum - mat[row_index][col_index] + mat[row_index][col_index+1]
24 | new_col_array = col_array.copy()
25 | new_col_array[row_index] = col_index + 1
26 |
27 | key = tuple(new_col_array)
28 | if key in seen:
29 | continue
30 |
31 | seen.add(key)
32 | heapq.heappush(queue, (new_sum, new_col_array))
33 |
34 | return curr_sum
35 |
36 |
--------------------------------------------------------------------------------
/python/1456_maximum_number_of_vowels_in_a_substring_of_given_length.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def maxVowels(self, s: str, k: int) -> int:
4 |
5 | VOWELS = ['a', 'e', 'i', 'o', 'u']
6 | vowel_cnt = 0
7 | for letter in s[0:k]:
8 | if letter in VOWELS:
9 | vowel_cnt += 1
10 |
11 | # starting number of vowels in a sliding window
12 | max_vowel_cnt = vowel_cnt
13 |
14 | for index in range(k, len(s)):
15 | out_of_index = index - k
16 | # two pointers that defines the boundary of the sliding window
17 | if s[index] in VOWELS:
18 | vowel_cnt += 1
19 |
20 | if s[out_of_index] in VOWELS:
21 | vowel_cnt -= 1
22 |
23 | max_vowel_cnt = max(max_vowel_cnt, vowel_cnt)
24 |
25 | return max_vowel_cnt
--------------------------------------------------------------------------------
/python/145_binary_tree_postorder_traversal.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
9 |
10 | output = []
11 |
12 | def dfs(node):
13 | if not node:
14 | return
15 |
16 | dfs(node.left)
17 | dfs(node.right)
18 | output.append(node.val)
19 |
20 | dfs(root)
21 | return output
22 |
23 |
24 | # Definition for a binary tree node.
25 | # class TreeNode:
26 | # def __init__(self, val=0, left=None, right=None):
27 | # self.val = val
28 | # self.left = left
29 | # self.right = right
30 | class SolutionStack:
31 | def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
32 |
33 | output = deque([])
34 |
35 | stack = [root]
36 | while stack:
37 | node = stack.pop()
38 |
39 | if node:
40 | stack.append(node.left)
41 | stack.append(node.right)
42 |
43 | output.appendleft(node.val)
44 |
45 | return output
46 |
--------------------------------------------------------------------------------
/python/1469_Find_All_Lonely_Nodes.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def getLonelyNodes(self, root: TreeNode) -> List[int]:
9 | lonely_nodes = []
10 |
11 | def dfs(node, is_lonely):
12 | if node is None:
13 | return
14 |
15 | if is_lonely:
16 | lonely_nodes.append(node.val)
17 |
18 | if (node.left is None) ^ (node.right is None):
19 | is_lonely = True
20 | else:
21 | is_lonely = False
22 |
23 | dfs(node.left, is_lonely)
24 | dfs(node.right, is_lonely)
25 |
26 | dfs(root, False)
27 |
28 | return lonely_nodes
--------------------------------------------------------------------------------
/python/147_Insertion_Sort_List.py:
--------------------------------------------------------------------------------
1 | # Definition for singly-linked list.
2 | # class ListNode:
3 | # def __init__(self, val=0, next=None):
4 | # self.val = val
5 | # self.next = next
6 |
7 | # def printList(head):
8 | # ret = []
9 | # while head:
10 | # ret.append(head.val)
11 | # head = head.next
12 | # print(ret)
13 |
14 | class Solution:
15 |
16 | def insertionSortList(self, head: ListNode) -> ListNode:
17 |
18 | pseudo_head = ListNode()
19 |
20 | curr = head
21 | while curr:
22 | prev_node = pseudo_head
23 | next_node = prev_node.next
24 |
25 | # find the position to insert the current node
26 | while next_node:
27 | if curr.val < next_node.val:
28 | break
29 | prev_node = next_node
30 | next_node = next_node.next
31 |
32 | # insert the current node to the new list
33 | new_node = ListNode(curr.val)
34 | if next_node:
35 | new_node.next = next_node
36 | prev_node.next = new_node
37 |
38 | # moving on
39 | curr = curr.next
40 |
41 | return pseudo_head.next
42 |
43 |
44 |
--------------------------------------------------------------------------------
/python/148_sort_list.py:
--------------------------------------------------------------------------------
1 | # Definition for singly-linked list.
2 | # class ListNode:
3 | # def __init__(self, x):
4 | # self.val = x
5 | # self.next = None
6 |
7 | class Solution:
8 | def partition(self, head):
9 | pre, slow, fast = None, head, head
10 | while fast and fast.next:
11 | pre, slow, fast = slow, slow.next, fast.next.next
12 | pre.next = None
13 | return head, slow
14 |
15 | def merge(self, first, second):
16 |
17 | merge_head = ListNode()
18 | pm, p1, p2 = merge_head, first, second
19 | while p1 and p2:
20 | if p1.val <= p2.val:
21 | pm.next = p1
22 | p1 = p1.next
23 | else:
24 | pm.next = p2
25 | p2 = p2.next
26 | pm = pm.next
27 |
28 | pm.next = p1 or p2
29 | return merge_head.next
30 |
31 |
32 | def sortList(self, head: ListNode) -> ListNode:
33 | """
34 | :type head: ListNode
35 | :rtype: ListNode
36 | """
37 | if not head or not head.next:
38 | return head
39 |
40 | first_half, second_half = self.partition(head)
41 |
42 | first_half = self.sortList(first_half)
43 | second_half = self.sortList(second_half)
44 |
45 | return self.merge(first_half, second_half)
46 |
--------------------------------------------------------------------------------
/python/14_longest_common_prefix.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def longestCommonPrefix(self, strs: List[str]) -> str:
3 |
4 | def common_prefix(word_1, word_2):
5 | bound = min(len(word_1), len(word_2))
6 | index = 0
7 | while index < bound:
8 | if word_1[index] != word_2[index]:
9 | break
10 | index += 1
11 |
12 | return word_1[0:index]
13 |
14 | prefix = strs[0]
15 | for word in strs[1:]:
16 | prefix = common_prefix(prefix, word)
17 |
18 | return prefix
19 |
20 |
21 | def longestCommonPrefix_dict(self, strs: List[str]) -> str:
22 |
23 | prefix_dict = defaultdict(int)
24 |
25 | def indexing_prefix(word):
26 | nonlocal prefix_dict
27 | for index in range(1, len(word)+1):
28 | prefix = word[:index]
29 | prefix_dict[prefix] += 1
30 |
31 | for word in strs:
32 | indexing_prefix(word)
33 |
34 | max_prefix = ""
35 | for prefix, count in prefix_dict.items():
36 | if count == len(strs):
37 | if len(prefix) > len(max_prefix):
38 | max_prefix = prefix
39 |
40 | return max_prefix
41 |
--------------------------------------------------------------------------------
/python/1506_find_root_of_N-ary_tree.py:
--------------------------------------------------------------------------------
1 | """
2 | # Definition for a Node.
3 | class Node:
4 | def __init__(self, val=None, children=None):
5 | self.val = val
6 | self.children = children if children is not None else []
7 | """
8 |
9 | class Solution:
10 | def findRoot(self, tree: List['Node']) -> 'Node':
11 |
12 | node_indegree = {}
13 |
14 | for node in tree:
15 | if node not in node_indegree:
16 | node_indegree[node] = 0
17 | for child in node.children:
18 | node_indegree[child] = 1
19 |
20 | for node, indegree in node_indegree.items():
21 | if indegree == 0:
22 | return node
23 |
24 |
25 | class SolutionSet:
26 | def findRoot(self, tree: List['Node']) -> 'Node':
27 |
28 | seen = set()
29 |
30 | for node in tree:
31 | for child in node.children:
32 | seen.add(child.val)
33 |
34 | for node in tree:
35 | if node.val not in seen:
36 | return node
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/python/1508_range_sum_of_sorted_subarray_sums.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def rangeSum(self, nums: List[int], n: int, left: int, right: int) -> int:
3 |
4 | subarray_sums = []
5 | modulo = 10 ** 9 + 7
6 |
7 | for start_index, start_num in enumerate(nums):
8 | subarray_sum = 0
9 | for end_index, end_num in enumerate(nums[start_index:]):
10 | subarray_sum += end_num
11 | subarray_sums.append(subarray_sum)
12 |
13 | subarray_sums.sort()
14 |
15 | ret = 0
16 | for index in range(left-1, right):
17 | ret = (ret + subarray_sums[index]) % modulo
18 |
19 | return ret
20 |
--------------------------------------------------------------------------------
/python/1510_Stone_Game_IV.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def winnerSquareGame(self, n: int) -> bool:
3 |
4 | @lru_cache(maxsize=None)
5 | def dfs(remain):
6 | sqrt_root = int(sqrt(remain))
7 | # current player will win immediately by taking the square number tiles
8 | if sqrt_root ** 2 == remain:
9 | return True
10 |
11 | for i in range(1, sqrt_root+1):
12 | # if there is any chance to make the opponent lose the game in the next round,
13 | # then the current player will win.
14 | if not dfs(remain - i*i):
15 | return True
16 |
17 | return False
18 |
19 | return dfs(n)
20 |
--------------------------------------------------------------------------------
/python/151_find_minimum_in_rotated_sorted_array.py:
--------------------------------------------------------------------------------
1 | '''
2 | Suppose an array sorted in ascending order 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 | You may assume no duplicate exists in the array.
9 | '''
10 | class Solution:
11 | def findMin(self, nums: List[int]) -> int:
12 | low = 0
13 | high = len(nums)-1
14 | # the original array is either contains a single element
15 | # or is actually not rotated
16 | if low == len(nums) - 1 or nums[low] < nums[high]:
17 | return nums[low]
18 |
19 | while low < high:
20 | pivot = int((low+high)/2)
21 | #print('old', low, high, pivot)
22 |
23 | if pivot == len(nums)-1:
24 | return nums[-1]
25 | # found the rotation pivot !
26 | if nums[pivot] > nums[pivot+1]:
27 | return nums[pivot+1]
28 |
29 | if nums[pivot] >= nums[0]:
30 | low = pivot + 1
31 | else:
32 | high = pivot
33 |
34 | #print('new', low, high, pivot)
35 | return nums[pivot]
--------------------------------------------------------------------------------
/python/152_Maximum_Product_Subarray.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def maxProduct(self, nums: List[int]) -> int:
4 | """
5 | Keep the intermediate results of the previous num
6 | """
7 | curr_products = []
8 | max_product = float('-inf')
9 |
10 | for num in nums:
11 | curr_products.append(1)
12 | next_products = []
13 | for product in curr_products:
14 | new_product = num * product
15 | max_product = max(max_product, new_product)
16 | next_products.append(new_product)
17 |
18 | curr_products = next_products
19 |
20 | return max_product
21 |
22 |
23 | class SolutionDP:
24 | """
25 | Rather than keeping all the intermediate products,
26 | we take the two extreme numbers among the intermediate results,
27 | since only these two extreme numbers can change the final result.
28 | """
29 | def maxProduct(self, nums: List[int]) -> int:
30 |
31 | max_product = nums[0]
32 | max_sofar, min_sofar = nums[0], nums[0]
33 |
34 | for num in nums[1:]:
35 | new_min_sofar = num * min_sofar
36 | new_max_sofar = num * max_sofar
37 | min_sofar = min(num, new_min_sofar, new_max_sofar)
38 | max_sofar = max(num, new_min_sofar, new_max_sofar)
39 |
40 | max_product = max(max_product, max_sofar)
41 |
42 | return max_product
--------------------------------------------------------------------------------
/python/1539_Kth_Missing_Positive_Number.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def findKthPositive(self, arr: List[int], k: int) -> int:
3 |
4 | prev = 0
5 | missing_cnt = 0
6 |
7 | for curr in arr:
8 |
9 | # case 1). we find the missing number in between the array
10 | while prev < curr - 1:
11 | prev += 1
12 | missing_cnt += 1
13 | if missing_cnt == k:
14 | return prev
15 |
16 | prev = curr
17 |
18 | # case 2). we find the missing number beyond the array
19 | return curr + (k - missing_cnt)
20 |
--------------------------------------------------------------------------------
/python/154_Find_Minimum_in_Rotated_Sorted_Array_II.py:
--------------------------------------------------------------------------------
1 | """
2 | Suppose an array sorted in ascending order 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 | The array may contain duplicates.
9 |
10 | Example 1:
11 |
12 | Input: [1,3,5]
13 | Output: 1
14 |
15 | Example 2:
16 | Input: [2,2,2,0,1]
17 | Output: 0
18 | """
19 | class Solution:
20 | def findMin(self, nums: List[int]) -> int:
21 | low = 0
22 | high = len(nums)-1
23 | while high > low:
24 | pivot = low + (high - low) // 2
25 | # pivot = (low + high) // 2 could overflow
26 | # Case 1):
27 | if nums[pivot] < nums[high]:
28 | high = pivot
29 | # alternative: high = pivot - 1
30 | # too aggressive to move the `high` index,
31 | # it won't work for the test case of [3, 1, 3]
32 | # Case 2):
33 | elif nums[pivot] > nums[high]:
34 | low = pivot + 1
35 | # Case 3):
36 | else:
37 | high -= 1
38 | # the 'low' and 'high' index converge to the inflection point.
39 | return nums[low]
40 |
--------------------------------------------------------------------------------
/python/1570_dot_product_of_two_sparse_vectors.py:
--------------------------------------------------------------------------------
1 |
2 | class SparseVector:
3 | def __init__(self, nums: List[int]):
4 | self.value_table = {}
5 | for index, num in enumerate(nums):
6 | if num != 0:
7 | self.value_table[index] = num
8 |
9 | # Return the dotProduct of two sparse vectors
10 | def dotProduct(self, vec: 'SparseVector') -> int:
11 | if len(self.value_table) < len(vec.value_table):
12 | small_table = self.value_table
13 | large_table = vec.value_table
14 | else:
15 | small_table = vec.value_table
16 | large_table = self.value_table
17 |
18 | dot_product = 0
19 | for key, value in small_table.items():
20 | if key in large_table:
21 | dot_product += value * large_table[key]
22 |
23 | return dot_product
24 |
25 | # Your SparseVector object will be instantiated and called as such:
26 | # v1 = SparseVector(nums1)
27 | # v2 = SparseVector(nums2)
28 | # ans = v1.dotProduct(v2)
--------------------------------------------------------------------------------
/python/163_missing_ranges.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def findMissingRanges(self, nums: List[int], lower: int, upper: int) -> List[str]:
3 |
4 | range_iter = lower
5 | num_iter = 0
6 | ranges = []
7 | while range_iter < upper and num_iter < len(nums):
8 | if range_iter < nums[num_iter]:
9 | if nums[num_iter] - 1 == range_iter:
10 | ranges.append(str(range_iter))
11 | else:
12 | ranges.append("{}->{}".format(range_iter, nums[num_iter]-1))
13 |
14 | range_iter = nums[num_iter] + 1
15 | num_iter += 1
16 |
17 | if num_iter >= len(nums) and range_iter == upper:
18 | ranges.append("{}".format(range_iter))
19 | elif range_iter < upper:
20 | ranges.append("{}->{}".format(range_iter, upper))
21 |
22 | return ranges
--------------------------------------------------------------------------------
/python/165_compare_version_number.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def compareVersion(self, version1: str, version2: str) -> int:
3 |
4 | revision_list_1 = [int(i) for i in version1.split(".")]
5 | revision_list_2 = [int(i) for i in version2.split(".")]
6 |
7 | def padding(revisions, to_length):
8 | for i in range(len(revisions), to_length):
9 | revisions.append(0)
10 | return revisions
11 |
12 | max_length = max(len(revision_list_1), len(revision_list_2))
13 | padded_revision_1 = padding(revision_list_1, max_length)
14 | padded_revision_2 = padding(revision_list_2, max_length)
15 | for p in range(0, max_length):
16 | if padded_revision_1[p] > padded_revision_2[p]:
17 | return 1
18 | elif padded_revision_1[p] < padded_revision_2[p]:
19 | return -1
20 |
21 | return 0
22 |
--------------------------------------------------------------------------------
/python/1676_lowest_common_ancestor_for_multiple_nodes.py:
--------------------------------------------------------------------------------
1 |
2 | # Definition for a binary tree node.
3 | # class TreeNode:
4 | # def __init__(self, x):
5 | # self.val = x
6 | # self.left = None
7 | # self.right = None
8 |
9 | class Solution:
10 | def lowestCommonAncestor(self, root: 'TreeNode', nodes: 'List[TreeNode]') -> 'TreeNode':
11 |
12 | value_subset = set([node.val for node in nodes])
13 |
14 | result = None
15 | def get_descendants(parent):
16 | nonlocal result
17 |
18 | if not parent:
19 | return set()
20 |
21 | left_nodes = get_descendants(parent.left)
22 | if result:
23 | return set()
24 | right_nodes = get_descendants(parent.right)
25 |
26 | all_nodes = {parent.val} | left_nodes | right_nodes
27 |
28 | if value_subset.issubset(all_nodes) and not result:
29 | result = parent
30 |
31 | return all_nodes
32 |
33 | get_descendants(root)
34 | return result
35 |
--------------------------------------------------------------------------------
/python/169_major_element.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def majorityElement(self, nums: List[int]) -> int:
3 | """ Boyer-Moore voting algorithm"""
4 | candidate, count = 0, 0
5 |
6 | for num in nums:
7 | if count == 0:
8 | candidate = num
9 |
10 | count += (1 if num == candidate else -1)
11 |
12 | return candidate
--------------------------------------------------------------------------------
/python/1701_average_waiting_time.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def averageWaitingTime(self, customers: List[List[int]]) -> float:
3 |
4 | prev_end = customers[0][0]
5 |
6 | total_time = 0
7 | for customer in customers:
8 | arrival, duration = customer[0], customer[1]
9 |
10 | if prev_end > arrival:
11 | # delayed by the previous customer
12 | wait_time = prev_end - arrival + duration
13 | prev_end = prev_end + duration
14 | else:
15 | # the chef is idle and thus serve the customer immediately
16 | wait_time = duration
17 | prev_end = arrival + duration
18 |
19 | total_time += wait_time
20 |
21 | return total_time / len(customers)
22 |
23 |
24 |
--------------------------------------------------------------------------------
/python/1710_maximum_capacity_on_truck.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class Solution:
4 | def maximumUnits(self, boxTypes: List[List[int]], truckSize: int) -> int:
5 |
6 | # Greedy algorithm
7 | # load the boxes prioritized on the their capacities
8 | boxTypes.sort(key=lambda x:x[1], reverse=True)
9 |
10 | unit_sum = 0
11 | for box_num, box_units in boxTypes:
12 | if truckSize == 0:
13 | break
14 |
15 | if truckSize > box_num:
16 | truckSize -= box_num
17 | unit_sum += box_num * box_units
18 | else:
19 | unit_sum += truckSize * box_units
20 | truckSize = 0
21 |
22 | return unit_sum
23 |
--------------------------------------------------------------------------------
/python/1721_swapping_nodes_in_a_linked_list.py:
--------------------------------------------------------------------------------
1 |
2 | # Definition for singly-linked list.
3 | # class ListNode:
4 | # def __init__(self, val=0, next=None):
5 | # self.val = val
6 | # self.next = next
7 | class Solution:
8 | def swapNodes(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
9 |
10 | first_switch, second_switch = None, None
11 |
12 | step = 1
13 | # the distance between the 'prev' and 'curr' is k steps,
14 | # so when the 'curr' reaches the end, the 'prev' would be the second switching point
15 | curr, prev = head, None
16 |
17 | while curr:
18 | if prev:
19 | prev = prev.next
20 |
21 | if step == k:
22 | # kick of the 'prev' pointer
23 | first_switch = curr
24 | prev = head
25 |
26 | # move on to the next step
27 | curr = curr.next
28 | step += 1
29 |
30 | second_switch = prev
31 |
32 | first_switch.val, second_switch.val = second_switch.val, first_switch.val
33 |
34 | return head
--------------------------------------------------------------------------------
/python/1722_minimum_hamming_distance_after_swapping_operations.py:
--------------------------------------------------------------------------------
1 | class UnionFind:
2 |
3 | def __init__(self, size):
4 | self.parent = [i for i in range(size)]
5 |
6 | def find(self, a):
7 | if self.parent[a] != a:
8 | self.parent[a] = self.find(self.parent[a])
9 | return self.parent[a]
10 |
11 | def union(self, a, b):
12 | ga = self.find(a)
13 | gb = self.find(b)
14 | if ga != gb:
15 | self.parent[ga] = self.parent[gb]
16 |
17 |
18 | class Solution:
19 | def minimumHammingDistance(self, source: List[int], target: List[int], allowedSwaps: List[List[int]]) -> int:
20 |
21 | str_len = len(source)
22 |
23 | uf = UnionFind(str_len)
24 | for a, b in allowedSwaps:
25 | uf.union(a, b)
26 |
27 | group_index = defaultdict(list)
28 | for index in range(str_len):
29 | group_id = uf.find(index)
30 | group_index[group_id].append(index)
31 |
32 | hamming_distance = 0
33 | for group_id, group_index in group_index.items():
34 | source_counter = Counter([source[i] for i in group_index])
35 | target_counter = Counter([target[i] for i in group_index])
36 | common_elements = source_counter & target_counter
37 | hamming_distance += len(group_index) - sum(common_elements.values())
38 |
39 | return hamming_distance
40 |
41 |
42 |
--------------------------------------------------------------------------------
/python/1730_shortest_path_to_get_food.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def getFood(self, grid: List[List[str]]) -> int:
4 |
5 | start = None
6 |
7 | # 1). Locate the starting point first
8 | ROWS = len(grid)
9 | COLS = len(grid[0])
10 | for row in range(ROWS):
11 | for col in range(COLS):
12 | if grid[row][col] == '*':
13 | start = (row, col)
14 | break
15 |
16 | grid[start[0]][start[1]] = "X"
17 | queue = deque([(start, 0)])
18 |
19 | # Run a BFS search to find the "nearest" target/food.
20 | while queue:
21 | (row, col), distance = queue.popleft()
22 |
23 | for r_offset, c_offset in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
24 | next_row, next_col = row + r_offset, col + c_offset
25 | if 0 > next_row or next_row == ROWS or 0 > next_col or next_col == COLS:
26 | continue
27 | if grid[next_row][next_col] == "X":
28 | continue
29 | elif grid[next_row][next_col] == "#": # find the food
30 | return distance + 1
31 | else: # open space
32 | # OPTIMIZATION: reduce the number of elements in queue
33 | grid[next_row][next_col] = "X" # mark it as visited
34 | queue.append(((next_row, next_col), distance+1))
35 |
36 | return -1
--------------------------------------------------------------------------------
/python/1754_largest_merge_of_two_strings.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def largestMerge(self, word1: str, word2: str) -> str:
3 |
4 | index_1, index_2 = 0, 0
5 | len_1, len_2 = len(word1), len(word2)
6 |
7 | merge = []
8 | while index_1 < len_1 or index_2 < len_2:
9 |
10 | if index_1 == len_1:
11 | merge.append(word2[index_2])
12 | index_2 += 1
13 | elif index_2 == len_2:
14 | merge.append(word1[index_1])
15 | index_1 += 1
16 | else: # both index are valid
17 | # look ahead of the rest of the substring
18 | # pick the larger substring
19 | if word1[index_1:] >= word2[index_2:]:
20 | merge.append(word1[index_1])
21 | index_1 += 1
22 | else:
23 | merge.append(word2[index_2])
24 | index_2 += 1
25 |
26 | return "".join(merge)
27 |
--------------------------------------------------------------------------------
/python/1759_count_number_of_homogenous_substrings.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def countHomogenous(self, s: str) -> int:
4 |
5 | modulo = 10 ** 9 + 7
6 |
7 | total_substr = 0
8 | substr_len = 1
9 | prev = s[0]
10 |
11 | for curr in s[1:]:
12 | if curr == prev:
13 | substr_len += 1
14 | else:
15 | # calculate each part of the consecutive substring
16 | total_substr += (1 + substr_len) * substr_len // 2
17 | # reset
18 | prev = curr
19 | substr_len = 1
20 |
21 | # the last part of the homogenous substring
22 | total_substr += (1 + substr_len) * substr_len // 2
23 |
24 | return total_substr % modulo
--------------------------------------------------------------------------------
/python/176_Excel_Sheet_Column_Number.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def titleToNumber(self, s: str) -> int:
3 |
4 | length = len(s)
5 | num = 0
6 | for i in range(0, length):
7 | num += (ord(s[length-i-1]) - ord('A') + 1) * (26 ** i)
8 |
9 | return num
--------------------------------------------------------------------------------
/python/17_letter_combination_of_a_phone_number.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def letterCombinations(self, digits: str) -> List[str]:
4 |
5 | digit_map = {"2": "abc", "3": "def", "4": "ghi", '5': "jkl",
6 | "6": "mno", "7": "pqrs", "8": "tuv", "9": "wxyz"}
7 |
8 | output = []
9 |
10 | def dfs(curr_index, comb):
11 | nonlocal output
12 |
13 | if curr_index == len(digits):
14 | output.append("".join(comb))
15 | return
16 |
17 | digit = digits[curr_index]
18 | for letter in digit_map[digit]:
19 | comb.append(letter)
20 | dfs(curr_index+1, comb)
21 | comb.pop()
22 |
23 | if len(digits) == 0:
24 | return []
25 |
26 | dfs(0, [])
27 | return output
28 |
--------------------------------------------------------------------------------
/python/189_Rotate_Array.py:
--------------------------------------------------------------------------------
1 | class SolutionReverse:
2 | def reverse(self, nums, start, end):
3 | while start < end:
4 | nums[start], nums[end] = nums[end], nums[start]
5 | start, end = start+1, end-1
6 |
7 | def rotate(self, nums: List[int], k: int) -> None:
8 | length = len(nums)
9 | k %= length
10 |
11 | # reverse the array in three times: first the entire array,
12 | # then first and second part respectively
13 | self.reverse(nums, 0, length-1)
14 | self.reverse(nums, 0, k-1)
15 | self.reverse(nums, k, length-1)
16 |
17 |
18 | class SolutionShift:
19 | def rotate(self, nums: List[int], k: int) -> None:
20 | """
21 | Do not return anything, modify nums in-place instead.
22 | """
23 | for i in range(k):
24 | prev = nums[-1]
25 | # shift the array to the right, once at a time
26 | for j in range(len(nums)):
27 | nums[j], prev = prev, nums[j]
--------------------------------------------------------------------------------
/python/198_House_Robber.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def rob(self, nums: List[int]) -> int:
3 |
4 | to_rob, not_to_rob = 0, 0
5 |
6 | # state machine
7 | # At each step, we calculate profits of two choices: to_rob, not_to_rob
8 | for num in nums:
9 | # if we break down into two statements,
10 | # we need some temporary values to ensure the same results.
11 | to_rob, not_to_rob = max(not_to_rob + num, to_rob), max(to_rob, not_to_rob)
12 |
13 | return max(to_rob, not_to_rob)
14 |
15 |
16 | class SolutionRecursionMemoization:
17 | def rob(self, nums: List[int]) -> int:
18 |
19 | @functools.lru_cache(maxsize=None)
20 | def dfs(start, accu):
21 |
22 | if start >= len(nums):
23 | return accu
24 |
25 | return max(dfs(start+1, accu), dfs(start+2, accu + nums[start]))
26 |
27 | return dfs(0, 0)
28 |
29 |
30 | class SolutionDP:
31 | def rob(self, nums: List[int]) -> int:
32 |
33 | N = len(nums)
34 | dp = [0] * (len(nums) + 1)
35 |
36 | dp[N-1] = nums[N-1]
37 |
38 | for i in range(N-2, -1, -1):
39 | dp[i] = max(dp[i+1], dp[i+2] + nums[i])
40 |
41 | return dp[0]
42 |
--------------------------------------------------------------------------------
/python/199_Binary_Tree_with_Right_Side_View.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def rightSideView(self, root: TreeNode) -> List[int]:
9 |
10 | results = []
11 |
12 | def DFS(node, depth):
13 | if node:
14 | if depth == len(results):
15 | results.append(node.val)
16 | # preorder with the priority on the right child
17 | DFS(node.right, depth+1)
18 | DFS(node.left, depth+1)
19 |
20 | DFS(root , 0)
21 | return results
22 |
--------------------------------------------------------------------------------
/python/206_reverse_linked_list.py:
--------------------------------------------------------------------------------
1 | # Definition for singly-linked list.
2 | # class ListNode:
3 | # def __init__(self, val=0, next=None):
4 | # self.val = val
5 | # self.next = next
6 | class Solution:
7 | def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
8 |
9 | prev, curr = None, head
10 | while curr:
11 | next_curr = curr.next
12 | curr.next = prev
13 |
14 | prev = curr
15 | curr = next_curr
16 |
17 | return prev
18 |
19 |
20 | # Definition for singly-linked list.
21 | # class ListNode:
22 | # def __init__(self, val=0, next=None):
23 | # self.val = val
24 | # self.next = next
25 | class Solution:
26 | def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
27 |
28 | # return the new head element
29 | if head is None or head.next is None:
30 | return head
31 |
32 | new_head = self.reverseList(head.next)
33 |
34 | # reverse the pair of elements: head, head->next
35 | head.next.next = head
36 | head.next = None
37 |
38 | return new_head
39 |
--------------------------------------------------------------------------------
/python/2073_time_needed_to_buy_tickets.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def timeRequiredToBuy(self, tickets: List[int], k: int) -> int:
3 |
4 | clock = 0
5 | while tickets[k]:
6 |
7 | for index, ticket in enumerate(tickets):
8 | if ticket > 0:
9 | tickets[index] -= 1
10 | clock += 1
11 |
12 | # stop the clock as soon as the target reaches zero
13 | if tickets[k] == 0:
14 | return clock
15 |
16 | return clock
--------------------------------------------------------------------------------
/python/20_Valid_Parentheses.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def isValid(self, s: str) -> bool:
3 | stack = []
4 |
5 | bracket_map = { ")": "(", "}": "{" , "]": "["}
6 |
7 | for char in s:
8 | if char not in bracket_map:
9 | stack.append(char)
10 | else:
11 | if stack and stack.pop() == bracket_map[char]:
12 | continue
13 | else:
14 | return False
15 |
16 | return len(stack) == 0
17 |
--------------------------------------------------------------------------------
/python/216_combination_sum_III.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def combinationSum3(self, k: int, n: int) -> List[List[int]]:
4 |
5 | global_set = []
6 |
7 | def backtrack(remain, comb, next_start):
8 | """
9 | remain: remaining sum
10 | comb: the current combination
11 | next_start: the starting index for the next candidates
12 |
13 | Pick the candidates in order,
14 | so that we won't have any duplidates
15 | e.g. if we picked the number 3 in the previous step,
16 | then in the following steps,
17 | the list of candiates become [4 5, ... 9]
18 | """
19 | if remain == 0 and len(comb) == k:
20 | # make a copy of current combination
21 | global_set.append(list(comb))
22 | return
23 | elif remain < 0 or len(comb) == k:
24 | return
25 |
26 | for i in range(next_start, 9):
27 | comb.append(i+1)
28 | backtrack(remain-i-1, comb, i+1)
29 | comb.pop()
30 |
31 | comb = []
32 | backtrack(n, comb, 0)
33 |
34 | return global_set
35 |
--------------------------------------------------------------------------------
/python/220_Contains_Duplicates_III.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
3 | """
4 | bucket sort alike algorithm
5 | """
6 | buckets = {}
7 | window = (t+1)
8 |
9 | if t < 0:
10 | return False
11 |
12 | def locate(num):
13 | return num // window
14 |
15 | for index, num in enumerate(nums):
16 | bucket_id = locate(num)
17 |
18 | left = bucket_id - 1
19 | right = bucket_id + 1
20 |
21 | # check [left_bucket][current_bucket][right_bucket]
22 | if bucket_id in buckets:
23 | return True
24 | if left in buckets and abs(num - buckets[left]) < window:
25 | return True
26 | if right in buckets and abs(buckets[right] - num) < window:
27 | return True
28 |
29 | buckets[bucket_id] = num
30 |
31 | if len(buckets) > k:
32 | buckets.pop(locate(nums[index-k]))
33 |
34 | return False
--------------------------------------------------------------------------------
/python/228_summary_range.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def summaryRanges(self, nums: List[int]) -> List[str]:
3 |
4 | def format_range(low, high):
5 | return str(low) if low == high else "{}->{}".format(low, high)
6 |
7 | results = []
8 |
9 | if len(nums) == 0:
10 | return results
11 |
12 | low = nums[0]
13 | for i in range(1, len(nums)):
14 | if nums[i] - nums[i-1] > 1:
15 | results.append(format_range(low, nums[i-1]))
16 | low = nums[i]
17 |
18 | results.append(format_range(low, nums[-1]))
19 |
20 | return results
--------------------------------------------------------------------------------
/python/229_major_elements_II.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def majorityElement(self, nums: List[int]) -> List[int]:
3 |
4 | major_elements = defaultdict(int)
5 |
6 | # voting for the major elements
7 | for num in nums:
8 | major_elements[num] += 1
9 | if len(major_elements) == 3:
10 | to_delete = []
11 | for k, v in major_elements.items():
12 | major_elements[k] -= 1
13 | if v == 1:
14 | to_delete.append(k)
15 | for k in to_delete:
16 | del major_elements[k]
17 |
18 | ret = []
19 | # a second round to verify if the major elements takes 1/3 votes
20 | for elem in major_elements:
21 | if nums.count(elem) > len(nums) / 3:
22 | ret.append(elem)
23 |
24 | return ret
--------------------------------------------------------------------------------
/python/238_product_of_array_except_self.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class Solution:
4 | def productExceptSelf(self, nums: List[int]) -> List[int]:
5 |
6 | num_len = len(nums)
7 | prefix_products, postfix_products = [1] * (num_len + 1), [1] * (num_len + 1)
8 |
9 | prefix_product, postfix_product = 1, 1
10 |
11 | for prefix_index in range(num_len):
12 | prefix_product *= nums[prefix_index]
13 | prefix_products[prefix_index+1] = prefix_product
14 |
15 | postfix_index = num_len - 1 - prefix_index
16 | postfix_product *= nums[postfix_index]
17 | postfix_products[postfix_index] = postfix_product
18 |
19 | infix_products = []
20 | for index in range(num_len):
21 | infix_products.append(prefix_products[index] * postfix_products[index+1])
22 |
23 | return infix_products
24 |
25 |
--------------------------------------------------------------------------------
/python/242_valid_anagrams.py:
--------------------------------------------------------------------------------
1 |
2 | """
3 |
4 | """
5 | class Solution:
6 | def isAnagram(self, s, t):
7 | """
8 | :type s: str
9 | :type t: str
10 | :rtype: bool
11 | """
12 | if (len(s) != len(t)):
13 | return False
14 |
15 | def to_dict(word):
16 | ret = {}
17 | for letter in word:
18 | if letter in ret:
19 | ret[letter] +=1
20 | else:
21 | ret[letter] = 1
22 | return ret
23 |
24 | dict_1 = to_dict(s)
25 | dict_2 = to_dict(t)
26 | return (dict_1 == dict_2)
27 |
28 |
29 |
30 | if __name__ == "__main__":
31 |
32 | solution = Solution()
33 |
34 | print(solution.isAnagram("abcd", "bcda"))
35 |
36 |
37 |
--------------------------------------------------------------------------------
/python/249_group_shifted_strings.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def groupStrings(self, strings: List[str]) -> List[List[str]]:
4 |
5 | str_table = defaultdict(list)
6 |
7 | for string in strings:
8 | str_len = len(string)
9 | if str_len == 1:
10 | str_table[(1)].append(string)
11 | else:
12 | # list of distances between each adjacent letters
13 | key = []
14 | for index in range(1, str_len):
15 | diff = (ord(string[index]) - ord(string[index-1]) + 26) % 26
16 | key.append(diff)
17 |
18 | str_table[tuple(key)].append(string)
19 |
20 | return str_table.values()
21 |
--------------------------------------------------------------------------------
/python/252_meeting_room.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def canAttendMeetings(self, intervals: List[List[int]]) -> bool:
3 |
4 | intervals.sort(key = lambda x: x[0])
5 |
6 | for curr in range(0, len(intervals)-1):
7 | curr_interval = intervals[curr]
8 | next_interval = intervals[curr+1]
9 | if curr_interval[1] > next_interval[0]:
10 | return False
11 |
12 | return True
13 |
--------------------------------------------------------------------------------
/python/257_binary_tree_paths.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def binaryTreePaths(self, root: TreeNode) -> List[str]:
9 |
10 | output = []
11 |
12 | def backtrack(node, path):
13 |
14 | if node.left is None and node.right is None:
15 | output.append("->".join(path))
16 | return
17 |
18 | for child in [node.left, node.right]:
19 | if child is None:
20 | continue
21 | path.append(str(child.val))
22 | backtrack(child, path)
23 | path.pop()
24 |
25 | if root is not None:
26 | path = [str(root.val)]
27 | backtrack(root, path)
28 |
29 | return output
30 |
--------------------------------------------------------------------------------
/python/266_Palindrome_Permutation.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def canPermutePalindrome(self, s: str) -> bool:
3 | char_set = set()
4 |
5 | for char in s:
6 | if char in char_set:
7 | char_set.remove(char)
8 | else:
9 | char_set.add(char)
10 | return len(char_set) <= 1
11 |
--------------------------------------------------------------------------------
/python/276_Paint_Fence.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def numWays(self, n: int, k: int) -> int:
3 |
4 | if n == 0:
5 | return 0
6 | elif n == 1:
7 | return k
8 | elif (k == 1) and (n >= 3):
9 | return 0
10 |
11 | dp = [0 for i in range(n)]
12 | dp[0] = k
13 | dp[1] = k * k
14 |
15 | for i in range(2, n):
16 | # case 1). last two fences of the same colors
17 | # case 2). last two fences of different colors
18 | dp[i] = (dp[i-1] + dp[i-2]) * (k - 1)
19 |
20 | return dp[-1]
21 |
--------------------------------------------------------------------------------
/python/283_move_zeroes.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def moveZeroes(self, nums: List[int]) -> None:
3 | """
4 | Do not return anything, modify nums in-place instead.
5 | """
6 | read_index, write_index = 0, -1
7 | len_nums = len(nums)
8 |
9 | # shift non-zero numbers to the head of the list
10 | while read_index < len_nums:
11 | if nums[read_index] != 0:
12 | write_index += 1
13 | nums[write_index] = nums[read_index]
14 | read_index += 1
15 |
16 | # reset the rest of numbers to zeroes
17 | write_index += 1
18 | while write_index < len_nums:
19 | nums[write_index] = 0
20 | write_index += 1
21 |
--------------------------------------------------------------------------------
/python/300_Longest_Increasing_Subsequence.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an unsorted array of integers, find the length of longest increasing subsequence.
3 |
4 | Example:
5 |
6 | Input: [10,9,2,5,3,7,101,18]
7 | Output: 4
8 |
9 |
10 | Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.
11 |
12 |
13 | Note:
14 | - There may be more than one LIS combination, it is only necessary for you to return the length.
15 | - Your algorithm should run in O(n2) complexity.
16 |
17 | Follow up:
18 | Could you improve it to O(n log n) time complexity?
19 | """
20 | class Solution(object):
21 | def lengthOfLIS(self, nums):
22 | """
23 | :type nums: List[int]
24 | :rtype: int
25 | """
26 | if len(nums) == 0:
27 | return 0
28 |
29 | # the longest increasing subsequence for the prefix [0...i]
30 | dp = [1] * (len(nums))
31 |
32 | globalMaxLen = -1
33 |
34 | for i, num in enumerate(nums):
35 | localMaxLen = 1
36 | for k in range(i):
37 | if nums[i] > nums[k]:
38 | localMaxLen = max(dp[k]+1, localMaxLen)
39 |
40 | dp[i] = localMaxLen
41 | globalMaxLen = max(localMaxLen, globalMaxLen)
42 |
43 | return globalMaxLen
44 |
--------------------------------------------------------------------------------
/python/301_remove_invalid_parentheses.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def removeInvalidParentheses(self, s: str) -> List[str]:
3 |
4 | def is_valid(expr):
5 | """ quick check if the expression is valid """
6 | balance = 0
7 | # the balance should always be >= 0
8 | for char in expr:
9 | if char not in '()':
10 | continue
11 |
12 | if char == "(":
13 | balance += 1
14 | elif char == ")":
15 | balance -= 1
16 |
17 | if balance < 0:
18 | return False
19 | return balance == 0
20 |
21 | queue = deque([s])
22 | visited = set([s])
23 | found = False
24 | output = []
25 |
26 | while queue:
27 | substr = queue.popleft()
28 |
29 | if is_valid(substr):
30 | output.append(substr)
31 | found = True
32 |
33 | # once found the first qualified elements, stop exploring further
34 | if found:
35 | continue
36 |
37 | for index in range(len(substr)):
38 | if substr[index] not in "()":
39 | continue
40 | new_str = substr[:index] + substr[index+1:]
41 | if new_str not in visited:
42 | visited.add(new_str)
43 | queue.append(new_str)
44 |
45 | return output
46 |
47 |
--------------------------------------------------------------------------------
/python/306_Additive_Number.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def isAdditiveNumber(self, num: str) -> bool:
3 |
4 |
5 | def dfs(prev_sum_str, prev_num_str, start, count):
6 |
7 | if start > len(num) - 1:
8 | return True if count >= 3 else False
9 | elif len(num) - start + 1 < len(prev_sum_str):
10 | return False
11 | elif num[start:(start+len(prev_sum_str))] != prev_sum_str:
12 | return False
13 | else:
14 | next_start = start + len(prev_sum_str)
15 | next_sum = int(prev_sum_str) + int(prev_num_str)
16 | return dfs(str(next_sum), prev_sum_str, next_start, count+1)
17 |
18 |
19 | for first_sep in range(1, len(num)-1):
20 | first_num = int(num[0:first_sep])
21 | # skip the numbers with leading zero, e.g. "02"
22 | if first_sep > 1 and first_num < 10:
23 | break
24 |
25 | for second_sep in range(first_sep+1, len(num)):
26 | prev_num = int(num[first_sep:second_sep])
27 | # skip the numbers with leading zero, e.g. "02"
28 | if second_sep - first_sep > 1 and prev_num < 10:
29 | break
30 |
31 | prev_sum = first_num + prev_num
32 | if dfs(str(prev_sum), str(prev_num), second_sep, 2):
33 | return True
34 |
35 | return False
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/python/309_Buy_and_Sell_Stock_with_Cooldown.py:
--------------------------------------------------------------------------------
1 | class Solution(object):
2 | def maxProfit(self, prices):
3 | """
4 | :type prices: List[int]
5 | :rtype: int
6 | """
7 | L = len(prices)
8 | dp = [0] * (L + 2)
9 |
10 | for buy in range(L-1, -1, -1):
11 | max_profit = 0
12 | for sell in range(buy+1, L):
13 | profit = (prices[sell] - prices[buy]) + dp[sell+2]
14 | max_profit = max(profit, max_profit)
15 |
16 | # In addition, we need to compare with doing no transaction
17 | dp[buy] = max(max_profit, dp[buy+1])
18 |
19 | return dp[0]
20 |
--------------------------------------------------------------------------------
/python/311_Sparse_Matrix_Multiplication.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def multiply(self, mat1: List[List[int]], mat2: List[List[int]]) -> List[List[int]]:
3 |
4 | # convert the second matrix to column-based vectors
5 | col_vecs = [[] for i in range(len(mat2[0]))]
6 | for row in mat2:
7 | for col_index, col in enumerate(row):
8 | col_vecs[col_index].append(col)
9 |
10 | result = [[] for i in range(len(mat1))]
11 | for row_index, row_vec in enumerate(mat1):
12 | for col_index, col_vec in enumerate(col_vecs):
13 | dot_product = sum([a*b for (a, b) in zip(row_vec, col_vec)])
14 | result[row_index].append(dot_product)
15 |
16 | return result
17 |
--------------------------------------------------------------------------------
/python/314_binary_tree_vertical_order_traversal.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, x):
4 | # self.val = x
5 | # self.left = None
6 | # self.right = None
7 | from collections import defaultdict
8 | class Solution:
9 | def verticalOrder(self, root: TreeNode) -> List[List[int]]:
10 | columnTable = defaultdict(list)
11 | queue = deque([(root, 0),])
12 |
13 | while queue:
14 | node, column = queue.popleft()
15 |
16 | if node is not None:
17 | columnTable[column].append(node.val)
18 |
19 | queue.append((node.left, column - 1))
20 | queue.append((node.right, column + 1))
21 |
22 | return [columnTable[x] for x in sorted(columnTable.keys())]
23 |
--------------------------------------------------------------------------------
/python/31_next_permutation.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def nextPermutation(self, nums: List[int]) -> None:
3 | """
4 | Do not return anything, modify nums in-place instead.
5 | """
6 | def swap(array, i, j):
7 | array[i], array[j] = array[j], array[i]
8 |
9 | def reverse(array, start):
10 | """ reverse the postfix subarray starting from 'start' """
11 | end = len(array) - 1
12 | while start < end:
13 | array[start], array[end] = array[end], array[start]
14 | start += 1
15 | end -= 1
16 |
17 | # locate the pair of elements to switch
18 | i = len(nums) - 2
19 | while i >= 0:
20 | if nums[i] < nums[i+1]:
21 | break
22 | i -= 1
23 |
24 | if i >= 0:
25 | j = len(nums) - 1
26 | while j > 0:
27 | if nums[j] > nums[i]:
28 | break
29 | j -= 1
30 |
31 | swap(nums, i, j)
32 |
33 | # reverse the postfix in order to obtain the minimal permutation
34 | reverse(nums, i+1)
35 |
--------------------------------------------------------------------------------
/python/323_number_of_connected_components_in_graph.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def countComponents(self, n: int, edges: List[List[int]]) -> int:
3 |
4 | graph = defaultdict(list)
5 | for edge in edges:
6 | start, end = edge[0], edge[1]
7 | graph[start].append(end)
8 | graph[end].append(start)
9 |
10 | visited = [False for _ in range(n)]
11 |
12 | def explore(node, visited):
13 | if visited[node]:
14 | return
15 |
16 | visited[node] = True
17 | for neighbor in graph[node]:
18 | if not visited[neighbor]:
19 | explore(neighbor, visited)
20 |
21 | component_cnt = 0
22 |
23 | for node in range(n):
24 | if not visited[node]:
25 | explore(node, visited)
26 | component_cnt += 1
27 |
28 | return component_cnt
29 |
30 |
--------------------------------------------------------------------------------
/python/325_maximum_size_subarray_sum_equals_K.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def maxSubArrayLen(self, nums: List[int], k: int) -> int:
3 |
4 | max_subarray = 0
5 | prefix_sum_index = {}
6 | prefix_sum = 0
7 |
8 | for index in range(0, len(nums)):
9 |
10 | prefix_sum += nums[index]
11 |
12 | if prefix_sum == k:
13 | # use only the prefix
14 | max_subarray = max(max_subarray, index + 1)
15 |
16 | if prefix_sum not in prefix_sum_index:
17 | prefix_sum_index[prefix_sum] = index
18 |
19 | target = prefix_sum - k
20 | if target in prefix_sum_index:
21 | prev_index = prefix_sum_index[target]
22 | max_subarray = max(max_subarray, index - prev_index)
23 |
24 | return max_subarray
25 |
26 |
27 |
--------------------------------------------------------------------------------
/python/329_longest_increasing_path_in_matrix.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def longestIncreasingPath(self, matrix: List[List[int]]) -> int:
3 |
4 | if len(matrix) == 0:
5 | return 0
6 |
7 | rows = len(matrix)
8 | cols = len(matrix[0])
9 |
10 | @lru_cache(maxsize=None)
11 | def dfs(row, col):
12 | ans = 0
13 | for ro, co in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
14 | new_row, new_col = row + ro, col + co
15 | if 0 <= new_row and new_row < rows and \
16 | 0 <= new_col and new_col < cols and \
17 | matrix[new_row][new_col] > matrix[row][col]:
18 | ans = max(ans, dfs(new_row, new_col))
19 | return ans + 1
20 |
21 | max_paths = 0
22 | for row in range(rows):
23 | for col in range(cols):
24 | max_paths = max(max_paths, dfs(row, col))
25 |
26 | return max_paths
--------------------------------------------------------------------------------
/python/337_house_robber_III.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def rob(self, root: TreeNode) -> int:
9 |
10 | @lru_cache(maxsize=None)
11 | def dfs(node, can_rob, acc_sum):
12 | if not node:
13 | return acc_sum
14 |
15 | max_sum = acc_sum
16 |
17 | if can_rob:
18 | # rob the current node
19 | left_sum = dfs(node.left, False, 0)
20 | right_sum = dfs(node.right, False, 0)
21 | max_sum += node.val + left_sum + right_sum
22 |
23 | # either cannot or choose not to rob the current node
24 | left_sum = dfs(node.left, True, 0)
25 | right_sum = dfs(node.right, True, 0)
26 | max_sum = max(max_sum, left_sum + right_sum)
27 |
28 | return max_sum
29 |
30 | first_try = dfs(root, True, 0)
31 | second_try = dfs(root, False, 0)
32 |
33 | return max(first_try, second_try)
34 |
35 |
--------------------------------------------------------------------------------
/python/342_power_of_four.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def isPowerOfFour(self, num: int) -> bool:
3 |
4 | return num > 0 and math.log2(num) % 2 == 0
5 | # num & (num - 1) == 0 // power of two
6 | # num & 0xaaaaaaaa == 0 // odd number of power of twos
7 | #return num > 0 and num & (num-1) == 0 and (num & 0xaaaaaaaa) == 0
8 |
--------------------------------------------------------------------------------
/python/345_reverse_vowels_of_string.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def reverseVowels(self, s: str) -> str:
4 |
5 | letter_list = []
6 | vowel_index_list = []
7 |
8 | VOWELS = ['a', 'e', 'i', 'o', 'u',
9 | 'A', 'E', 'I', 'O', 'U']
10 |
11 | for index, letter in enumerate(s):
12 | letter_list.append(letter)
13 | if letter in VOWELS:
14 | vowel_index_list.append(index)
15 |
16 | vowel_index = 0
17 | total_vowels = len(vowel_index_list)
18 |
19 | left, right = 0, len(vowel_index_list) - 1
20 |
21 | while left < right:
22 | left_index = vowel_index_list[left]
23 | right_index = vowel_index_list[right]
24 | letter_list[left_index], letter_list[right_index] \
25 | = letter_list[right_index], letter_list[left_index]
26 |
27 | left += 1
28 | right -= 1
29 |
30 | return "".join(letter_list)
--------------------------------------------------------------------------------
/python/346_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 |
6 | MovingAverage m = new MovingAverage(3);
7 | m.next(1) = 1
8 | m.next(10) = (1 + 10) / 2
9 | m.next(3) = (1 + 10 + 3) / 3
10 | m.next(5) = (10 + 3 + 5) / 3
11 |
12 | """
13 |
14 | class MovingAverage:
15 | """
16 | Design a circular queue with array,
17 | with minimal calculation and space consumption
18 | """
19 | def __init__(self, size: int):
20 | """
21 | Initialize your data structure here.
22 |
23 | """
24 | self.size = size
25 | self.queue = [0] * self.size
26 | self.curr = 0
27 | self.sum = 0
28 | self.count = 0
29 |
30 | def next(self, val: int) -> float:
31 | self.count += 1
32 | tail = (self.curr + self.size + 1) % self.size
33 | self.sum = self.sum - self.queue[tail] + val
34 | # move on to the next head
35 | self.curr = (self.curr + 1) % self.size
36 | self.queue[self.curr] = val
37 |
38 | return self.sum / (self.size if self.count > self.size else self.count)
39 |
40 |
41 | # Your MovingAverage object will be instantiated and called as such:
42 | # obj = MovingAverage(size)
43 | # param_1 = obj.next(val)
--------------------------------------------------------------------------------
/python/347_Top_K_Frequent_Elements.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a non-empty array of integers, return the k most frequent elements.
3 |
4 | Example 1:
5 |
6 | Input: nums = [1,1,1,2,2,3], k = 2
7 | Output: [1,2]
8 | """
9 |
10 | class Solution:
11 | def topKFrequent(self, nums: List[int], k: int) -> List[int]:
12 | """
13 | :type nums: List[int]
14 | :type k: int
15 | :rtype: List[int]
16 | """
17 | from collections import defaultdict
18 | numCount = defaultdict(int)
19 | for num in nums:
20 | numCount[num] += 1
21 |
22 | sorted_counts = sorted(numCount.items(), key=lambda kv: kv[1])
23 |
24 | return [sorted_counts[-i][0] for i in range(1, k+1)]
25 |
26 | class Solution2(object):
27 | def topKFrequent(self, nums, k):
28 | """
29 | :type nums: List[int]
30 | :type k: int
31 | :rtype: List[int]
32 | """
33 | #cnt = collections.Counter(nums)
34 | #return [kv[0] for kv in cnt.most_common(k)]
35 |
36 | cnt = collections.Counter(nums)
37 |
38 | import heapq
39 | return heapq.nlargest(k, cnt, key=cnt.get)
40 |
41 | class Solution3(object):
42 | def topKFrequent(self, nums, k):
43 | """
44 | :type nums: List[int]
45 | :type k: int
46 | :rtype: List[int]
47 | """
48 | cnt = collections.Counter(nums)
49 | return [kv[0] for kv in cnt.most_common(k)]
--------------------------------------------------------------------------------
/python/350_intersection_of_two_arrays_II.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
4 |
5 | nums1.sort()
6 | nums2.sort()
7 |
8 | p1, p2 = 0, 0
9 |
10 | nums1_len, nums2_len = len(nums1), len(nums2)
11 |
12 | result = []
13 | while p1 < nums1_len and p2 < nums2_len:
14 | if nums1[p1] == nums2[p2]:
15 | result.append(nums1[p1])
16 | elif nums1[p1] > nums2[p2]:
17 | p1 -= 1
18 | else:
19 | p2 -= 1
20 |
21 | p1 += 1
22 | p2 += 1
23 |
24 | return result
25 |
26 |
27 | class Solution:
28 | def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
29 |
30 | # https://www.geeksforgeeks.org/operations-on-python-counter/
31 | # Operations on Counter: +, -, &, |
32 | # addition, subtraction, intersection, union
33 | counter1 = Counter(nums1)
34 | counter2 = Counter(nums2)
35 |
36 | result = []
37 |
38 | # intersections between the frequency count
39 | intersections = counter1 & counter2
40 | for key, count in intersections.items():
41 | result.extend([key] * count)
42 |
43 | return result
44 |
--------------------------------------------------------------------------------
/python/361_bomb_enemy.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def maxKilledEnemies(self, grid: List[List[str]]) -> int:
3 | if len(grid) == 0:
4 | return 0
5 |
6 | rows, cols = len(grid), len(grid[0])
7 |
8 | max_count = 0
9 | row_hits = 0
10 | col_hits = [0] * cols
11 |
12 | for row in range(0, rows):
13 | for col in range(0, cols):
14 | # reset the hits on the row, if necessary
15 | if col == 0 or grid[row][col-1] == 'W':
16 | row_hits = 0
17 | for k in range(col, cols):
18 | if grid[row][k] == 'W':
19 | break
20 | elif grid[row][k] == 'E':
21 | row_hits += 1
22 |
23 | # reset the hits on the col, if necessary
24 | if row == 0 or grid[row-1][col] == 'W':
25 | col_hits[col] = 0
26 | for k in range(row, rows):
27 | if grid[k][col] == 'W':
28 | break
29 | elif grid[k][col] == 'E':
30 | col_hits[col] += 1
31 |
32 | if grid[row][col] == '0':
33 | total_hits = row_hits + col_hits[col]
34 | max_count = max(max_count, total_hits)
35 |
36 | return max_count
37 |
--------------------------------------------------------------------------------
/python/366_Find_Leaves_of_Binary_Tree.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, x):
4 | # self.val = x
5 | # self.left = None
6 | # self.right = None
7 |
8 | class Solution:
9 | def findLeaves(self, root):
10 | """
11 | :type root: TreeNode
12 | :rtype: List[List[int]]
13 | """
14 | results = []
15 |
16 | def distance_to_leave(node):
17 | nonlocal results
18 |
19 | if node is None:
20 | return 0
21 |
22 | distance = 1 + max(distance_to_leave(node.left),
23 | distance_to_leave(node.right))
24 |
25 | # update the resulting array
26 | if distance > len(results):
27 | results.append([node.val])
28 | else:
29 | results[distance-1].append(node.val)
30 |
31 | # return the maximum distance to any of the leaves
32 | return distance
33 |
34 | distance_to_leave(root)
35 |
36 | return results
37 |
--------------------------------------------------------------------------------
/python/367_valid_perfect_square.py:
--------------------------------------------------------------------------------
1 | '''
2 | Given a positive integer num, write a function which returns True if num is a perfect square else False.
3 |
4 | Note: Do not use any built-in library function such as sqrt.
5 |
6 | Example 1:
7 | Input: 16
8 | Output: true
9 |
10 | Example 2:
11 |
12 | Input: 14
13 | Output: false
14 | '''
15 |
16 | class Solution:
17 | def isPerfectSquare(self, num: int) -> bool:
18 | '''
19 | Binary search on the proper number
20 | '''
21 | low, high = 0, num
22 |
23 | # tricky to set the conditions:
24 | while low <= high: # condition 1). low <= high
25 | pivot = (low + high) // 2
26 | product = pivot * pivot
27 | if product == num:
28 | return True
29 | elif product < num:
30 | low = pivot + 1 # condition 2). move the pivot
31 | else:
32 | high = pivot - 1 # condition 3). move the pivot
33 |
34 | return False
35 |
--------------------------------------------------------------------------------
/python/370_range_addition.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def getModifiedArray(self, length: int, updates: List[List[int]]) -> List[int]:
4 |
5 | array = [0] * length
6 |
7 | # update the boundaries with delta values
8 | for start, end, delta in updates:
9 | array[start] += delta
10 | if end < length - 1:
11 | array[end + 1] -= delta
12 |
13 | # calculate the cumulative sum / prefix_sum
14 | prefix_sum = 0
15 | for index in range(length):
16 | array[index] += prefix_sum
17 | prefix_sum = array[index]
18 |
19 | return array
20 |
--------------------------------------------------------------------------------
/python/375_Guess_Higher_or_Lower_Number_II.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def getMoneyAmount(self, n: int) -> int:
3 |
4 | @lru_cache(maxsize=None)
5 | def cost(low, high):
6 | """ minmax algorithm:
7 | the minimal values among all possible (worst) scenarios
8 | """
9 | if low >= high:
10 | return 0
11 |
12 | min_cost = float('inf')
13 | for pivot in range(low, high):
14 | worst_scenario = pivot + max(cost(low, pivot-1), cost(pivot+1, high))
15 | min_cost = min(min_cost, worst_scenario)
16 |
17 | return min_cost
18 |
19 | return cost(0, n)
20 |
21 |
22 | class SolutionOptimized:
23 | def getMoneyAmount(self, n: int) -> int:
24 |
25 | @lru_cache(maxsize=None)
26 | def cost(low, high):
27 | if low >= high:
28 | return 0
29 |
30 | min_cost = float('inf')
31 | # only consider using the right half of the elments as pivots,
32 | # as they are the worst scenarios.
33 | for pivot in range((low+high)//2, high):
34 | worst_scenario = pivot + max(cost(low, pivot-1), cost(pivot+1, high))
35 | min_cost = min(min_cost, worst_scenario)
36 |
37 | return min_cost
38 |
39 | return cost(1, n)
--------------------------------------------------------------------------------
/python/377_combination_sum_IV.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def combinationSum4(self, nums: List[int], target: int) -> int:
3 |
4 | """
5 | dynamic programming:
6 | comb[target] = sum(comb[target-nums[i]])
7 |
8 | - treat each candidate number as the last number in the final combination.
9 | - append the candidate number to the combinations of (target - nums[i]), i.e. comb[target-nums[i]]
10 | """
11 |
12 | #import functools
13 | @functools.lru_cache(maxsize = None)
14 | def combinationSum4(remain):
15 | if remain == 0:
16 | return 1
17 |
18 | result = 0
19 | for num in nums:
20 | if remain - num >= 0:
21 | result += combinationSum4(remain - num)
22 | return result
23 |
24 | return combinationSum4(target)
25 |
--------------------------------------------------------------------------------
/python/383_ransom_note.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def canConstruct(self, ransomNote: str, magazine: str) -> bool:
4 |
5 | def count_letter(word):
6 | letter_cnt = defaultdict(int)
7 | for letter in word:
8 | letter_cnt[letter] += 1
9 | return letter_cnt
10 |
11 |
12 | ransom_dict = count_letter(ransomNote)
13 | magazine_dict = count_letter(magazine)
14 |
15 | for letter, cnt in ransom_dict.items():
16 | if letter not in magazine_dict:
17 | return False
18 | if cnt > magazine_dict[letter]:
19 | return False
20 |
21 | return True
22 |
23 |
24 | def canConstruct_OneHashmap(self, ransomNote: str, magazine: str) -> bool:
25 |
26 | def count_letter(word):
27 | letter_cnt = defaultdict(int)
28 | for letter in word:
29 | letter_cnt[letter] += 1
30 | return letter_cnt
31 |
32 | magazine_dict = count_letter(magazine)
33 |
34 | for letter in ransomNote:
35 | if letter not in magazine_dict:
36 | return False
37 | magazine_dict[letter] -= 1
38 | if magazine_dict[letter] == 0:
39 | del magazine_dict[letter]
40 |
41 | return True
42 |
--------------------------------------------------------------------------------
/python/384_Shuffle_Array.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 |
3 | def __init__(self, nums: List[int]):
4 | self.original = nums
5 | self.perm = list(self.original)
6 |
7 |
8 | def reset(self) -> List[int]:
9 | """
10 | Resets the array to its original configuration and return it.
11 | """
12 | # restore the current state of permutation to its original state
13 | self.perm = list(self.original)
14 | return self.perm
15 |
16 |
17 | def shuffle(self) -> List[int]:
18 | """
19 | Returns a random shuffling of the array.
20 | """
21 | # apparently this is so-call Fisher-Yates algorithm.
22 | for i in range(len(self.perm)):
23 | #randi = random.randrange(i, len(self.perm))
24 | randi = i + random.randint(0, len(self.perm)-i-1)
25 | self.perm[i], self.perm[randi] = self.perm[randi], self.perm[i]
26 |
27 | return self.perm
28 |
29 |
30 | # Your Solution object will be instantiated and called as such:
31 | # obj = Solution(nums)
32 | # param_1 = obj.reset()
33 | # param_2 = obj.shuffle()
--------------------------------------------------------------------------------
/python/392_Is_Subsequence.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def isSubsequence(self, s: str, t: str) -> bool:
3 |
4 | LEFT_BOUND = len(s)
5 | RIGHT_BOUND = len(t)
6 |
7 | @lru_cache(None)
8 | def rec_isSubsequence(left_index, right_index):
9 | if left_index == LEFT_BOUND:
10 | return True
11 | elif right_index == RIGHT_BOUND:
12 | return False
13 |
14 | if s[left_index] == t[right_index]:
15 | left_index += 1
16 | right_index += 1
17 | else:
18 | right_index += 1
19 |
20 | return rec_isSubsequence(left_index, right_index)
21 |
22 |
23 | return rec_isSubsequence(0, 0)
--------------------------------------------------------------------------------
/python/404_sum_of_left_leaves.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def sumOfLeftLeaves(self, root: TreeNode) -> int:
9 |
10 | leaf_sum = 0
11 | def dfs(node, is_left=None):
12 | nonlocal leaf_sum
13 | if node is None:
14 | return
15 |
16 | if node.left is None and node.right is None and is_left:
17 | leaf_sum += node.val
18 | else:
19 | dfs(node.left, True)
20 | dfs(node.right, False)
21 |
22 | dfs(root)
23 | return leaf_sum
24 |
--------------------------------------------------------------------------------
/python/415_add_strings.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def addStrings(self, num1: str, num2: str) -> str:
3 |
4 | p1, p2 = len(num1) - 1, len(num2) - 1
5 | output = []
6 | carry = 0
7 |
8 | while p1 >= 0 or p2 >= 0:
9 |
10 | bit_sum = 0
11 |
12 | if p1 >= 0:
13 | bit_sum += int(num1[p1])
14 | p1 -= 1
15 |
16 | if p2 >= 0:
17 | bit_sum += int(num2[p2])
18 | p2 -= 1
19 |
20 | bit_sum += carry
21 | carry = bit_sum // 10
22 | curr_bit = bit_sum % 10
23 |
24 | output.append(str(curr_bit))
25 |
26 | if carry > 0:
27 | output.append(str(carry))
28 |
29 | return "".join(reversed(output))
--------------------------------------------------------------------------------
/python/416_partition_equal_subset_sum.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def canPartition(self, nums: List[int]) -> bool:
3 |
4 | total_sum = sum(nums)
5 | if total_sum % 2 != 0:
6 | return False
7 |
8 | target = total_sum // 2
9 |
10 | @lru_cache(maxsize=None)
11 | def backtrack(curr, curr_sum):
12 |
13 | if curr_sum == target:
14 | return True
15 | elif curr_sum > target or curr == len(nums):
16 | return False
17 |
18 | if backtrack(curr+1, curr_sum + nums[curr]):
19 | return True
20 |
21 | if backtrack(curr+1, curr_sum):
22 | return True
23 |
24 | return backtrack(0, 0)
25 |
--------------------------------------------------------------------------------
/python/42_trapping_rain_water.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def trap(self, height: List[int]) -> int:
3 |
4 | left_max, right_max = 0, 0
5 | left, right = 0, len(height) - 1
6 |
7 | total_sum = 0
8 | while left < right:
9 | left_max = max(left_max, height[left])
10 | right_max = max(right_max, height[right])
11 |
12 | if left_max < right_max:
13 | total_sum += left_max - height[left]
14 | left += 1
15 | else:
16 | total_sum += right_max - height[right]
17 | right -= 1
18 |
19 | return total_sum
20 |
--------------------------------------------------------------------------------
/python/435_non_overlapping_intervals.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
4 |
5 | intervals.sort(key = lambda x: x[1])
6 |
7 | eliminate_count = 0
8 |
9 | curr_end = intervals[0][1]
10 |
11 | # Eliminate the intervals at early as possible greedily
12 | for (start, end) in intervals[1:]:
13 | if start < curr_end:
14 | # eliminate the current overlapped interval,
15 | # since if we keep it, it would have a greater chance to overlap with the following intervals
16 | eliminate_count += 1
17 | else:
18 | curr_end = end
19 |
20 | return eliminate_count
--------------------------------------------------------------------------------
/python/442_find_duplicates_in_an_array.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def findDuplicates(self, nums: List[int]) -> List[int]:
3 | ret = []
4 | for x in nums:
5 | if nums[abs(x) - 1] < 0:
6 | ret.append(abs(x))
7 | else:
8 | nums[abs(x) - 1] *= -1
9 |
10 | return ret
--------------------------------------------------------------------------------
/python/450_delete_node_in_BST.py:
--------------------------------------------------------------------------------
1 |
2 | # Definition for a binary tree node.
3 | # class TreeNode:
4 | # def __init__(self, val=0, left=None, right=None):
5 | # self.val = val
6 | # self.left = left
7 | # self.right = right
8 | class Solution:
9 | def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
10 |
11 | if not root:
12 | return root
13 |
14 | def find_least_node(node):
15 | while node.left:
16 | node = node.left
17 | return node
18 |
19 | if key < root.val:
20 | root.left = self.deleteNode(root.left, key)
21 | elif key > root.val:
22 | root.right = self.deleteNode(root.right, key)
23 | else: # key == root.val
24 | # replace it with either of non-empty child node
25 | if not root.left:
26 | return root.right
27 | elif not root.right:
28 | return root.left
29 | else:
30 | # delete the current node by replacing it with the left most value on its right child
31 | left_most_node = find_least_node(root.right)
32 | root.val = left_most_node.val
33 | root.right = self.deleteNode(root.right, root.val)
34 |
35 | return root
36 |
--------------------------------------------------------------------------------
/python/452_minimal_number_of_arrows_to_burst_ballons.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class Solution:
4 | def findMinArrowShots(self, points: List[List[int]]) -> int:
5 |
6 | points.sort(key = lambda x:x[1])
7 |
8 | # minimal arrows
9 | arrow_count = 1
10 |
11 | # starting from the first ballon
12 | curr_end = points[0][1]
13 |
14 | for (start, end) in points:
15 | # Use one arrow to burst all ballons in an overlapped interval
16 | if curr_end < start:
17 | arrow_count += 1
18 | curr_end = end
19 |
20 | return arrow_count
--------------------------------------------------------------------------------
/python/458_poor_pigs.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def poorPigs(self, buckets: int, minutesToDie: int, minutesToTest: int) -> int:
3 |
4 | bit_states = minutesToTest / minutesToDie + 1
5 |
6 | # a mathematical solution
7 | # information contained in buckets: log(buckets)
8 | # information contained for a single pig (possible states): log(states)
9 | #return math.ceil(math.log(buckets) / math.log(bit_states))
10 |
11 | num_bits = 0 # number of pigs as well
12 | while bit_states ** num_bits < buckets:
13 | num_bits += 1
14 |
15 | return num_bits
16 |
17 |
--------------------------------------------------------------------------------
/python/461_hamming_distance.py:
--------------------------------------------------------------------------------
1 | """
2 | The Hamming distance between two integers is the number of positions at which the corresponding bits are different.
3 |
4 | Given two integers x and y, calculate the Hamming distance.
5 |
6 | Note:
7 | 0 ≤ x, y < 231.
8 |
9 | Example:
10 | Input: x = 1, y = 4
11 |
12 | Output: 2
13 |
14 | Explanation:
15 | 1 (0 0 0 1)
16 | 4 (0 1 0 0)
17 | ↑ ↑
18 |
19 | The above arrows point to positions where the corresponding bits are different.
20 |
21 | """
22 | class BrianKernighanSolution:
23 | def hammingDistance(self, x: int, y: int) -> int:
24 | diff = x ^ y
25 | count = 0
26 | while diff:
27 | count += 1
28 | # turn off rightmost 1-bit
29 | diff = diff & (diff - 1)
30 | return count
31 |
32 | class Solution(object):
33 | def hammingDistance(self, x, y):
34 | """
35 | :type x: int
36 | :type y: int
37 | :rtype: int
38 | """
39 | distance = 0
40 |
41 | while x != 0 or y != 0:
42 | if (x % 2) != (y % 2):
43 | distance += 1
44 |
45 | x = x >> 1
46 | y = y >> 1
47 |
48 | return distance
--------------------------------------------------------------------------------
/python/463_Island_Perimeter.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def islandPerimeter(self, grid: List[List[int]]) -> int:
4 |
5 | ROWS, COLS = len(grid), len(grid[0])
6 |
7 | def shoreCount(row, col):
8 | count = 0
9 | directions = [(-1, 0), (0, 1), (1, 0), (0, -1)]
10 | for rowOffset, colOffset in directions:
11 | newRow, newCol = row+rowOffset, col+colOffset
12 | if newRow < 0 or newRow >= ROWS or newCol < 0 or newCol >= COLS:
13 | count += 1
14 | elif grid[newRow][newCol] == 0:
15 | count += 1
16 | return count
17 |
18 | perimeter = 0
19 | for row in range(ROWS):
20 | for col in range(COLS):
21 | if grid[row][col] == 1:
22 | perimeter += shoreCount(row, col)
23 |
24 | return perimeter
25 |
--------------------------------------------------------------------------------
/python/46_permutations.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def permute(self, nums: List[int]) -> List[List[int]]:
4 |
5 | output = []
6 |
7 | def swap(array, a, b):
8 | if a != b:
9 | array[a], array[b] = array[b], array[a]
10 |
11 | def backtrack(start, array):
12 | nonlocal output
13 | """
14 | Generate permutation for the subarray[start:]
15 |
16 | when we reach the last subarray, the permutation is formed inside the array.
17 | """
18 | if start == len(array):
19 | output.append(list(array))
20 | return
21 |
22 | for next_index in range(start, len(array)):
23 | swap(array, next_index, start)
24 |
25 | # move on the subarray, i.e. array[start+1:]
26 | backtrack(start + 1, array)
27 |
28 | swap(array, next_index, start)
29 |
30 | backtrack(0, nums)
31 | return output
32 |
33 |
34 |
--------------------------------------------------------------------------------
/python/470_implement_rand10_using_rand7.py:
--------------------------------------------------------------------------------
1 | # The rand7() API is already defined for you.
2 | # def rand7():
3 | # @return a random integer in the range 1 to 7
4 |
5 | class Solution:
6 | def rand10(self):
7 | """
8 | :rtype: int
9 |
10 | Two-phase generation, decision-tree alike approach
11 |
12 | [1, 2, 3] [5, 6, 7]
13 | | |
14 | | |
15 | [1, 2, 3, 4, 5] [6, 7, 8, 9, 10]
16 |
17 | """
18 | while True:
19 | first_round = rand7()
20 | if first_round != 4:
21 | while True:
22 | second_round = rand7()
23 | if second_round <= 5:
24 | return second_round + (first_round < 4) * 5
25 |
26 |
27 | def rand10_rejection_sampling(self):
28 | """
29 | :rtype: int
30 | """
31 | while True:
32 | row, col = rand7(), rand7()
33 | index = (row - 1) * 7 + col
34 | if index <= 40:
35 | return (index - 1) % 10 + 1
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/python/480_sliding_window_median.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]:
3 |
4 | window, medians = [], []
5 | for i, num in enumerate(nums):
6 |
7 | # insert an element into sorted list
8 | # the resulting list would be still in order
9 | bisect.insort(window, num)
10 |
11 | if i >= k:
12 | # remove the element that is just out of scope
13 | # window.remove(nums[i-k])
14 | # apply binary search to locate the element to remove
15 | # but it won't make much difference, since eventually
16 | # we need to shift the elements
17 | window.pop(bisect.bisect(window, nums[i-k]) - 1)
18 |
19 | if i >= k - 1:
20 | if k % 2 == 0:
21 | median = (window[k//2] + window[k//2 - 1]) / 2
22 | else:
23 | median = window[k//2]
24 |
25 | medians.append(median)
26 |
27 |
28 | return medians
--------------------------------------------------------------------------------
/python/497_random_point_in_non-overlapping_rectangles.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 | class Solution:
4 |
5 | def __init__(self, rects: List[List[int]]):
6 | self.prefix_sums = []
7 | self.total_area = 0
8 | for rect in rects:
9 | x1, y1, x2, y2 = rect
10 | # the area could be of lines
11 | area = (x2-x1 + 1) * (y2-y1 + 1)
12 | self.total_area += area
13 | self.prefix_sums.append(self.total_area)
14 | self.rects = rects
15 |
16 | def pick(self) -> List[int]:
17 |
18 | pick = int(random.random() * self.total_area)
19 |
20 | # binary search to locate the chosen rectangle
21 | low, high = 0, len(self.prefix_sums)
22 | while low < high:
23 | mid = int((high - low) / 2 + low)
24 | if pick >= self.prefix_sums[mid]:
25 | low = mid + 1
26 | else:
27 | high = mid
28 |
29 | picked_rect = self.rects[low]
30 | x1, y1, x2, y2 = picked_rect
31 |
32 | return [random.randrange(x1, x2+1), random.randrange(y1, y2+1)]
33 |
34 |
35 | # Your Solution object will be instantiated and called as such:
36 | # obj = Solution(rects)
37 | # param_1 = obj.pick()
--------------------------------------------------------------------------------
/python/513_find_bottom_left_tree_value.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def findBottomLeftValue(self, root: TreeNode) -> int:
9 | leaves_list = []
10 |
11 | def dfs(node, row, col):
12 | if node is None:
13 | return
14 |
15 | if node.left is None and node.right is None:
16 | leaves_list.append((-row, col, node.val))
17 | else:
18 | dfs(node.left, row+1, col-1)
19 | dfs(node.right, row+1, col+1)
20 |
21 | dfs(root, 0, 0)
22 |
23 | # order the leaves nodes by its (row, col) index
24 | leaves_list.sort()
25 |
26 | return leaves_list[0][2]
27 |
--------------------------------------------------------------------------------
/python/516_longest_palindromic_subsequence.py:
--------------------------------------------------------------------------------
1 | class SolutionTLE:
2 | def longestPalindromeSubseq(self, s: str) -> int:
3 |
4 | max_len = 0
5 | str_len = len(s)
6 |
7 | def dfs(index, subsequence):
8 | nonlocal max_len
9 |
10 | if subsequence == subsequence[::-1]:
11 | max_len = max(max_len, len(subsequence))
12 |
13 | if index == str_len:
14 | return
15 |
16 | dfs(index+1, subsequence)
17 | dfs(index+1, subsequence + s[index])
18 |
19 |
20 | dfs(0, "")
21 |
22 | return max_len
23 |
24 |
25 | class Solution:
26 | def longestPalindromeSubseq(self, s: str) -> int:
27 |
28 | """
29 | optimized break-down of the problem,
30 | with less memory consumption, as well as less computation.
31 | """
32 | @functools.lru_cache(maxsize=None)
33 | def dp(left, right):
34 |
35 | if left == right:
36 | return 1
37 | elif left > right:
38 | return 0
39 |
40 | if s[left] == s[right]:
41 | return 2 + dp(left+1, right-1)
42 | else:
43 | return max(dp(left+1, right), dp(left, right-1))
44 |
45 | return dp(0, len(s)-1)
--------------------------------------------------------------------------------
/python/523_Continuous_Subarray_Sum.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def checkSubarraySum(self, nums: List[int], k: int) -> bool:
3 |
4 | # the earliest index with the same module remaider of k
5 | prefix_sum_indices = {}
6 |
7 | # a virtual prefix sum index.
8 | # for the test case of [0, 0] k = 0
9 | prefix_sum = 0
10 | prefix_sum_indices[0] = -1
11 |
12 | for index, num in enumerate(nums):
13 |
14 | prefix_sum += num
15 |
16 | # group the prefix sums with modulo
17 | if k != 0:
18 | prefix_sum %= k # normalize the sum
19 |
20 | if prefix_sum in prefix_sum_indices:
21 | if index - prefix_sum_indices[prefix_sum] > 1:
22 | return True
23 | else:
24 | prefix_sum_indices[prefix_sum] = index
25 |
26 | return False
27 |
--------------------------------------------------------------------------------
/python/526_beautiful_arrangement.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def countArrangement(self, N: int) -> int:
3 |
4 | nums = [i+1 for i in range(N)]
5 | comb_count = 0
6 | def backtrack(start, comb):
7 | nonlocal comb_count
8 |
9 | if start == N:
10 | comb_count += 1
11 | return
12 |
13 | for index in range(start, N):
14 |
15 | if (start + 1) % nums[index] == 0 \
16 | or nums[index] % (start + 1) == 0:
17 | # mark the choice
18 | comb[start], comb[index] = comb[index], comb[start]
19 | backtrack(start+1, comb)
20 | # revert the choice
21 | comb[start], comb[index] = comb[index], comb[start]
22 |
23 | backtrack(0, nums)
24 |
25 | return comb_count
26 |
--------------------------------------------------------------------------------
/python/528_random_pick_with_weight.py:
--------------------------------------------------------------------------------
1 | class Solution(object):
2 |
3 | def __init__(self, w):
4 | """
5 | :type w: List[int]
6 | """
7 | self.prefix_sum_array = []
8 |
9 | prefix_sum = 0
10 | for weight in w:
11 | prefix_sum += weight
12 | self.prefix_sum_array.append(prefix_sum)
13 | self.total_sum = prefix_sum
14 |
15 | def pickIndex(self):
16 | """
17 | :rtype: int
18 | """
19 | from bisect import bisect_left
20 |
21 | prefix_sum = self.total_sum * random.random()
22 | return bisect_left(self.prefix_sum_array, prefix_sum)
23 |
24 |
25 | # Your Solution object will be instantiated and called as such:
26 | # obj = Solution(w)
27 | # param_1 = obj.pickIndex()
--------------------------------------------------------------------------------
/python/530_min_absolute_difference_in_BST.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def getMinimumDifference(self, root: TreeNode) -> int:
9 |
10 | min_diff = float('inf')
11 |
12 | def dfs(node):
13 | nonlocal min_diff
14 | if not node:
15 | return (-1, -1)
16 |
17 | l_min_val, l_max_val = dfs(node.left)
18 | r_min_val, r_max_val = dfs(node.right)
19 |
20 | if l_max_val != -1:
21 | min_diff = min(min_diff, abs(l_max_val - node.val))
22 | else:
23 | l_min_val = node.val
24 |
25 | if r_min_val != -1:
26 | min_diff = min(min_diff, abs(r_min_val - node.val))
27 | else:
28 | r_max_val = node.val
29 |
30 | return min(l_min_val, node.val), max(node.val, r_max_val)
31 |
32 | dfs(root)
33 |
34 | return min_diff
35 |
--------------------------------------------------------------------------------
/python/539_minimum_time_difference.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def findMinDifference(self, timePoints: List[str]) -> int:
3 |
4 | def to_minutes(time_str):
5 | return int(time_str[0:2]) * 60 + int(time_str[3:])
6 |
7 | timestamps = [to_minutes(time_str) for time_str in timePoints]
8 |
9 | timestamps.sort()
10 |
11 | min_gap = float('inf')
12 | for index in range(1, len(timestamps)):
13 | min_gap = min(min_gap, timestamps[index] - timestamps[index-1])
14 |
15 | tail_to_head = 24 * 60 - timestamps[-1] + timestamps[0]
16 | min_gap = min(min_gap, tail_to_head)
17 |
18 | return min_gap
--------------------------------------------------------------------------------
/python/542_01_matrix.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def updateMatrix(self, mat: List[List[int]]) -> List[List[int]]:
4 |
5 | ROWS = len(mat)
6 | COLS = len(mat[0])
7 |
8 | def bfs(pos):
9 | visited = set([pos])
10 | queue = deque([(pos, 0)])
11 |
12 | while queue:
13 | (row, col), distance = queue.popleft()
14 |
15 | for ro, co in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
16 | new_row, new_col = row + ro, col + co
17 | if 0 > new_row or new_row == ROWS or 0 > new_col or new_col == COLS:
18 | continue
19 |
20 | if (new_row, new_col) in visited:
21 | continue
22 |
23 | if mat[new_row][new_col] == 0:
24 | return distance + 1
25 | else: # == 1
26 | visited.add((new_row, new_col))
27 | queue.append(((new_row, new_col), distance+1))
28 |
29 | # should never have arrived here.
30 | return distance
31 |
32 | res = [[0]*COLS for _ in range(ROWS)]
33 |
34 | for row in range(ROWS):
35 | for col in range(COLS):
36 | if mat[row][col] == 1:
37 | res[row][col] = bfs((row, col))
38 |
39 | return res
40 |
41 |
42 |
--------------------------------------------------------------------------------
/python/547_number_of_provinces.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def findCircleNum(self, isConnected: List[List[int]]) -> int:
3 |
4 | def isExplored(node, visited):
5 | """
6 | To explore the province starting from the current node.
7 | Mark all connected cities as visited.
8 |
9 | return: True if the current city is visited already.
10 | otherwise false.
11 | """
12 | if visited[node]:
13 | return True
14 |
15 | visited[node] = True
16 | is_connected = isConnected[node]
17 | for neighbor in range(0, city_num):
18 | if is_connected[neighbor] == 1 and not visited[neighbor]:
19 | isExplored(neighbor, visited)
20 |
21 | return False
22 |
23 | city_num = len(isConnected)
24 | visited = [False for _ in range(city_num)]
25 |
26 | province_cnt = 0
27 | for city in range(city_num):
28 | if not isExplored(city, visited):
29 | province_cnt += 1
30 |
31 | return province_cnt
32 |
--------------------------------------------------------------------------------
/python/559_maximum_depth_N-ary_tree.py:
--------------------------------------------------------------------------------
1 | """
2 | # Definition for a Node.
3 | class Node:
4 | def __init__(self, val=None, children=None):
5 | self.val = val
6 | self.children = children if children else []
7 | """
8 |
9 | class Solution:
10 | def maxDepth(self, root: 'Node') -> int:
11 |
12 | max_depth = 0
13 |
14 | def dfs(node, curr_depth):
15 | nonlocal max_depth
16 |
17 | if node is None:
18 | return
19 |
20 | if len(node.children) == 0:
21 | max_depth = max(max_depth, curr_depth)
22 | else:
23 | for child in node.children:
24 | dfs(child, curr_depth+1)
25 |
26 | dfs(root, 1)
27 |
28 | return max_depth
29 |
--------------------------------------------------------------------------------
/python/565_Nesting_Array.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def arrayNesting(self, nums: List[int]) -> int:
3 |
4 | max_length = -1
5 | visited = [False] * len(nums)
6 |
7 | for i in range(0, len(nums)):
8 | if visited[i]:
9 | continue
10 | start, count = nums[i], 0
11 | visited[i] = True
12 | # form the cycle
13 | while True:
14 | start = nums[start]
15 | visited[start] = True
16 | count += 1
17 | if start == nums[i]:
18 | break
19 |
20 | max_length = max(max_length, count)
21 |
22 | return max_length
--------------------------------------------------------------------------------
/python/56_merge_intervals.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def merge(self, intervals: List[List[int]]) -> List[List[int]]:
4 |
5 | intervals.sort(key = lambda x: x[0])
6 |
7 | merged = []
8 | for interval in intervals:
9 | if len(merged) == 0 or merged[-1][1] < interval[0]:
10 | # add a new interval
11 | merged.append(interval)
12 | else:
13 | # update the previous interval
14 | merged[-1][1] = max(merged[-1][1], interval[1])
15 |
16 | return merged
17 |
18 |
--------------------------------------------------------------------------------
/python/572_subtree_of_another_tree.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def isSubtree(self, s: TreeNode, t: TreeNode) -> bool:
9 |
10 | def isIdentical(a, b):
11 | if a is None or b is None:
12 | return (a is None) and (b is None)
13 | if a.val != b.val:
14 | return False
15 | if not isIdentical(a.left, b.left):
16 | return False
17 | return isIdentical(a.right, b.right)
18 |
19 | if s is None:
20 | return False
21 |
22 | if s.val == t.val:
23 | if isIdentical(s, t):
24 | return True
25 |
26 | if self.isSubtree(s.left, t):
27 | return True
28 | else:
29 | return self.isSubtree(s.right, t)
30 |
--------------------------------------------------------------------------------
/python/593_valid_square.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def validSquare(self, p1: List[int], p2: List[int], p3: List[int], p4: List[int]) -> bool:
3 |
4 | points = sorted([tuple(p1), tuple(p2), tuple(p3), tuple(p4)])
5 |
6 | diag1 = (points[3][0] - points[0][0],
7 | points[3][1] - points[0][1])
8 |
9 | diag2 = (points[2][0] - points[1][0],
10 | points[2][1] - points[1][1])
11 |
12 | mid1 = ((points[3][0] + points[0][0]) / 2,
13 | (points[3][1] + points[0][1]) / 2)
14 | mid2 = ((points[2][0] + points[1][0]) / 2,
15 | (points[2][1] + points[1][1]) / 2)
16 |
17 | # vectors of the same length
18 | # orthogonal vectors
19 | if mid1 != mid2 or \
20 | (diag1[0] ** 2 + diag1[1] ** 2) == 0 or \
21 | (diag1[0] * diag2[0] + diag1[1] * diag2[1]) != 0.0 or \
22 | (diag1[0] ** 2 + diag1[1] ** 2) != (diag2[0] ** 2 + diag2[1] ** 2):
23 | return False
24 |
25 | return True
--------------------------------------------------------------------------------
/python/611_valid_triangle_number.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | """
3 | Time limit exceeded
4 | """
5 | def triangleNumber(self, nums: List[int]) -> int:
6 |
7 | triangle_cnt = 0
8 | nums.sort()
9 |
10 | def backtrack(start, comb):
11 | nonlocal triangle_cnt
12 | if len(comb) == 3:
13 | if comb[0] + comb[1] > comb[2] and comb[2] - comb[1] < comb[0]:
14 | triangle_cnt += 1
15 | return
16 |
17 | for i in range(start, len(nums)):
18 | comb.append(nums[i])
19 | backtrack(i + 1, comb)
20 | comb.pop()
21 |
22 | backtrack(0, [])
23 |
24 | return triangle_cnt
25 |
26 |
27 | class SolutionThreePointers:
28 | def triangleNumber(self, nums: List[int]) -> int:
29 | n = len(nums)
30 |
31 | triangle_cnt = 0
32 | nums.sort()
33 |
34 | for third in range(n-1, 1, -1):
35 | # fixing on the third side
36 | first = 0
37 | second = third - 1
38 | while first < second:
39 | if nums[first] + nums[second] > nums[third]:
40 | triangle_cnt += second - first
41 | # try another candidate for the second side
42 | second -= 1
43 | else:
44 | # the first side is too small
45 | first += 1
46 |
47 | return triangle_cnt
--------------------------------------------------------------------------------
/python/621_task_scheduler.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def leastInterval(self, tasks: List[str], n: int) -> int:
3 |
4 | task_queue = []
5 |
6 | task_count = defaultdict(int)
7 | for task in tasks:
8 | task_count[task] += 1
9 |
10 | for task, count in task_count.items():
11 | task_queue.append((-count, task))
12 |
13 | heapq.heapify(task_queue)
14 |
15 | total_slots = 0
16 |
17 | while task_queue:
18 | slots_window = n + 1
19 |
20 | # populate one interval of slots
21 | slot_arrange = []
22 | while task_queue and slots_window > 0:
23 | count, task = heapq.heappop(task_queue)
24 | slot_arrange.append((task, count+1))
25 | slots_window -= 1
26 | total_slots += 1
27 |
28 | # need to re-insert the remain tasks
29 | for task, count in slot_arrange:
30 | if count != 0:
31 | heapq.heappush(task_queue, (count, task))
32 |
33 | if len(task_queue) == 0:
34 | break
35 |
36 | # padding with idle slots
37 | total_slots += slots_window
38 |
39 | return total_slots
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/python/628_maximum_product_of_three_numbers.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def maximumProduct(self, nums: List[int]) -> int:
4 |
5 | nums.sort()
6 |
7 | # the maximum value for the product of three numbers can only be the following two cases:
8 | # - top 3 numbers
9 | # - top 1 number * bottom 2 numbers
10 | return max(nums[-1] * nums[-2] * nums[-3],
11 | nums[0] * nums[1] * nums[-1])
12 |
--------------------------------------------------------------------------------
/python/637_average_of_levels_in_binary_tree.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def averageOfLevels(self, root: TreeNode) -> List[float]:
9 | if root is None:
10 | return []
11 |
12 | queue = deque([root])
13 | avg_list = []
14 | while queue:
15 | level_size = len(queue)
16 |
17 | level_sum = 0
18 | for i in range(level_size):
19 | node = queue.popleft()
20 | level_sum += node.val
21 |
22 | for next_node in [node.left, node.right]:
23 | if next_node is not None:
24 | queue.append(next_node)
25 |
26 | avg_list.append(level_sum / level_size)
27 |
28 | return avg_list
29 |
--------------------------------------------------------------------------------
/python/647_palindromic_substrings.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def countSubstrings(self, s: str) -> int:
4 |
5 | @functools.lru_cache(maxsize=None)
6 | def isPalindrome(start, end):
7 | if start >= end:
8 | return True
9 |
10 | if s[start] != s[end]:
11 | return False
12 | else:
13 | return isPalindrome(start+1, end-1)
14 |
15 | substr_cnt = 0
16 |
17 | for end in range(0, len(s)):
18 | for start in range(0, end+1):
19 | if isPalindrome(start, end):
20 | substr_cnt += 1
21 |
22 | return substr_cnt
23 |
24 |
25 | class Solution:
26 | def countSubstrings(self, s: str) -> int:
27 |
28 | str_len = len(s)
29 |
30 | def countPalindromicSubstr(start, end):
31 | cnt = 0
32 | # expand towards two ends
33 | while start >= 0 and end < str_len:
34 | if s[start] != s[end]:
35 | break
36 | start -= 1
37 | end += 1
38 | cnt += 1
39 |
40 | return cnt
41 |
42 | total_cnt = 0
43 | for center in range(0, str_len):
44 | total_cnt += countPalindromicSubstr(center, center)
45 | total_cnt += countPalindromicSubstr(center, center+1)
46 |
47 | return total_cnt
48 |
--------------------------------------------------------------------------------
/python/648_replace_words.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def replaceWords(self, dictionary: List[str], sentence: str) -> str:
3 |
4 | trie = {}
5 |
6 | def update_trie(word, trie):
7 | for letter in word:
8 | if letter not in trie:
9 | trie[letter] = {}
10 | trie = trie[letter]
11 | trie["$"] = word
12 |
13 | # building a Trie data structure for all words
14 | for word in dictionary:
15 | update_trie(word, trie)
16 |
17 | def find_min_prefix(word, trie):
18 | """
19 | Find the shortest common prefix
20 | """
21 | for letter in word:
22 | if letter not in trie:
23 | return ""
24 | trie = trie[letter]
25 | if "$" in trie:
26 | return trie["$"]
27 | return ""
28 |
29 |
30 | output = []
31 | words = sentence.split()
32 | for word in words:
33 | prefix = find_min_prefix(word, trie)
34 | if prefix == "":
35 | output.append(word)
36 | else:
37 | output.append(prefix)
38 |
39 | return " ".join(output)
--------------------------------------------------------------------------------
/python/664_Strange_Printer.py:
--------------------------------------------------------------------------------
1 | """
2 | Reference: https://leetcode.com/problems/strange-printer/discuss/106810/Java-O(n3)-DP-Solution-with-Explanation-and-Simple-Optimization
3 | """
4 | class Solution:
5 | def strangePrinter(self, s: str) -> int:
6 | str_size = len(s)
7 | if str_size == 0:
8 | return 0
9 |
10 | # init with the value 'n', size of the square
11 | dp = [[str_size]*str_size for i in range(str_size)]
12 | for i in range(str_size):
13 | # reset the diagnoal values
14 | dp[i][i] = 1
15 |
16 | # complexity O(N^3)
17 | for end in range(0, str_size):
18 | for start in range(end, -1, -1):
19 | for mid in range(start, end):
20 | default_print_num = dp[start][mid] + dp[mid+1][end]
21 | if s[mid] == s[end]:
22 | default_print_num -= 1
23 | dp[start][end] = min(dp[start][end], default_print_num)
24 |
25 |
26 | return dp[0][str_size-1]
--------------------------------------------------------------------------------
/python/667_Beautiful_Arrangements_II.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def constructArray(self, n: int, k: int) -> List[int]:
3 |
4 | # prefix
5 | nums = [i for i in range(1, n-k)]
6 |
7 | # postfix pattern:
8 | # 1, n, 2, n-1, 3, n-2, ....
9 | for i in range(k+1):
10 | if i % 2 == 0:
11 | nums.append(n-k + i // 2)
12 | else:
13 | nums.append(n - i // 2)
14 |
15 | return nums
16 |
--------------------------------------------------------------------------------
/python/669_Trim_Binary_Search_Tree.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def trimBST(self, root: TreeNode, low: int, high: int) -> TreeNode:
9 |
10 | if root is None:
11 | return root
12 |
13 | left_child = self.trimBST(root.left, low, high)
14 | right_child = self.trimBST(root.right, low, high)
15 |
16 | if root.val < low or root.val > high:
17 | # trim the current node
18 | root = left_child or right_child
19 | else:
20 | root.left = left_child
21 | root.right = right_child
22 |
23 | return root
--------------------------------------------------------------------------------
/python/696_count_binary_substrings.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def countBinarySubstrings(self, s: str) -> int:
3 |
4 | # count the groups of identical bits
5 | # e.g. [1110011] -> [3, 2, 2]
6 | groups = [1]
7 | for i in range(1, len(s)):
8 | if s[i] != s[i-1]:
9 | groups.append(1)
10 | else:
11 | groups[-1] += 1
12 |
13 | ans = 0
14 | for gi in range(1, len(groups)):
15 | ans += min(groups[gi], groups[gi-1])
16 |
17 | return ans
18 |
--------------------------------------------------------------------------------
/python/697_degree_of_array.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def findShortestSubArray(self, nums: List[int]) -> int:
3 |
4 | num_range_dict = {}
5 | max_count = 0
6 |
7 | for index, num in enumerate(nums):
8 | if num in num_range_dict:
9 | start, end, count = num_range_dict[num]
10 | new_count = count + 1
11 | num_range_dict[num] = (start, index, new_count)
12 | else:
13 | new_count = 1
14 | num_range_dict[num] = (index, index, new_count)
15 |
16 | if new_count > max_count:
17 | max_count = new_count
18 |
19 | min_range = float("inf")
20 | for _, value in num_range_dict.items():
21 | start, end, count = value
22 | if count == max_count:
23 | min_range = min(min_range, end-start+1)
24 |
25 | return min_range
26 |
27 |
28 |
--------------------------------------------------------------------------------
/python/698_Partition_To_K_Equal_Sum_Subsets.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def canPartitionKSubsets(self, nums: List[int], k: int) -> bool:
3 | """ Time Limit Exceed solution """
4 |
5 | total_sum = sum(nums)
6 | if total_sum % k != 0:
7 | return False
8 | target = total_sum // k
9 |
10 | @lru_cache(maxsize=None)
11 | def backtrack(curr, comb):
12 | if curr == len(nums):
13 | return all([s == target for s in comb])
14 |
15 | comb_list = list(comb)
16 | for index, subset_sum in enumerate(comb_list):
17 | if subset_sum + nums[curr] > target:
18 | continue
19 |
20 | comb_list[index] += nums[curr]
21 | if backtrack(curr+1, tuple(sorted(comb_list, reverse=True))):
22 | return True
23 | comb_list[index] -= nums[curr]
24 |
25 | return False
26 |
27 | nums.sort()
28 | if nums[-1] > target: return False
29 |
30 | comb = [0] * k
31 | return backtrack(0, tuple(comb))
32 |
--------------------------------------------------------------------------------
/python/701_Insert_into_a_Binary_Search_Tree.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
9 |
10 | def dfs(node, value):
11 | next_node = None
12 | if value < node.val:
13 | if node.left is None:
14 | # insert as the new left child
15 | node.left = TreeNode(value)
16 | return
17 | else:
18 | next_node = node.left
19 | else: # value > node.val
20 | if node.right is None:
21 | node.right = TreeNode(value)
22 | return
23 | else:
24 | next_node = node.right
25 | # continue the search
26 | dfs(next_node, value)
27 |
28 | if root is None:
29 | return TreeNode(val)
30 | else:
31 | dfs(root, val)
32 | return root
33 |
--------------------------------------------------------------------------------
/python/713_Subarray_Product_Less_Than_K.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int:
3 |
4 | if k <= 1: return 0
5 |
6 | window_product = 1
7 | left, count = 0, 0
8 |
9 | for right, val in enumerate(nums):
10 |
11 | window_product *= val
12 |
13 | while window_product >= k:
14 | window_product //= nums[left]
15 | left += 1
16 |
17 | count += right - left + 1
18 |
19 | return count
20 |
--------------------------------------------------------------------------------
/python/71_simplify_path.py:
--------------------------------------------------------------------------------
1 | class SolutionRefined:
2 | def simplifyPath(self, path: str) -> str:
3 |
4 | folders = path.split('/')
5 |
6 | canonical = deque([])
7 | for i, folder in enumerate(folders):
8 | if folder == "" or folder == ".":
9 | # skip
10 | continue
11 | elif folder == "..":
12 | # we might go beyond the root folder
13 | if canonical:
14 | canonical.pop()
15 | else:
16 | canonical.append(folder)
17 |
18 | return "/" + "/".join(canonical)
19 |
20 |
21 |
22 | class Solution:
23 | def simplifyPath(self, path: str) -> str:
24 |
25 | folders = path.split('/')
26 |
27 | canonical = deque([])
28 | for i, folder in enumerate(folders):
29 | if folder == "" and i > 0:
30 | # skip
31 | continue
32 | elif folder == "..":
33 | # we might go beyond the root folder
34 | if canonical:
35 | canonical.pop()
36 | elif folder == ".":
37 | continue
38 | else:
39 | canonical.append(folder)
40 |
41 | if len(canonical) == 0 or canonical[0] != "":
42 | canonical.appendleft("")
43 |
44 | if len(canonical) == 1:
45 | return "/"
46 | else:
47 | return "/".join(canonical)
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/python/735_asteroids_collision.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def asteroidCollision(self, asteroids: List[int]) -> List[int]:
3 |
4 | stack = []
5 |
6 | for asteroid in asteroids:
7 | if len(stack) == 0:
8 | stack.append(asteroid)
9 | continue
10 |
11 | to_add = True
12 |
13 | while stack:
14 | tail = stack[-1]
15 | if (tail * asteroid > 0) or (tail < 0 and asteroid > 0):
16 | stack.append(asteroid)
17 | to_add = False
18 | break
19 | else:
20 | # collision
21 | if abs(tail) > abs(asteroid):
22 | # current asteroid is destroyed
23 | to_add = False
24 | break
25 | elif abs(tail) == abs(asteroid):
26 | # both asteroid is destroyed
27 | stack.pop()
28 | to_add = False
29 | break
30 | else:
31 | # previous asteroid is destroyed
32 | stack.pop()
33 | if to_add:
34 | # we still need to add the current asteroid into the stack
35 | stack.append(asteroid)
36 |
37 | return stack
--------------------------------------------------------------------------------
/python/739_daily_temperatures.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def dailyTemperatures(self, T: List[int]) -> List[int]:
4 |
5 | mono_stack = []
6 | answer = [0] * len(T)
7 |
8 | for index, number in enumerate(T):
9 |
10 | while mono_stack:
11 | top_index, top_number = mono_stack[-1]
12 | if top_number < number:
13 | mono_stack.pop()
14 | answer[top_index] = index - top_index
15 | else:
16 | break
17 |
18 | mono_stack.append((index, number))
19 |
20 | return answer
--------------------------------------------------------------------------------
/python/73_set_matrix_zeroes.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def setZeroes(self, matrix: List[List[int]]) -> None:
3 | """
4 | Do not return anything, modify matrix in-place instead.
5 | """
6 |
7 | column_header = matrix[0]
8 | col_size = len(column_header)
9 |
10 | # whether to reset the header later
11 | reset_header = False
12 | for header in column_header:
13 | if header == 0:
14 | reset_header = True
15 |
16 | # use the first row as the indicator to reset columns
17 | for row in range(1, len(matrix)):
18 | reset_row = False
19 | for col in range(col_size):
20 | if matrix[row][col] == 0:
21 | column_header[col] = 0
22 | reset_row = True
23 |
24 | if reset_row:
25 | matrix[row] = [0] * col_size
26 |
27 | # reset columns
28 | for col in range(col_size):
29 | if column_header[col] == 0:
30 | for row in range(len(matrix)):
31 | matrix[row][col] = 0
32 |
33 | # reset the column indicator if necessary
34 | if reset_header:
35 | matrix[0] = [0] * col_size
36 |
37 |
--------------------------------------------------------------------------------
/python/783_min_difference_between_BST_nodes.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def minDiffInBST(self, root: TreeNode) -> int:
9 |
10 | min_diff = float('inf')
11 |
12 | def dfs(node):
13 | nonlocal min_diff
14 |
15 | if not node:
16 | return (None, None)
17 |
18 | l_min_val, l_max_val = dfs(node.left)
19 | r_min_val, r_max_val = dfs(node.right)
20 |
21 | if l_max_val:
22 | min_diff = min(min_diff, abs(node.val - l_max_val))
23 | else:
24 | l_min_val = node.val
25 |
26 | if r_min_val:
27 | min_diff = min(min_diff, abs(node.val - r_min_val))
28 | else:
29 | r_max_val = node.val
30 |
31 | return min(l_min_val, node.val), max(r_max_val, node.val)
32 |
33 | dfs(root)
34 |
35 | return min_diff
36 |
--------------------------------------------------------------------------------
/python/785_is_graph_bipartite.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def isBipartite(self, graph: List[List[int]]) -> bool:
4 | """
5 | Run a BFS to see if the graph can be colored with two different codes,
6 | i.e. parent and child nodes should have different colors.
7 | """
8 | colors = {}
9 | nodes_num = len(graph)
10 |
11 | for node in range(nodes_num):
12 | if node in colors:
13 | continue
14 |
15 | colors[node] = 1
16 | queue = deque([node])
17 | while queue:
18 | curr = queue.popleft()
19 | for child in graph[curr]:
20 | if child not in colors:
21 | colors[child] = - colors[curr]
22 | queue.append(child)
23 | elif colors[child] == colors[curr]:
24 | return False
25 |
26 | return True
27 |
--------------------------------------------------------------------------------
/python/791_custom_sort_string.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def customSortString(self, order: str, s: str) -> str:
3 |
4 | # using order to define the priority/order of each letter
5 | letter_priority = {}
6 | for index, letter in enumerate(order):
7 | letter_priority[letter] = index
8 |
9 | # apply the priority for each letter
10 | # Note: by default, for letter with unknown priority, we put them in the front
11 | heap = []
12 | heapq.heapify(heap)
13 | for letter in s:
14 | priority = -1
15 | if letter in letter_priority:
16 | priority = letter_priority[letter]
17 | heapq.heappush(heap, (priority, letter))
18 |
19 | output = []
20 | while heap:
21 | priority, letter = heapq.heappop(heap)
22 | output.append(letter)
23 |
24 | return "".join(output)
--------------------------------------------------------------------------------
/python/792_number_of_matching_subsequence.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class Solution:
4 | def numMatchingSubseq(self, s: str, words: List[str]) -> int:
5 |
6 | letter_indices = defaultdict(list)
7 | for index, letter in enumerate(s):
8 | letter_indices[letter].append(index)
9 |
10 | def isSubsequence(word):
11 | """
12 | Greedy matching which ensures to find a solution if there exists one.
13 |
14 | XYZ --> ****X****Y*****Z***
15 | """
16 | cursor = -1
17 | for letter in word:
18 | if letter not in letter_indices:
19 | return False
20 |
21 | indices = letter_indices[letter]
22 | first_match = bisect.bisect_right(indices, cursor)
23 |
24 | if first_match == len(indices):
25 | # no match
26 | return False
27 | else:
28 | return True
29 |
30 | count = 0
31 | for word in words:
32 | if isSubsequence(word):
33 | count += 1
34 | return count
35 |
36 |
--------------------------------------------------------------------------------
/python/796_ratate_string.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def rotateString(self, s: str, goal: str) -> bool:
3 | if len(s) == 0 and len(goal) == 0:
4 | return True
5 | elif len(s) != len(goal):
6 | return False
7 |
8 | for split_index in range(len(s)):
9 | shift_str = s[split_index:] + s[0:split_index]
10 | if shift_str == goal:
11 | return True
12 |
13 | return False
14 |
15 |
16 | def rotateString_ABAB_BA(self, s: str, goal: str) -> bool:
17 | if len(s) == 0 and len(goal) == 0:
18 | return True
19 | elif len(s) != len(goal):
20 | return False
21 |
22 | return goal in (s+s)
23 |
24 |
--------------------------------------------------------------------------------
/python/826_most_profit_assign_work.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def maxProfitAssignment(self, difficulty: List[int], profit: List[int], worker: List[int]) -> int:
4 | """
5 | Similar problem as finding the intersection between two sorted list
6 | """
7 | jobs = [(d, p) for (d, p) in zip(difficulty, profit)]
8 | jobs.sort(key = lambda x: x[0])
9 |
10 | worker.sort()
11 | job_p, worker_p = 0, 0
12 |
13 | max_profit = 0
14 | total_profit = 0
15 |
16 | while worker_p < len(worker):
17 |
18 | # move the job pointer to find the most profitable job based on the current difficulty
19 | while job_p < len(jobs) and jobs[job_p][0] <= worker[worker_p]:
20 | max_profit = max(max_profit, jobs[job_p][1])
21 | job_p += 1
22 |
23 | # either we take a new job, or the previously most profitable job
24 | total_profit += max_profit
25 | worker_p += 1
26 |
27 | return total_profit
--------------------------------------------------------------------------------
/python/835_Image_Overlap.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def largestOverlap(self, A: List[List[int]], B: List[List[int]]) -> int:
3 |
4 | dim = len(A)
5 |
6 | def shift_and_count(x_shift, y_shift, M, R):
7 | """ M: matrix to be moved
8 | R: matrix for reference
9 | moving one matrix up and left is equivalent to
10 | moving the other matrix down and right
11 | """
12 | count = 0
13 | for r_row, m_row in enumerate(range(y_shift, dim)):
14 | for r_col, m_col in enumerate(range(x_shift, dim)):
15 | if M[m_row][m_col] == 1 and M[m_row][m_col] == R[r_row][r_col]:
16 | count += 1
17 | return count
18 |
19 | max_overlaps = 0
20 | # move one of the matrice up and left and vice versa.
21 | # (equivalent to move the other matrix down and right)
22 | for y_shift in range(0, dim):
23 | for x_shift in range(0, dim):
24 | max_overlaps = max(max_overlaps, shift_and_count(x_shift, y_shift, A, B))
25 | max_overlaps = max(max_overlaps, shift_and_count(x_shift, y_shift, B, A))
26 |
27 | return max_overlaps
--------------------------------------------------------------------------------
/python/841_rooms_and_keys.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def canVisitAllRooms(self, rooms: List[List[int]]) -> bool:
3 |
4 | visited = set()
5 |
6 | def dfs(curr):
7 | nonlocal visited
8 |
9 | visited.add(curr)
10 | for next_room in rooms[curr]:
11 | if next_room not in visited:
12 | dfs(next_room)
13 |
14 | # kick off the traversal
15 | dfs(0)
16 |
17 | return len(visited) == len(rooms)
18 |
--------------------------------------------------------------------------------
/python/844_backspace_string_compare.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def backspaceCompare(self, s: str, t: str) -> bool:
3 |
4 | def simulate(string):
5 | """
6 | Simulate the input with backspace key (i.e. "#")
7 | return the remaining string
8 | """
9 | str_stack = []
10 | for letter in string:
11 | if letter == "#":
12 | if str_stack:
13 | str_stack.pop()
14 | else:
15 | str_stack.append(letter)
16 |
17 | return "".join(str_stack)
18 |
19 |
20 | return simulate(s) == simulate(t)
--------------------------------------------------------------------------------
/python/867_transpose_matrix.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def transpose(self, A: List[List[int]]) -> List[List[int]]:
3 | TA = [[None] * len(A) for _ in range(len(A[0]))]
4 |
5 | # This initializaiton wont work!!! The elements are essentially references.
6 | # TA = [[0] * len(A)] * len(A[0])
7 |
8 | for row in range(len(A)):
9 | for col, num in enumerate(A[row]):
10 | TA[col][row] = num
11 |
12 | return TA
--------------------------------------------------------------------------------
/python/89_gray_code.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def grayCode(self, n: int) -> List[int]:
3 |
4 | res = []
5 |
6 | if n == 0:
7 | return [0]
8 |
9 | res.append(0)
10 | res.append(1)
11 |
12 | shift = 1
13 | while shift < n:
14 |
15 | # obtain the symmetric samples of the current results
16 | size = len(res)
17 | for i in range(size-1, -1, -1):
18 | new_value = res[i] | (1 << shift)
19 | res.append(new_value)
20 |
21 | shift += 1
22 |
23 | return res
24 |
--------------------------------------------------------------------------------
/python/905_sort_by_parity.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def sortArrayByParity(self, A: List[int]) -> List[int]:
3 | A.sort(key=lambda x:x%2)
4 | return A
5 |
6 |
7 | class SolutionTwoPointers:
8 | def sortArrayByParity(self, A: List[int]) -> List[int]:
9 |
10 | p_odd, p_even = 0, len(A)-1
11 | while p_odd < p_even:
12 |
13 | if A[p_odd] % 2 == 0:
14 | p_odd += 1
15 | elif A[p_even] % 2 == 1:
16 | p_even -= 1
17 | else:
18 | A[p_odd], A[p_even] = A[p_even], A[p_odd]
19 |
20 | return A
--------------------------------------------------------------------------------
/python/91_decode_ways.py:
--------------------------------------------------------------------------------
1 | """
2 | A message containing letters from A-Z is being encoded to numbers using the following mapping:
3 |
4 | 'A' -> 1
5 | 'B' -> 2
6 | ...
7 | 'Z' -> 26
8 | Given a non-empty string containing only digits, determine the total number of ways to decode it.
9 |
10 | Example 1:
11 |
12 | Input: "12"
13 | Output: 2
14 | Explanation: It could be decoded as "AB" (1 2) or "L" (12).
15 |
16 |
17 | Note:
18 | there are a few "exceptional" test cases, such as '0', '101' and '01' that one should takes into account.
19 |
20 | """
21 |
22 | from functools import lru_cache
23 |
24 |
25 | class Solution:
26 | def numDecodings(self, s: str) -> int:
27 | return self.count(s)
28 |
29 | @lru_cache(maxsize=None)
30 | def count(self, s):
31 | """ recursion with memoization
32 | """
33 | if len(s) == 0:
34 | return 1
35 |
36 | if s[0] == '0':
37 | return 0
38 |
39 | if len(s) == 1:
40 | return self.count(s[1:])
41 | if len(s) >= 2:
42 | if int(s[0:2]) < 27:
43 | return self.count(s[1:]) + self.count(s[2:])
44 | else:
45 | return self.count(s[1:])
46 |
47 |
--------------------------------------------------------------------------------
/python/921_minimal_add_to_make_parentheses_valid.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def minAddToMakeValid(self, s: str) -> int:
3 | stack = []
4 |
5 | missing_count = 0
6 | for bracket in s:
7 | if bracket == "(":
8 | stack.append(bracket)
9 | else: # ")"
10 | if len(stack) == 0:
11 | missing_count += 1
12 | else:
13 | stack.pop()
14 |
15 | return missing_count + len(stack)
16 |
--------------------------------------------------------------------------------
/python/925_long_pressed_name.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def isLongPressedName(self, name: str, typed: str) -> bool:
3 |
4 | # two pointers to the "name" and "typed" string respectively
5 | np, tp = 0, 0
6 |
7 | # advance two pointers, until we exhaust one of the strings
8 | while np < len(name) and tp < len(typed):
9 | if name[np] == typed[tp]:
10 | np += 1
11 | tp += 1
12 | elif tp >= 1 and typed[tp] == typed[tp-1]:
13 | tp += 1
14 | else:
15 | return False
16 |
17 | # if there is still some characters left *unmatched* in the origin string,
18 | # then we don't have a match.
19 | # e.g. name = "abc" typed = "aabb"
20 | if np != len(name):
21 | return False
22 | else:
23 | # In the case that there are some redundant characters left in typed
24 | # we could still have a match.
25 | # e.g. name = "abc" typed = "abccccc"
26 | while tp < len(typed):
27 | if typed[tp] != typed[tp-1]:
28 | return False
29 | tp += 1
30 |
31 | return True
--------------------------------------------------------------------------------
/python/933_number_of_recent_calls.py:
--------------------------------------------------------------------------------
1 | class RecentCounter:
2 |
3 | def __init__(self):
4 | self.slide_window = deque()
5 |
6 | def ping(self, t: int) -> int:
7 | self.slide_window.append(t)
8 |
9 | # invalidate the outdated pings
10 | while self.slide_window:
11 | if self.slide_window[0] < t - 3000:
12 | self.slide_window.popleft()
13 | else:
14 | break
15 |
16 | return len(self.slide_window)
17 |
18 |
19 | # Your RecentCounter object will be instantiated and called as such:
20 | # obj = RecentCounter()
21 | # param_1 = obj.ping(t)
--------------------------------------------------------------------------------
/python/938_range_sum_of_BST.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def rangeSumBST(self, root: TreeNode, L: int, R: int) -> int:
9 |
10 | value_sum = 0
11 | def dfs(node):
12 | nonlocal value_sum
13 | if not node:
14 | return
15 | if L <= node.val <= R:
16 | value_sum += node.val
17 |
18 | if node.val >= L:
19 | dfs(node.left)
20 | if node.val <= R:
21 | dfs(node.right)
22 |
23 | dfs(root)
24 |
25 | return value_sum
--------------------------------------------------------------------------------
/python/946_validate_stack_sequences.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:
3 |
4 | if len(pushed) == 0:
5 | return len(popped) == 0
6 |
7 | stack = list()
8 | push_curr, pop_curr = 1, 0
9 | stack.append(pushed[0])
10 |
11 | while pop_curr < len(popped):
12 |
13 | if len(stack) > 0 and popped[pop_curr] == stack[-1]:
14 | stack.pop()
15 | pop_curr += 1
16 | elif push_curr < len(pushed):
17 | stack.append(pushed[push_curr])
18 | push_curr += 1
19 | else:
20 | return False
21 |
22 | return pop_curr == len(popped)
--------------------------------------------------------------------------------
/python/949_Lagest_Time_for_Given_Digits.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def largestTimeFromDigits(self, A: List[int]) -> str:
3 |
4 | max_time = -1
5 | # enumerate all possiblities, with the permutation() func
6 | for h, i, j, k in itertools.permutations(A):
7 | hour = h*10 + i
8 | minute = j*10 + k
9 | if hour < 24 and minute < 60:
10 | max_time = max(max_time, hour * 60 + minute)
11 |
12 | if max_time == -1:
13 | return ""
14 | else:
15 | # string formatting with leading zero padding
16 | return "{:02d}:{:02d}".format(max_time // 60, max_time % 60)
17 |
--------------------------------------------------------------------------------
/python/94_binary_tree_inorder_traversal.py:
--------------------------------------------------------------------------------
1 | # Definition for a binary tree node.
2 | # class TreeNode:
3 | # def __init__(self, val=0, left=None, right=None):
4 | # self.val = val
5 | # self.left = left
6 | # self.right = right
7 | class Solution:
8 | def inorderTraversal(self, root: TreeNode) -> List[int]:
9 |
10 | def inorderDFS(node, results):
11 | if not node:
12 | return
13 |
14 | inorderDFS(node.left, results)
15 | results.append(node.val)
16 | inorderDFS(node.right, results)
17 |
18 |
19 | results = []
20 | inorderDFS(root, results)
21 |
22 | return results
23 |
--------------------------------------------------------------------------------
/python/953_verifying_an_alien_dictionary.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def isAlienSorted(self, words: List[str], order: str) -> bool:
3 |
4 | # handle the edge case, as well as a cheap optimization
5 | if len(words) <= 1:
6 | return True
7 |
8 | letter_order = {}
9 | for rank, letter in enumerate(order):
10 | letter_order[letter] = rank
11 |
12 | def is_less_than(word1, word2):
13 | bound = min(len(word1), len(word2))
14 | index = 0
15 | while index < bound:
16 | if letter_order[word1[index]] < letter_order[word2[index]]:
17 | return True
18 | elif letter_order[word1[index]] > letter_order[word2[index]]:
19 | return False
20 | index += 1
21 |
22 | return True if len(word1) <= len(word2) else False
23 |
24 |
25 | prev_word = words[0]
26 | for next_word in words[1:]:
27 | if not is_less_than(prev_word, next_word):
28 | return False
29 | prev_word = next_word
30 |
31 |
32 | return True
33 |
34 |
35 |
--------------------------------------------------------------------------------
/python/956_tallest_billboard.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def tallestBillboard(self, rods: List[int]) -> int:
3 |
4 | # knapsack problem
5 | # each rod to be placed in either left or right bin, or discarded
6 | # find the maximum sum of postive numbers, with the total sum of zero
7 | dp = {}
8 | # dp[sum] = max_sum_of_postive_number (left bin)
9 | dp[0] = 0
10 | for rod in rods:
11 |
12 | newDP = defaultdict(int)
13 | for rodSum in dp:
14 | newDP[rodSum] = max(dp[rodSum], newDP[rodSum])
15 | newDP[rodSum + rod] = max(dp[rodSum] + rod, newDP[rodSum + rod])
16 | newDP[rodSum - rod] = max(dp[rodSum], newDP[rodSum - rod])
17 |
18 | dp = newDP
19 |
20 | return dp[0]
21 |
--------------------------------------------------------------------------------
/python/957_Prison_Cells_After_N_Days.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def prisonAfterNDays(self, cells: List[int], N: int) -> List[int]:
3 |
4 | seen = defaultdict(int)
5 | is_fast_forwarded = False
6 |
7 | while N > 0:
8 | if not is_fast_forwarded:
9 | state_key = tuple(cells)
10 | last_seen_index = seen[state_key]
11 | if last_seen_index != 0:
12 | N %= seen[state_key] - N
13 | is_fast_forwarded = True
14 | else:
15 | seen[state_key] = N
16 |
17 | if N > 0:
18 | N -= 1
19 | next_day_cells = self.nextDay(cells)
20 | cells = next_day_cells
21 |
22 | return cells
23 |
24 |
25 | def nextDay(self, cells: List[int]):
26 | ret = []
27 | for i in range(len(cells)):
28 | if i > 0 and i < 7 and cells[i-1] == cells[i+1]:
29 | ret.append(1)
30 | else:
31 | ret.append(0)
32 | return ret
33 |
--------------------------------------------------------------------------------
/python/967_Numbers_With_Same_Consecutive_Differences.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def numsSameConsecDiff(self, N: int, K: int) -> List[int]:
3 |
4 | if N == 1:
5 | return [i for i in range(10)]
6 |
7 | ans = []
8 |
9 | def DFS(N, num):
10 | if N == 1:
11 | return ans.append(num)
12 |
13 | tail_digit = num % 10
14 | next_digits = set([tail_digit + K, tail_digit - K])
15 | for next_digit in next_digits:
16 | if 0 <= next_digit < 10:
17 | new_num = num * 10 + next_digit
18 | DFS(N-1, new_num)
19 |
20 | for num in range(1, 10):
21 | DFS(N, num)
22 |
23 | return list(ans)
24 |
25 |
--------------------------------------------------------------------------------
/python/973_k_closest_points_to_origin.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def kClosest(self, points: List[List[int]], k: int) -> List[List[int]]:
3 |
4 | distance_queue = []
5 |
6 | for point in points:
7 | x, y = point
8 | distance = x ** 2 + y ** 2
9 | distance_queue.append((distance, [x, y]))
10 |
11 | heapq.heapify(distance_queue)
12 | output = []
13 | while k:
14 | distance, point = heapq.heappop(distance_queue)
15 | output.append(point)
16 | k -= 1
17 |
18 | return output
--------------------------------------------------------------------------------
/python/974_Subarray_Sums_Divisable_by_K.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def subarraysDivByK(self, A: List[int], K: int) -> int:
3 |
4 | prefix_sum_group = defaultdict(int)
5 |
6 | prefix_sum = 0
7 | count = 0
8 |
9 | for num in A:
10 | prefix_sum += num
11 | prefix_sum %= K
12 | prefix_sum_group[prefix_sum] += 1
13 |
14 | for group_key, group_size in prefix_sum_group.items():
15 | if group_key == 0:
16 | # number of solutions constructed by modulo of K
17 | count += (group_size * (group_size -1))/2 + group_size
18 | elif group_size > 1:
19 | # number of solutions constructed by non-modulo of K
20 | count += group_size * (group_size -1) / 2
21 |
22 | return int(count)
23 |
--------------------------------------------------------------------------------
/python/977_squares_of_a_sorted_array.py:
--------------------------------------------------------------------------------
1 | class Solution:
2 | def sortedSquares(self, A: List[int]) -> List[int]:
3 |
4 | result = [0] * len(A)
5 |
6 | # pointers to left and right end of the array.
7 | lp, rp = 0, len(A)-1
8 | sp = len(A) - 1 # pointer for the result list
9 |
10 | while sp >= 0:
11 | if abs(A[lp]) > abs(A[rp]):
12 | result[sp] = A[lp] * A[lp]
13 | lp += 1
14 | else:
15 | result[sp] = A[rp] * A[rp]
16 | rp -= 1
17 | sp -= 1
18 |
19 | return result
20 |
--------------------------------------------------------------------------------
/python/983_minimum_costs_for_tickets.py:
--------------------------------------------------------------------------------
1 |
2 | class Solution:
3 | def mincostTickets(self, days: List[int], costs: List[int]) -> int:
4 |
5 | """
6 | Dynamic programming in the bottom-up approach
7 | """
8 | N = len(days)
9 |
10 | # dp[i] the minimum cost if the travel is of the postfix: days[i:]
11 | dp = [0] * (N+1)
12 |
13 | # should be the 1-day pass, if the input is designed properly
14 | # i.e. one day should be the least expensive of all.
15 | # the minimal cost of ticket if the travel plan consists of one day
16 | dp[N-1] = min(costs)
17 |
18 | for index in range(N-2, -1, -1):
19 | curr_day = days[index]
20 | min_cost = float('inf')
21 |
22 | # Try different plans from the current day till the end
23 | for ci, duration in enumerate([1, 7, 30]):
24 | next_day_index = index
25 | while next_day_index < N and days[next_day_index] < curr_day + duration :
26 | next_day_index += 1
27 |
28 | min_cost = min(min_cost, costs[ci] + dp[next_day_index])
29 | # fill the best plan for the postfix plan, days[index:]
30 | dp[index] = min_cost
31 |
32 | return dp[0]
33 |
--------------------------------------------------------------------------------
/python/insert_digit_5.py:
--------------------------------------------------------------------------------
1 | """
2 | Insert the digit '5' to an integer to make the resulting integer as big as possible
3 |
4 | e.g.
5 | 234 -> 5234
6 | 679 -> 6795
7 | -23 -> -235
8 | """
9 |
10 | from collections import deque
11 |
12 | def solution(N):
13 |
14 | positive = True if N >= 0 else False
15 |
16 | if not positive:
17 | N = - N
18 |
19 | # split the integer number into a list of digits
20 | nums = deque([])
21 | remainder = N
22 | while remainder > 0:
23 | nums.appendleft(remainder % 10)
24 | remainder = remainder // 10
25 |
26 | new_nums = []
27 | inserted = False
28 | for digit in nums:
29 | if positive:
30 | if 5 >= digit and not inserted:
31 | new_nums.append(5)
32 | inserted = True
33 | new_nums.append(digit)
34 | else:
35 | if 5 <= digit and not inserted:
36 | new_nums.append(5)
37 | inserted = True
38 | new_nums.append(digit)
39 |
40 | if not inserted:
41 | new_nums.append(5)
42 |
43 | # aggregate a list of digits into an integer
44 | power = 1
45 | result = 0
46 | for digit in reversed(new_nums):
47 | result += power * digit
48 | power = power * 10
49 |
50 | if positive:
51 | return result
52 | else:
53 | return -result
54 |
--------------------------------------------------------------------------------
/python/minimal_coin_changes.py:
--------------------------------------------------------------------------------
1 | from functools import lru_cache
2 |
3 |
4 | """
5 | Given an amount, return the combination of coin changes,
6 | so that the total number of coins is minimal.
7 | The available coins are [25, 10, 5, 1]
8 | """
9 |
10 | def make_change(amount):
11 |
12 | min_comb = (float("inf"), 0, 0, 0)
13 |
14 | @lru_cache(maxsize=None)
15 | def dp(sub_amount, comb):
16 | nonlocal min_comb
17 | #print(sub_amount, comb)
18 |
19 | if sub_amount < 0:
20 | return
21 | elif sub_amount == 0:
22 | if sum(comb) < sum(min_comb):
23 | min_comb = comb
24 | return
25 |
26 | for index, coin in enumerate([25, 10, 5, 1]):
27 | if sub_amount >= coin:
28 | next_comb = list(comb)
29 | next_comb[index] += 1
30 | dp(sub_amount - coin, tuple(next_comb))
31 |
32 | init_comb = (0, 0, 0, 0)
33 |
34 | dp(amount, init_comb)
35 | return min_comb
36 |
--------------------------------------------------------------------------------