├── .gitignore ├── CHANGELOG ├── LICENSE ├── NAMING-CONVENTION.md ├── README.md ├── owl ├── __init__.py ├── api │ ├── __init__.py │ ├── browser │ │ ├── README.md │ │ ├── __init__.py │ │ ├── base_testcase.py │ │ ├── selenium_api.py │ │ ├── selenium_browser.py │ │ └── selenium_driver.py │ ├── interface │ │ ├── README.md │ │ ├── __init__.py │ │ ├── http_requests.py │ │ └── rpc │ │ │ ├── __init__.py │ │ │ ├── dubbo-client.md │ │ │ ├── dubbo_client.py │ │ │ ├── grpc-serve-client.md │ │ │ ├── hessian_client.py │ │ │ ├── thrift-intro.md │ │ │ ├── thrift-server-client.md │ │ │ └── thrift_client.py │ └── mobile │ │ ├── README.md │ │ ├── __init__.py │ │ ├── adb │ │ ├── __init__.py │ │ ├── adb.py │ │ └── event_keys.py │ │ ├── appium_api.py │ │ ├── appium_controller.py │ │ ├── appium_driver.py │ │ ├── appium_server.py │ │ ├── base_testcase.py │ │ ├── intro.md │ │ ├── permission.json │ │ ├── record │ │ ├── __init__.py │ │ ├── action.py │ │ ├── action_windows.py │ │ ├── bulid_windows.bat │ │ ├── event_windows.py │ │ └── op.txt │ │ └── services │ │ ├── PerformanceCtrl.py │ │ ├── __init__.py │ │ ├── apk_manager.py │ │ └── device_info.py ├── configs │ ├── __init__.py │ ├── appium_cfg.py │ ├── default-owl.ini │ └── selenium_cfg.py ├── database │ ├── __init__.py │ ├── ftp_client.py │ ├── lindorm_client.py │ ├── mongo_client.py │ ├── mysql_client.py │ ├── oracle_client.py │ ├── rabbitmq_client.py │ └── redis_client.py ├── domain │ ├── __init__.py │ ├── appium_config_do.py │ ├── mobile_info_do.py │ ├── request_struct_do.py │ ├── requester_do.py │ ├── se_config_do.py │ ├── selector_enum.py │ └── ua_enum.py ├── exception │ ├── __init__.py │ ├── device_type.py │ ├── owl_type.py │ └── server_type.py ├── lib │ ├── __init__.py │ ├── clear_pyc.py │ ├── common.py │ ├── decorator.py │ ├── encrypt │ │ ├── __init__.py │ │ ├── gzip_encrypt.py │ │ ├── md5_encrypt.py │ │ └── zip_packager.py │ ├── gen │ │ ├── __init__.py │ │ ├── gen_data.py │ │ ├── gen_html.py │ │ ├── gen_image.py │ │ ├── gen_person_data.py │ │ └── gen_screenshot.py │ ├── inspector │ │ ├── __init__.py │ │ ├── string_checker.py │ │ └── xml_checker.py │ ├── jenkins_ci.py │ ├── message │ │ ├── __init__.py │ │ ├── email_msg.py │ │ └── weixin_msg.py │ ├── osystem │ │ ├── __init__.py │ │ ├── dos_command.py │ │ ├── dump_mobile.py │ │ └── system_info.py │ ├── processor │ │ ├── __init__.py │ │ ├── config_processor.py │ │ ├── date_processor.py │ │ ├── excel_processor.py │ │ ├── file_processor.py │ │ ├── object_processor.py │ │ └── string_processor.py │ └── reporter │ │ ├── __init__.py │ │ ├── log4py.py │ │ └── logging.conf ├── owl.jpg └── shell │ ├── local-se.bat │ ├── remote-se.bat │ ├── start-appium.bat │ └── stop-appium.bat ├── requirements.txt ├── setup.py ├── test-algorithms ├── README.md ├── __init__.py ├── algorithms │ ├── __init__.py │ ├── arrays │ │ ├── __init__.py │ │ ├── delete_nth.py │ │ ├── flatten.py │ │ ├── garage.py │ │ ├── josephus.py │ │ ├── limit.py │ │ ├── longest_non_repeat.py │ │ ├── max_ones_index.py │ │ ├── merge_intervals.py │ │ ├── missing_ranges.py │ │ ├── move_zeros.py │ │ ├── n_sum.py │ │ ├── plus_one.py │ │ ├── rotate.py │ │ ├── select_two_sum.py │ │ ├── summarize_ranges.py │ │ ├── three_sum.py │ │ ├── top_1.py │ │ ├── trimmean.py │ │ └── two_sum.py │ ├── automata │ │ ├── __init__.py │ │ └── dfa.py │ ├── backtrack │ │ ├── __init__.py │ │ ├── add_operators.py │ │ ├── anagram.py │ │ ├── array_sum_combinations.py │ │ ├── combination_sum.py │ │ ├── factor_combinations.py │ │ ├── find_words.py │ │ ├── generate_abbreviations.py │ │ ├── generate_parenthesis.py │ │ ├── letter_combination.py │ │ ├── palindrome_partitioning.py │ │ ├── pattern_match.py │ │ ├── permute.py │ │ ├── permute_unique.py │ │ ├── subsets.py │ │ └── subsets_unique.py │ ├── bfs │ │ ├── __init__.py │ │ ├── count_islands.py │ │ ├── maze_search.py │ │ ├── shortest_distance_from_all_buildings.py │ │ └── word_ladder.py │ ├── bit │ │ ├── __init__.py │ │ ├── add_bitwise_operator.py │ │ ├── binary_gap.py │ │ ├── bit_operation.py │ │ ├── bytes_int_conversion.py │ │ ├── count_flips_to_convert.py │ │ ├── count_ones.py │ │ ├── find_difference.py │ │ ├── find_missing_number.py │ │ ├── flip_bit_longest_sequence.py │ │ ├── has_alternative_bit.py │ │ ├── insert_bit.py │ │ ├── power_of_two.py │ │ ├── remove_bit.py │ │ ├── reverse_bits.py │ │ ├── single_number.py │ │ ├── single_number2.py │ │ ├── single_number3.py │ │ ├── subsets.py │ │ └── swap_pair.py │ ├── compression │ │ ├── __init__.py │ │ ├── elias.py │ │ ├── huffman_coding.py │ │ └── rle_compression.py │ ├── dfs │ │ ├── __init__.py │ │ ├── all_factors.py │ │ ├── count_islands.py │ │ ├── maze_search.py │ │ ├── pacific_atlantic.py │ │ ├── sudoku_solver.py │ │ └── walls_and_gates.py │ ├── distribution │ │ ├── __init__.py │ │ └── histogram.py │ ├── dp │ │ ├── __init__.py │ │ ├── buy_sell_stock.py │ │ ├── climbing_stairs.py │ │ ├── coin_change.py │ │ ├── combination_sum.py │ │ ├── edit_distance.py │ │ ├── egg_drop.py │ │ ├── fib.py │ │ ├── hosoya_triangle.py │ │ ├── house_robber.py │ │ ├── int_divide.py │ │ ├── job_scheduling.py │ │ ├── k_factor.py │ │ ├── knapsack.py │ │ ├── longest_common_subsequence.py │ │ ├── longest_increasing.py │ │ ├── matrix_chain_order.py │ │ ├── max_product_subarray.py │ │ ├── max_subarray.py │ │ ├── min_cost_path.py │ │ ├── num_decodings.py │ │ ├── regex_matching.py │ │ ├── rod_cut.py │ │ └── word_break.py │ ├── graph │ │ ├── __init__.py │ │ ├── all_pairs_shortest_path.py │ │ ├── bellman_ford.py │ │ ├── check_bipartite.py │ │ ├── check_digraph_strongly_connected.py │ │ ├── clone_graph.py │ │ ├── count_connected_number_of_component.py │ │ ├── cycle_detection.py │ │ ├── dijkstra.py │ │ ├── find_all_cliques.py │ │ ├── find_path.py │ │ ├── graph.py │ │ ├── markov_chain.py │ │ ├── maximum_flow.py │ │ ├── maximum_flow_bfs.py │ │ ├── maximum_flow_dfs.py │ │ ├── minimum_spanning_tree.py │ │ ├── path_between_two_vertices_in_digraph.py │ │ ├── prims_minimum_spanning.py │ │ ├── satisfiability.py │ │ ├── tarjan.py │ │ ├── transitive_closure_dfs.py │ │ └── traversal.py │ ├── heap │ │ ├── __init__.py │ │ ├── binary_heap.py │ │ ├── k_closest_points.py │ │ ├── merge_sorted_k_lists.py │ │ ├── skyline.py │ │ └── sliding_window_max.py │ ├── linkedlist │ │ ├── __init__.py │ │ ├── add_two_numbers.py │ │ ├── copy_random_pointer.py │ │ ├── delete_node.py │ │ ├── find_loop_port.py │ │ ├── first_cyclic_node.py │ │ ├── intersection.py │ │ ├── is_cyclic.py │ │ ├── is_palindrome.py │ │ ├── is_sorted.py │ │ ├── kth_to_last.py │ │ ├── linkedlist.py │ │ ├── merge_two_list.py │ │ ├── partition.py │ │ ├── remove_duplicates.py │ │ ├── remove_range.py │ │ ├── reverse.py │ │ ├── rotate_list.py │ │ └── swap_in_pairs.py │ ├── map │ │ ├── __init__.py │ │ ├── hashtable.py │ │ ├── is_anagram.py │ │ ├── is_isomorphic.py │ │ ├── longest_common_subsequence.py │ │ ├── randomized_set.py │ │ ├── separate_chaining_hashtable.py │ │ ├── valid_sudoku.py │ │ └── word_pattern.py │ ├── maths │ │ ├── __init__.py │ │ ├── base_conversion.py │ │ ├── chinese_remainder_theorem.py │ │ ├── combination.py │ │ ├── cosine_similarity.py │ │ ├── decimal_to_binary_ip.py │ │ ├── diffie_hellman_key_exchange.py │ │ ├── euler_totient.py │ │ ├── extended_gcd.py │ │ ├── factorial.py │ │ ├── find_order_simple.py │ │ ├── find_primitive_root_simple.py │ │ ├── gcd.py │ │ ├── generate_strobogrammtic.py │ │ ├── hailstone.py │ │ ├── is_strobogrammatic.py │ │ ├── krishnamurthy_number.py │ │ ├── magic_number.py │ │ ├── modular_exponential.py │ │ ├── modular_inverse.py │ │ ├── next_bigger.py │ │ ├── next_perfect_square.py │ │ ├── nth_digit.py │ │ ├── num_digits.py │ │ ├── polynomial.py │ │ ├── power.py │ │ ├── prime_check.py │ │ ├── primes_sieve_of_eratosthenes.py │ │ ├── pythagoras.py │ │ ├── rabin_miller.py │ │ ├── recursive_binomial_coefficient.py │ │ ├── rsa.py │ │ ├── sqrt_precision_factor.py │ │ ├── summing_digits.py │ │ └── symmetry_group_cycle_index.py │ ├── matrix │ │ ├── __init__.py │ │ ├── bomb_enemy.py │ │ ├── cholesky_matrix_decomposition.py │ │ ├── copy_transform.py │ │ ├── count_paths.py │ │ ├── crout_matrix_decomposition.py │ │ ├── matrix_exponentiation.py │ │ ├── matrix_inversion.py │ │ ├── multiply.py │ │ ├── rotate_image.py │ │ ├── search_in_sorted_matrix.py │ │ ├── sort_matrix_diagonally.py │ │ ├── sparse_dot_vector.py │ │ ├── sparse_mul.py │ │ ├── spiral_traversal.py │ │ ├── sudoku_validator.py │ │ └── sum_sub_squares.py │ ├── ml │ │ ├── __init__.py │ │ └── nearest_neighbor.py │ ├── queues │ │ ├── __init__.py │ │ ├── max_sliding_window.py │ │ ├── moving_average.py │ │ ├── priority_queue.py │ │ ├── queue.py │ │ ├── reconstruct_queue.py │ │ └── zigzagiterator.py │ ├── search │ │ ├── __init__.py │ │ ├── binary_search.py │ │ ├── find_max_substring.py │ │ ├── find_min_rotate.py │ │ ├── first_occurrence.py │ │ ├── interpolation_search.py │ │ ├── jump_search.py │ │ ├── last_occurrence.py │ │ ├── linear_search.py │ │ ├── next_greatest_letter.py │ │ ├── search_insert.py │ │ ├── search_range.py │ │ ├── search_rotate.py │ │ ├── ternary_search.py │ │ └── two_sum.py │ ├── set │ │ ├── __init__.py │ │ ├── find_keyboard_row.py │ │ ├── randomized_set.py │ │ └── set_covering.py │ ├── sort │ │ ├── __init__.py │ │ ├── bitonic_sort.py │ │ ├── bogo_sort.py │ │ ├── bubble_sort.py │ │ ├── bucket_sort.py │ │ ├── cocktail_shaker_sort.py │ │ ├── comb_sort.py │ │ ├── counting_sort.py │ │ ├── cycle_sort.py │ │ ├── gnome_sort.py │ │ ├── heap_sort.py │ │ ├── insertion_sort.py │ │ ├── meeting_rooms.py │ │ ├── merge_sort.py │ │ ├── pancake_sort.py │ │ ├── pigeonhole_sort.py │ │ ├── quick_sort.py │ │ ├── radix_sort.py │ │ ├── selection_sort.py │ │ ├── shell_sort.py │ │ ├── sort_colors.py │ │ ├── stooge_sort.py │ │ ├── top_sort.py │ │ └── wiggle_sort.py │ ├── stack │ │ ├── __init__.py │ │ ├── is_consecutive.py │ │ ├── is_sorted.py │ │ ├── longest_abs_path.py │ │ ├── ordered_stack.py │ │ ├── remove_min.py │ │ ├── simplify_path.py │ │ ├── stack.py │ │ ├── stutter.py │ │ ├── switch_pairs.py │ │ └── valid_parenthesis.py │ ├── streaming │ │ ├── __init__.py │ │ ├── misra_gries.py │ │ └── one_sparse_recovery.py │ ├── strings │ │ ├── __init__.py │ │ ├── add_binary.py │ │ ├── atbash_cipher.py │ │ ├── breaking_bad.py │ │ ├── caesar_cipher.py │ │ ├── check_pangram.py │ │ ├── contain_string.py │ │ ├── count_binary_substring.py │ │ ├── decode_string.py │ │ ├── delete_reoccurring.py │ │ ├── domain_extractor.py │ │ ├── encode_decode.py │ │ ├── first_unique_char.py │ │ ├── fizzbuzz.py │ │ ├── group_anagrams.py │ │ ├── int_to_roman.py │ │ ├── is_palindrome.py │ │ ├── is_rotated.py │ │ ├── judge_circle.py │ │ ├── knuth_morris_pratt.py │ │ ├── license_number.py │ │ ├── longest_common_prefix.py │ │ ├── longest_palindromic_substring.py │ │ ├── make_sentence.py │ │ ├── merge_string_checker.py │ │ ├── min_distance.py │ │ ├── multiply_strings.py │ │ ├── one_edit_distance.py │ │ ├── panagram.py │ │ ├── rabin_karp.py │ │ ├── repeat_string.py │ │ ├── repeat_substring.py │ │ ├── reverse_string.py │ │ ├── reverse_vowel.py │ │ ├── reverse_words.py │ │ ├── roman_to_int.py │ │ ├── rotate.py │ │ ├── strip_url_params.py │ │ ├── strong_password.py │ │ ├── text_justification.py │ │ ├── unique_morse.py │ │ ├── validate_coordinates.py │ │ └── word_squares.py │ ├── tree │ │ ├── __init__.py │ │ ├── avl │ │ │ ├── __init__.py │ │ │ └── avl.py │ │ ├── b_tree.py │ │ ├── bin_tree_to_list.py │ │ ├── binary_tree_paths.py │ │ ├── bst │ │ │ ├── BSTIterator.py │ │ │ ├── __init__.py │ │ │ ├── array_to_bst.py │ │ │ ├── bst.py │ │ │ ├── bst_closest_value.py │ │ │ ├── count_left_node.py │ │ │ ├── delete_node.py │ │ │ ├── depth_sum.py │ │ │ ├── height.py │ │ │ ├── is_bst.py │ │ │ ├── kth_smallest.py │ │ │ ├── lowest_common_ancestor.py │ │ │ ├── num_empty.py │ │ │ ├── predecessor.py │ │ │ ├── serialize_deserialize.py │ │ │ ├── successor.py │ │ │ └── unique_bst.py │ │ ├── construct_tree_postorder_preorder.py │ │ ├── deepest_left.py │ │ ├── fenwick_tree │ │ │ ├── __init__.py │ │ │ └── fenwick_tree.py │ │ ├── invert_tree.py │ │ ├── is_balanced.py │ │ ├── is_subtree.py │ │ ├── is_symmetric.py │ │ ├── longest_consecutive.py │ │ ├── lowest_common_ancestor.py │ │ ├── max_height.py │ │ ├── max_path_sum.py │ │ ├── min_height.py │ │ ├── path_sum.py │ │ ├── path_sum2.py │ │ ├── pretty_print.py │ │ ├── red_black_tree │ │ │ ├── __init__.py │ │ │ └── red_black_tree.py │ │ ├── same_tree.py │ │ ├── segment_tree │ │ │ ├── __init__.py │ │ │ ├── iterative_segment_tree.py │ │ │ └── segment_tree.py │ │ ├── traversal │ │ │ ├── __init__.py │ │ │ ├── inorder.py │ │ │ ├── level_order.py │ │ │ ├── postorder.py │ │ │ ├── preorder.py │ │ │ └── zigzag.py │ │ ├── tree.py │ │ └── trie │ │ │ ├── __init__.py │ │ │ ├── add_and_search.py │ │ │ └── trie.py │ ├── unionfind │ │ ├── __init__.py │ │ └── count_islands.py │ └── unix │ │ ├── __init__.py │ │ └── path │ │ ├── __init__.py │ │ ├── full_path.py │ │ ├── join_with_slash.py │ │ ├── simplify_path.py │ │ └── split.py ├── demo_jieba.py ├── interview │ ├── 1.两数之和.py │ ├── 100.相同的树.py │ ├── 101.对称二叉树.py │ ├── 104.二叉树的最大深度.py │ ├── 108.将有序数组转换为二叉搜索树.py │ ├── 110.平衡二叉树.py │ ├── 111.二叉树的最小深度.py │ ├── 112.路径总和.py │ ├── 118.杨辉三角.py │ ├── 119.杨辉三角-ii.py │ ├── 121.买卖股票的最佳时机.py │ ├── 125.验证回文串.py │ ├── 13.罗马数字转整数.py │ ├── 136.只出现一次的数字.py │ ├── 14.最长公共前缀.py │ ├── 141.环形链表.py │ ├── 144.二叉树的前序遍历.py │ ├── 145.二叉树的后序遍历.py │ ├── 160.相交链表.py │ ├── 168.excel表列名称.py │ ├── 169.多数元素.py │ ├── 171.excel-表列序号.py │ ├── 190.颠倒二进制位.py │ ├── 191.位-1-的个数.py │ ├── 2.两数相加.py │ ├── 20.有效的括号.py │ ├── 202.快乐数.py │ ├── 20220722-判断倒序字符串是否相等.py │ ├── 20220726-最长重复子串.py │ ├── 20230426-按字典分割字符串.py │ ├── 20230508-打印菱形.py │ ├── 20231017-螺旋打印二维数组.py │ ├── 20231019-list获取top_n.py │ ├── 203.移除链表元素.py │ ├── 21.合并两个有序链表.py │ ├── 26.删除有序数组中的重复项.py │ ├── 27.移除元素.py │ ├── 28.实现-str-str.py │ ├── 28.找出字符串中第一个匹配项的下标.py │ ├── 3.无重复字符的最长子串.py │ ├── 35.搜索插入位置.py │ ├── 39.组合总和.py │ ├── 5.最长回文子串.py │ ├── 53.最大子数组和.py │ ├── 58.最后一个单词的长度.py │ ├── 66.加一.py │ ├── 67.二进制求和.py │ ├── 69.x-的平方根.py │ ├── 70.爬楼梯.py │ ├── 83.删除排序链表中的重复元素.py │ ├── 88.合并两个有序数组.py │ ├── 9.回文数.py │ ├── 94.二叉树的中序遍历.py │ ├── attr_read_only.py │ ├── get_boss_qadev.py │ ├── get_reservation_info.py │ ├── is_shunzi.py │ ├── merge_ordered_arrays.py │ ├── organize_files.py │ ├── prime_number.py │ ├── readme.md │ ├── sort_list.py │ ├── test_opencv.py │ ├── test_wordcloud.py │ ├── thread_sync.py │ ├── worker-need.png │ ├── worker-need.txt │ ├── z1.随机红包.py │ ├── z2.获取最大版本号.py │ ├── z3.多线程打印字符串-2.py │ ├── z3.多线程打印字符串.py │ ├── z4.删除升序数组里重复.py │ ├── z5.快速排序.py │ ├── z6.快速排序2.py │ ├── z7.bin_tree_iter.py │ └── z8.最大价值.py ├── tests │ ├── demo.py │ ├── demo2.py │ ├── demo3.py │ ├── test_array.py │ ├── test_automata.py │ ├── test_backtrack.py │ ├── test_bfs.py │ ├── test_bit.py │ ├── test_compression.py │ ├── test_dfs.py │ ├── test_dp.py │ ├── test_graph.py │ ├── test_heap.py │ ├── test_histogram.py │ ├── test_iterative_segment_tree.py │ ├── test_linkedlist.py │ ├── test_map.py │ ├── test_maths.py │ ├── test_matrix.py │ ├── test_ml.py │ ├── test_monomial.py │ ├── test_polynomial.py │ ├── test_queues.py │ ├── test_search.py │ ├── test_set.py │ ├── test_singleton.py │ ├── test_sort.py │ ├── test_sqrt.py │ ├── test_stack.py │ ├── test_streaming.py │ ├── test_strings.py │ ├── test_tree.py │ └── test_unix.py └── tox.ini └── tests ├── __init__.py ├── configs ├── appium-service.ini └── owl.ini ├── conftest.py ├── data ├── interface-test-case.xlsx └── users-login-case.xls ├── owl ├── __init__.py ├── appium │ ├── __init__.py │ └── test_appium_case.py ├── selenium │ ├── __init__.py │ ├── docker │ │ ├── Dockerfile-1 │ │ ├── chrome-119 │ │ ├── config.toml │ │ ├── config_copy.toml │ │ ├── custom-chrome │ │ ├── dockerfile │ │ ├── readme.md │ │ ├── requirements.txt │ │ ├── selenium.conf │ │ ├── start-selenium-server-alone.sh │ │ └── start.sh │ ├── test_selenium.py │ └── test_selenium_case.py ├── test_db.py └── test_file_inspector.py ├── pytest.ini ├── run_test.py ├── test_asyncio_cancel.py ├── test_asyncio_pretest_req.py ├── test_cls.py ├── test_http_one.py └── test_pretest_req.py /README.md: -------------------------------------------------------------------------------- 1 | # OWL 2 | 3 | >The owl(override the world limit) project is a tidy implementation for testing purposes 4 | 5 | 6 | * [OWL](#owl) 7 | * [项目设计](#) 8 | * [运行环境](#) 9 | 10 | 11 | **背景:** 这个工程是为了练习或者总结什么而创建的?因为想过去一段时间使用到的 ui自动化(mobile、web)、接口自动化、网络爬虫都融合在同一个工具里,通过 python 来实现。 12 | 因为当前都是脚本曾层面的实现,希望后面有精力结合 flask/tornado 把 web 展示端也实现了。 13 | 14 |
15 | 图片名称 16 |
17 | ## 内容 18 | 19 | ## 项目设计 20 | 21 | * 基于 python 去做 Web UI 自动化、Mobile UI 自动化、接口自动化相关的事情; 22 | * 应用一些经验上的需要:弱耦合,高内聚,复用性,易用性,可读性,易拓展; 23 | * 引用的核心:selenium、appium、requests、allure、pytest; 24 | 25 | ## 运行环境 26 | 27 | 1. [anaconda](https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/):类似于一个本地仓库,就像java的maven一样,第三方库很多,就显得很强大,管理起来也很方便(既然我们的需求本身就很大,那么就需要一个大的基础) 28 | 2. virtualenv:简单型虚拟环境控制工具,但是没有自己的管理仓库,需要手动添加 29 | 3. Pipenv 是一个python的依赖管理器,可以用pip管理依赖,但pip不能提供运行时环境,pipenv会帮你把包和environment的问题一起解决,及pip+virtualenv。 30 | 31 | **开始选择了 virtualenv, 升级 python3+ 后用的 conda** 32 | 33 | -------------------------------------------------------------------------------- /owl/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @file: __init__.py 6 | """ -------------------------------------------------------------------------------- /owl/api/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /owl/api/browser/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jay.zhen 5 | @version: 1.0.0 6 | @license: Apache Licence 7 | @file: __init__.py.py 8 | @time: 2022/10/24 13:17 9 | """ 10 | -------------------------------------------------------------------------------- /owl/api/browser/base_testcase.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @file: base_testcase.py 7 | @time: 2024/3/25 13:24 8 | """ 9 | 10 | from owl.api.browser.selenium_driver import BrowserDriver 11 | 12 | 13 | class BaseTestCase: 14 | """ 15 | 测试用例可以继承,以达到节省代码 16 | """ 17 | driver = None 18 | 19 | # 方法级开始--类里每个测试方法执行前执行 20 | def setup(self): 21 | self.driver = BrowserDriver(self).init_driver() 22 | assert self.driver, "init driver error, recheck" 23 | 24 | # 方法级结束--类里每个测试方法执行后执行 25 | def teardown(self): 26 | if self.driver: 27 | self.driver.stop_web_driver() 28 | -------------------------------------------------------------------------------- /owl/api/interface/README.md: -------------------------------------------------------------------------------- 1 | # 使用 python 来设计简单的接口自动化测试框架 2 | 3 | # 接口api管理平台 4 | 1. [API管理平台XXL-API](https://github.com/xuxueli/xxl-api) 5 | 2. [Web接口管理工具](https://github.com/thx/RAP) 6 | 3. [网易接口管理平台](https://nei.netease.com/login?url=%2Fprogroup%2Fhome%2Fmanagement%2F) 7 | 4. [WireMock](http://wiremock.org/) 8 | 9 | 10 | ## 20170605 11 | 1. http请求中的host、port、path、header、parms(get)、body(psot)、cookie、session等; 12 | 2. 请求中的parms和body中涉及到的数据类型:string、int、dict(json)等; 13 | 3. 请求数据的格式有:转码的base64字符串(图片识别接口)、普通字符串、gzip文件等; 14 | 4. 返回的数据我们需要关注的:网络状态码、cookie、session、接口返回数据格式(json、html)等; 15 | 16 | 5. 我们要做的是封装一套网络请求的api,初始化和配置好我们需要的接口请求参数(url+parms), 17 | 再封装一套解析接口返回数据的api,保存或校验接口返回的数据; 18 | 6. 封装各种处理文件的api,包括文件的编码和解码; 19 | 20 | httpclient.py 模块主要处理接口的请求组合和请求发送 21 | 22 | 参数化方式:class进行类变量定义、config进行定义、excel进行定义、数据库进行定义 23 | 24 | ## 20180620 25 | 1. 接口自动化如果做到线上监控,那么结合网络爬虫的方式来达到监控和定位的效果 26 | 2. 针对接口还是像之前那样确认接口需要的资源,并对其进行规则化管理 27 | 3. 数据模板方式(excel、cvs、数据库),使用pandas库来读写数据 28 | -------------------------------------------------------------------------------- /owl/api/interface/rpc/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @software: PyCharm & Python 2.7 6 | @file: __init__.py.py 7 | @time: 2018/09/14 12:21 8 | """ -------------------------------------------------------------------------------- /owl/api/mobile/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @software: PyCharm & Python 3.7+ 6 | @file: __init__.py 7 | @time: 2023/8/16 13:20 8 | """ 9 | -------------------------------------------------------------------------------- /owl/api/mobile/adb/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/owl/e444919bdc1547e0458f24cf955a822b4c815539/owl/api/mobile/adb/__init__.py -------------------------------------------------------------------------------- /owl/api/mobile/adb/event_keys.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | POWER = 26 5 | BACK = 4 6 | HOME = 3 7 | MENU = 82 8 | VOLUME_UP = 24 9 | VOLUME_DOWN = 25 10 | SPACE = 62 11 | BACKSPACE = 67 12 | ENTER = 66 13 | MOVE_HOME = 122 14 | MOVE_END = 123 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /owl/api/mobile/appium_controller.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @file: appium_controller.py 6 | @time: 2024/3/26 23:08 7 | """ 8 | 9 | from owl.api.mobile.appium_driver import InitAppiumDriver 10 | from owl.configs.appium_cfg import AppiumConfiger 11 | 12 | 13 | class PostRunController(object): 14 | """ 15 | 根据一个设备的sno号来确定一个 appium 操作手 16 | 需要做的是单机模式和多机模式 17 | """ 18 | 19 | def __init__(self, sno=None): 20 | """ 21 | @param sno{string} : 可以指定 sno ,也可以不指定,不指定就用连接的设备中的一个 22 | """ 23 | self.sno = sno 24 | 25 | def get_device_map_appium(self): 26 | appium_props = AppiumConfiger() 27 | impl = InitAppiumDriver(appium_props) 28 | device_list = [self.sno] 29 | if self.sno is None: 30 | device_list = impl.android.get_device_list() 31 | work_api_list = {} 32 | if len(device_list) > 0: 33 | for d in device_list: 34 | work_api_list[d] = impl.get_appium_driver(d) 35 | return work_api_list 36 | 37 | def __str__(self): 38 | return "当前操作的设备号是 {} ".format(self.sno) 39 | -------------------------------------------------------------------------------- /owl/api/mobile/base_testcase.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @file: base_testcase.py 7 | @time: 2024/3/25 13:24 8 | """ 9 | import random 10 | 11 | from owl.api.mobile.appium_api import AppiumWorkApi 12 | from owl.api.mobile.appium_controller import PostRunController 13 | 14 | 15 | class BaseTestCase: 16 | """ 17 | 测试用例可以继承,以达到节省代码 18 | """ 19 | driver = None 20 | 21 | def setup(self): 22 | # 根据当前链接的设备,实例化 appium server 23 | devices = PostRunController().get_device_map_appium() 24 | assert len(devices.keys()) > 0, "No device connection" 25 | self.driver: AppiumWorkApi = devices.get(random.choice(list(devices.keys()))) 26 | 27 | def teardown(self): 28 | if self.driver.driver: 29 | self.driver.driver.quit() 30 | -------------------------------------------------------------------------------- /owl/api/mobile/record/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @software: PyCharm & Python 3.7+ 7 | @file: __init__.py 8 | @time: 2023/8/16 13:20 9 | """ 10 | -------------------------------------------------------------------------------- /owl/api/mobile/record/bulid_windows.bat: -------------------------------------------------------------------------------- 1 | python D:\software\python2.7_32\pyinstaller-2.0\pyinstaller.py -F event_windows.py -------------------------------------------------------------------------------- /owl/api/mobile/services/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | @author: ‘jayzhen‘ 5 | @file: __init__.py.py 6 | """ -------------------------------------------------------------------------------- /owl/database/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/owl/e444919bdc1547e0458f24cf955a822b4c815539/owl/database/__init__.py -------------------------------------------------------------------------------- /owl/database/rabbitmq_client.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: rabbitmq_client.py 8 | @time: 2023/9/4 19:25 9 | pip install pika 10 | """ 11 | 12 | import pika 13 | 14 | conn = pika.BlockingConnection(pika.ConnectionParameters("http://192.168.18.53:5672")) 15 | channel = conn.channel() 16 | channel.queue_declare(queue="testing") 17 | channel.basic_publish(exchange="", routing_key="testing", body="hello jayzhen") 18 | channel.close() -------------------------------------------------------------------------------- /owl/domain/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | @version: v1.0 6 | @author: jayzhen 7 | @license: Apache Licence 8 | @software: PyCharm 9 | @file: __init__.py.py 10 | @time: 2018/4/3 12:49 11 | """ -------------------------------------------------------------------------------- /owl/domain/mobile_info_do.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | @version: v1.0 6 | @author: jayzhen 7 | @license: Apache Licence 8 | @software: PyCharm 9 | @file: mobile_info_do.py 10 | @time: 2017/10/22 17:52 11 | """ 12 | 13 | 14 | class MobileInfos(object): 15 | 16 | def __init__(self): 17 | self.sno = None 18 | self.phone_brand = None 19 | self.phone_model = None 20 | self.os_version = None 21 | self.ram = None 22 | self.dpi = None 23 | self.image_resolution = None 24 | self.ip = None 25 | -------------------------------------------------------------------------------- /owl/domain/selector_enum.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @version: v1.0 5 | @author: jayzhen 6 | @license: Apache Licence 7 | @software: PyCharm 8 | @file: FinderType 9 | @time: 2018/5/8 11:22 10 | """ 11 | 12 | from enum import Enum, unique 13 | 14 | from selenium.webdriver.common.by import By 15 | 16 | 17 | # @unique 18 | class FindBy(By): 19 | pass 20 | # ID = By.ID 21 | # NAME = By.NAME 22 | # CLASS_NAME = By.CLASS_NAME 23 | # CSS_SELECTOR = By.CSS_SELECTOR 24 | # LINK_TEXT = By.LINK_TEXT 25 | # PARTIAL_LINK_TEXT = By.PARTIAL_LINK_TEXT 26 | # TAG_NAME = By.TAG_NAME 27 | # XPATH = By.XPATH 28 | -------------------------------------------------------------------------------- /owl/exception/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @site: https://github.com/gitjayzhen 6 | @version: 1.0.0 7 | @license: Apache Licence 8 | @software: PyCharm & Python 3.7+ 9 | @file: __init__.py 10 | @time: 2023/8/18 11:44 11 | """ 12 | from enum import Enum, unique 13 | 14 | from owl.lib.common import EnumDirectValueMeta 15 | 16 | 17 | @unique 18 | class ExceptionMsg(Enum, metaclass=EnumDirectValueMeta): 19 | 20 | AppiumServiceNotRunning = "the appium service is not running" 21 | NoDeviceConnection = "no mobile devices are connected to the current machine" 22 | SingletonInstantiation = "This class is a singleton!" 23 | BrowserDriverError = "The browser failed to instantiate the driver, please recheck" 24 | -------------------------------------------------------------------------------- /owl/exception/device_type.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @file: device_type.py 6 | @time: 2023/8/18 16:37 7 | """ 8 | from owl.exception import ExceptionMsg 9 | 10 | 11 | class NoDeviceConnectionException(Exception): 12 | def __init__(self, message=ExceptionMsg.NoDeviceConnection): 13 | self.message = message 14 | super().__init__(self.message) 15 | -------------------------------------------------------------------------------- /owl/exception/owl_type.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: owl_type.py 8 | @time: 2023/9/4 17:11 9 | """ 10 | from owl.exception import ExceptionMsg 11 | 12 | 13 | class SingletonInstantiationException(Exception): 14 | def __init__(self, message=ExceptionMsg.SingletonInstantiation): 15 | self.message = message 16 | super().__init__(self.message) 17 | 18 | 19 | class BrowserDriverError(Exception): 20 | def __init__(self, message=ExceptionMsg.BrowserDriverError): 21 | self.message = message 22 | super().__init__(self.message) 23 | -------------------------------------------------------------------------------- /owl/exception/server_type.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @site: https://github.com/gitjayzhen 6 | @version: 1.0.0 7 | @license: Apache Licence 8 | @software: PyCharm & Python 3.7+ 9 | @file: server_type.py 10 | @time: 2023/8/18 11:45 11 | """ 12 | from owl.exception import ExceptionMsg 13 | 14 | 15 | class AppiumServiceNotRunningException(Exception): 16 | def __init__(self, message=ExceptionMsg.AppiumServiceNotRunning): 17 | self.message = message 18 | super().__init__(self.message) 19 | -------------------------------------------------------------------------------- /owl/lib/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @version: v1.0 5 | @author: jayzhen 6 | @license: Apache Licence 7 | @software: PyCharm 8 | @file: __init__.py 9 | @time: 2024/3/30 13:55 10 | """ -------------------------------------------------------------------------------- /owl/lib/encrypt/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @file: __init__.py.py 7 | @time: 2018/3/31 21:06 8 | """ -------------------------------------------------------------------------------- /owl/lib/encrypt/gzip_encrypt.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @site: https://github.com/gitjayzhen 6 | @software: PyCharm & Python 2.7 7 | @file: gzip_encrypt.py 8 | @time: 2018/09/03 16:54 9 | """ 10 | 11 | import gzip 12 | from io import StringIO 13 | 14 | 15 | def gzip_compress(raw_data): 16 | buf = StringIO() 17 | f = gzip.GzipFile(mode='wb', fileobj=buf) 18 | try: 19 | f.write(raw_data) 20 | finally: 21 | f.close() 22 | return buf.getvalue() 23 | 24 | 25 | def gzip_uncompress(c_data): 26 | buf = StringIO(c_data) 27 | f = gzip.GzipFile(mode='rb', fileobj=buf) 28 | try: 29 | r_data = f.read() 30 | finally: 31 | f.close() 32 | return r_data 33 | 34 | 35 | def compress_file(fn_in, fn_out): 36 | f_in = open(fn_in, 'rb') 37 | f_out = gzip.open(fn_out, 'wb') 38 | f_out.writelines(f_in) 39 | f_out.close() 40 | f_in.close() 41 | 42 | 43 | def uncompress_file(fn_in, fn_out): 44 | f_in = gzip.open(fn_in, 'rb') 45 | f_out = open(fn_out, 'wb') 46 | file_content = f_in.read() 47 | f_out.write(file_content) 48 | f_out.close() 49 | f_in.close() 50 | -------------------------------------------------------------------------------- /owl/lib/gen/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: __init__.py 8 | @time: 2024/4/24 15:56 9 | """ 10 | -------------------------------------------------------------------------------- /owl/lib/gen/gen_image.py: -------------------------------------------------------------------------------- 1 | #!usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | @author: jayzhen 6 | @site: https://github.com/gitjayzhen 7 | @software: PyCharm & Python 2.7 8 | @file: gen_image.py 9 | @time: 2018/06/22 17:08 10 | """ 11 | from PIL import Image, ImageDraw, ImageFont 12 | import os 13 | 14 | 15 | def gen_image(text, file_path): 16 | # 创建一个新的图片对象 17 | i = Image.new("RGB", (1900, 1080), (255, 255, 255)) 18 | # 把这个底片先画出来 19 | dr = ImageDraw.Draw(i) 20 | # 为我们即将在这个底片上画东西调好颜料 21 | font = ImageFont.truetype(os.path.join("fonts", "simsun.ttc"), 18) 22 | # 开始下笔,用调好的颜料画给定的内容 23 | dr.text((30, 30), text, font=font, fill="#000000") 24 | # 画好了,展示一下 25 | i.show() 26 | # 记得保存 27 | i.save(file_path, "JPEG") 28 | 29 | 30 | def gen_image_2(text, file_path): 31 | pass -------------------------------------------------------------------------------- /owl/lib/inspector/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: __init__.py 8 | @time: 2024/4/24 15:50 9 | """ 10 | -------------------------------------------------------------------------------- /owl/lib/jenkins_ci.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @file: jenkins_CI 6 | @time: 2018/5/8 20:03 7 | """ 8 | 9 | import jenkins 10 | 11 | # 定义远程的jenkins master server的url,以及port 12 | 13 | jenkins_server_url = 'xxxx:xxxx' 14 | 15 | # 定义用户的User Id 和 API Token,获取方式同上文 16 | 17 | user_id = 'xxxx' 18 | 19 | api_token = 'xxxx' 20 | 21 | # 实例化jenkins对象,连接远程的jenkins master server 22 | 23 | server = jenkins.Jenkins(jenkins_server_url, username=user_id, password=api_token) 24 | 25 | # 构建job名为job_name的job(不带构建参数) 26 | server.build_job(job_name) 27 | # String参数化构建job名为job_name的job, 参数param_dict为字典形式,如:param_dict= {"param1":“value1”, “param2”:“value2”} 28 | 29 | server.build_job(job_name, parameters=param_dict) 30 | 31 | # 获取job名为job_name的job的相关信息 32 | server.get_job_info(job_name) 33 | 34 | # 获取job名为job_name的job的最后次构建号 35 | 36 | server.get_job_info(job_name)['lastBuild']['number'] 37 | 38 | # 获取job名为job_name的job的某次构建的执行结果状态 39 | 40 | server.get_build_info(job_name, build_number)['result'] 41 | 42 | # 判断job名为job_name的job的某次构建是否还在构建中 43 | 44 | server.get_build_info(job_name, build_number)['building'] 45 | -------------------------------------------------------------------------------- /owl/lib/message/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @version: v1.0 5 | @author: jayzhen 6 | @license: Apache Licence 7 | @file: __init__.py.py 8 | @time: 2018/3/31 21:40 9 | """ -------------------------------------------------------------------------------- /owl/lib/osystem/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: __init__.py 8 | @time: 2024/4/24 15:54 9 | """ 10 | -------------------------------------------------------------------------------- /owl/lib/processor/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: __init__.py 8 | @time: 2024/4/24 15:46 9 | """ 10 | -------------------------------------------------------------------------------- /owl/lib/reporter/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @version: v1.0 5 | @author: jayzhen 6 | @license: Apache Licence 7 | @software: PyCharm 8 | @file: __init__.py 9 | @time: 2024/3/30 13:56 10 | """ -------------------------------------------------------------------------------- /owl/owl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/owl/e444919bdc1547e0458f24cf955a822b4c815539/owl/owl.jpg -------------------------------------------------------------------------------- /owl/shell/local-se.bat: -------------------------------------------------------------------------------- 1 | echo '主节点服务启动,并生成注册中心,注意服务所在的机器防火墙要关闭' 2 | 3 | java -jar selenium-server-standalone-2.40.0.jar -role hub -------------------------------------------------------------------------------- /owl/shell/remote-se.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | chcp 65001 4 | 5 | :: '节点启动服务,并连接上注册中心,配置上被访问的参数' 6 | :: rem "-role node -hub http://10.134.101.182:4444/grid/register" 7 | java -jar selenium-server-standalone-2.53.1.jar -browser "browserName=chrome,maxinstance=5,platform=WINDOWS" -Dwebdriver.chrome.driver="..\\driver\\exe\\67chrome2.40\\chromedriver.exe" -log node.log 8 | 9 | pause -------------------------------------------------------------------------------- /owl/shell/start-appium.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | title startAppiumServer 3 | cmd /c "appium -a 127.0.0.1 -p 4723" -------------------------------------------------------------------------------- /owl/shell/stop-appium.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | title stopAppiumServer 3 | tasklist /V|find "startAppiumServer">nul 4 | if %errorlevel%==0 ( 5 | ::关闭appium服务 6 | taskkill /F /IM node.exe 7 | taskkill /F /FI "WINDOWTITLE eq startAppiumServer" 8 | ) 9 | taskkill /F /FI "WINDOWTITLE eq stopAppiumServer" -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pytest==8.1.1 2 | selenium==4.19.0 3 | requests==2.31.0 4 | pandas==2.0.3 5 | styleframe==4.2 6 | chardet~=3.0.4 7 | thrift==0.20.0 8 | pillow==10.3.0 9 | numpy==1.24.4 10 | xlrd~=1.2.0 11 | xlutils~=2.0.0 12 | pymysql~=1.1.0 13 | python-jenkins~=1.5.0 14 | enum34~=1.1.10 15 | appium-python-client==4.0.0 16 | redis==5.0.3 17 | pika~=1.3.2 18 | mysql-connector-python==8.3.0 19 | setuptools==69.2.0 20 | dbutils==3.1.0 21 | opencv-python==4.9.0.80 22 | jieba~=0.42.1 23 | matplotlib==3.7.5 24 | wordcloud~=1.9.3 25 | pytest-rerunfailures 26 | allure-pytest -------------------------------------------------------------------------------- /test-algorithms/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: __init__.py 8 | @time: 2024/3/28 15:21 9 | """ 10 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/owl/e444919bdc1547e0458f24cf955a822b4c815539/test-algorithms/algorithms/__init__.py -------------------------------------------------------------------------------- /test-algorithms/algorithms/arrays/__init__.py: -------------------------------------------------------------------------------- 1 | from .delete_nth import * 2 | from .flatten import * 3 | from .garage import * 4 | from .josephus import * 5 | from .longest_non_repeat import * 6 | from .max_ones_index import * 7 | from .merge_intervals import * 8 | from .missing_ranges import * 9 | from .move_zeros import * 10 | from .plus_one import * 11 | from .rotate import * 12 | from .summarize_ranges import * 13 | from .three_sum import * 14 | from .trimmean import * 15 | from .top_1 import * 16 | from .two_sum import * 17 | from .limit import * 18 | from .n_sum import * 19 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/arrays/delete_nth.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a list lst and a number N, create a new list 3 | that contains each number of the list at most N times without reordering. 4 | 5 | For example if N = 2, and the input is [1,2,3,1,2,1,2,3], you take [1,2,3,1,2], 6 | drop the next [1,2] since this would lead to 1 and 2 being in the result 3 times, and then take 3, 7 | which leads to [1,2,3,1,2,3] 8 | """ 9 | import collections 10 | 11 | 12 | # Time complexity O(n^2) 13 | def delete_nth_naive(array, n): 14 | ans = [] 15 | for num in array: 16 | if ans.count(num) < n: 17 | ans.append(num) 18 | return ans 19 | 20 | 21 | # Time Complexity O(n), using hash tables. 22 | def delete_nth(array, n): 23 | result = [] 24 | counts = collections.defaultdict(int) # keep track of occurrences 25 | 26 | for i in array: 27 | 28 | if counts[i] < n: 29 | result.append(i) 30 | counts[i] += 1 31 | 32 | return result 33 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/arrays/flatten.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implement Flatten Arrays. 3 | Given an array that may contain nested arrays, 4 | produce a single resultant array. 5 | """ 6 | from collections.abc import Iterable 7 | 8 | 9 | # return list 10 | def flatten(input_arr, output_arr=None): 11 | if output_arr is None: 12 | output_arr = [] 13 | for ele in input_arr: 14 | if not isinstance(ele, str) and isinstance(ele, Iterable): 15 | flatten(ele, output_arr) #tail-recursion 16 | else: 17 | output_arr.append(ele) #produce the result 18 | return output_arr 19 | 20 | 21 | # returns iterator 22 | def flatten_iter(iterable): 23 | """ 24 | Takes as input multi dimensional iterable and 25 | returns generator which produces one dimensional output. 26 | """ 27 | for element in iterable: 28 | if not isinstance(element, str) and isinstance(element, Iterable): 29 | yield from flatten_iter(element) 30 | else: 31 | yield element 32 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/arrays/josephus.py: -------------------------------------------------------------------------------- 1 | """ 2 | There are people sitting in a circular fashion, 3 | print every third member while removing them, 4 | the next counter starts immediately after the member is removed. 5 | Print till all the members are exhausted. 6 | 7 | For example: 8 | Input: consider 123456789 members sitting in a circular fashion, 9 | Output: 369485271 10 | """ 11 | 12 | 13 | def josephus(int_list, skip): 14 | skip = skip - 1 # list starts with 0 index 15 | idx = 0 16 | len_list = (len(int_list)) 17 | while len_list > 0: 18 | idx = (skip + idx) % len_list # hash index to every 3rd 19 | yield int_list.pop(idx) 20 | len_list -= 1 21 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/arrays/limit.py: -------------------------------------------------------------------------------- 1 | """ 2 | Sometimes you need to limit array result to use. Such as you only need the 3 | value over 10 or, you need value under than 100. By use this test-algorithms, you 4 | can limit your array to specific value 5 | 6 | If array, Min, Max value was given, it returns array that contains values of 7 | given array which was larger than Min, and lower than Max. You need to give 8 | 'unlimit' to use only Min or Max. 9 | 10 | ex) limit([1,2,3,4,5], None, 3) = [1,2,3] 11 | 12 | Complexity = O(n) 13 | """ 14 | 15 | # tl:dr -- array slicing by value 16 | def limit(arr, min_lim=None, max_lim=None): 17 | min_check = lambda val: True if min_lim is None else (min_lim <= val) 18 | max_check = lambda val: True if max_lim is None else (val <= max_lim) 19 | 20 | return [val for val in arr if min_check(val) and max_check(val)] 21 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/arrays/missing_ranges.py: -------------------------------------------------------------------------------- 1 | """ 2 | Find missing ranges between low and high in the given array. 3 | Ex) [3, 5] lo=1 hi=10 => answer: [(1, 2), (4, 4), (6, 10)] 4 | """ 5 | 6 | def missing_ranges(arr, lo, hi): 7 | 8 | res = [] 9 | start = lo 10 | 11 | for n in arr: 12 | 13 | if n == start: 14 | start += 1 15 | elif n > start: 16 | res.append((start, n-1)) 17 | start = n + 1 18 | 19 | if start <= hi: # after done iterating thru array, 20 | res.append((start, hi)) # append remainder to list 21 | 22 | return res 23 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/arrays/move_zeros.py: -------------------------------------------------------------------------------- 1 | """ 2 | Write an algorithm that takes an array and moves all of the zeros to the end, 3 | preserving the order of the other elements. 4 | move_zeros([false, 1, 0, 1, 2, 0, 1, 3, "a"]) 5 | returns => [false, 1, 1, 2, 1, 3, "a", 0, 0] 6 | 7 | The time complexity of the below algorithm is O(n). 8 | """ 9 | 10 | 11 | # False == 0 is True 12 | def move_zeros(array): 13 | result = [] 14 | zeros = 0 15 | 16 | for i in array: 17 | if i == 0 and type(i) != bool: # not using `not i` to avoid `False`, `[]`, etc. 18 | zeros += 1 19 | else: 20 | result.append(i) 21 | 22 | result.extend([0] * zeros) 23 | return result 24 | 25 | 26 | print(move_zeros([False, 1, 0, 1, 2, 0, 1, 3, "a"])) -------------------------------------------------------------------------------- /test-algorithms/algorithms/arrays/summarize_ranges.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a sorted integer array without duplicates, 3 | return the summary of its ranges. 4 | 5 | For example, given [0, 1, 2, 4, 5, 7], return [(0, 2), (4, 5), (7, 7)]. 6 | """ 7 | 8 | 9 | def summarize_ranges(array): 10 | """ 11 | :type array: List[int] 12 | :rtype: List[] 13 | """ 14 | res = [] 15 | if len(array) == 1: 16 | return [str(array[0])] 17 | i = 0 18 | while i < len(array): 19 | num = array[i] 20 | while i + 1 < len(array) and array[i + 1] - array[i] == 1: 21 | i += 1 22 | if array[i] != num: 23 | res.append((num, array[i])) 24 | else: 25 | res.append((num, num)) 26 | i += 1 27 | return res 28 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/arrays/top_1.py: -------------------------------------------------------------------------------- 1 | """ 2 | This algorithm receives an array and returns most_frequent_value 3 | Also, sometimes it is possible to have multiple 'most_frequent_value's, 4 | so this function returns a list. This result can be used to find a 5 | representative value in an array. 6 | 7 | This algorithm gets an array, makes a dictionary of it, 8 | finds the most frequent count, and makes the result list. 9 | 10 | For example: top_1([1, 1, 2, 2, 3, 4]) will return [1, 2] 11 | 12 | (TL:DR) Get mathematical Mode 13 | Complexity: O(n) 14 | """ 15 | def top_1(arr): 16 | values = {} 17 | #reserve each value which first appears on keys 18 | #reserve how many time each value appears by index number on values 19 | result = [] 20 | f_val = 0 21 | 22 | for i in arr: 23 | if i in values: 24 | values[i] += 1 25 | else: 26 | values[i] = 1 27 | 28 | f_val = max(values.values()) 29 | 30 | for i in values.keys(): 31 | if values[i] == f_val: 32 | result.append(i) 33 | else: 34 | continue 35 | 36 | return result 37 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/arrays/trimmean.py: -------------------------------------------------------------------------------- 1 | """ 2 | When make reliable means, we need to neglect best and worst values. 3 | For example, when making average score on athletes we need this option. 4 | So, this algorithm affixes some percentage to neglect when making mean. 5 | For example, if you suggest 20%, it will neglect the best 10% of values 6 | and the worst 10% of values. 7 | 8 | This algorithm takes an array and percentage to neglect. After sorted, 9 | if index of array is larger or smaller than desired ratio, we don't 10 | compute it. 11 | 12 | Compleity: O(n) 13 | """ 14 | def trimmean(arr, per): 15 | ratio = per/200 16 | # /100 for easy calculation by *, and /2 for easy adaption to best and worst parts. 17 | cal_sum = 0 18 | # sum value to be calculated to trimmean. 19 | arr.sort() 20 | neg_val = int(len(arr)*ratio) 21 | arr = arr[neg_val:len(arr)-neg_val] 22 | for i in arr: 23 | cal_sum += i 24 | return cal_sum/len(arr) 25 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/arrays/two_sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of integers, return indices of the two numbers 3 | such that they add up to a specific target. 4 | 5 | You may assume that each input would have exactly one solution, 6 | and you may not use the same element twice. 7 | 8 | Example: 9 | Given nums = [2, 7, 11, 15], target = 9, 10 | 11 | Because nums[0] + nums[1] = 2 + 7 = 9, 12 | return (0, 1) 13 | """ 14 | 15 | 16 | def two_sum(array, target): 17 | dic = {} 18 | for i, num in enumerate(array): 19 | if num in dic: 20 | return dic[num], i 21 | else: 22 | dic[target - num] = i 23 | return None 24 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/automata/__init__.py: -------------------------------------------------------------------------------- 1 | from .dfa import * 2 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/automata/dfa.py: -------------------------------------------------------------------------------- 1 | def DFA(transitions, start, final, string): 2 | 3 | num = len(string) 4 | num_final = len(final) 5 | cur = start 6 | 7 | for i in range(num): 8 | 9 | if transitions[cur][string[i]] is None: 10 | return False 11 | else: 12 | cur = transitions[cur][string[i]] 13 | 14 | for i in range(num_final): 15 | if cur == final[i]: 16 | return True 17 | return False 18 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/backtrack/__init__.py: -------------------------------------------------------------------------------- 1 | from .add_operators import * 2 | from .anagram import * 3 | from .array_sum_combinations import * 4 | from .combination_sum import * 5 | from .factor_combinations import * 6 | from .find_words import * 7 | from .generate_abbreviations import * 8 | from .generate_parenthesis import * 9 | from .letter_combination import * 10 | from .palindrome_partitioning import * 11 | from .pattern_match import * 12 | from .permute_unique import * 13 | from .permute import * 14 | from .subsets_unique import * 15 | from .subsets import * 16 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/backtrack/anagram.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two strings, determine if they are equal after reordering. 3 | 4 | Examples: 5 | "apple", "pleap" -> True 6 | "apple", "cherry" -> False 7 | """ 8 | 9 | 10 | def anagram(s1, s2): 11 | c1 = [0] * 26 12 | c2 = [0] * 26 13 | 14 | for c in s1: 15 | pos = ord(c)-ord('a') 16 | c1[pos] = c1[pos] + 1 17 | 18 | for c in s2: 19 | pos = ord(c)-ord('a') 20 | c2[pos] = c2[pos] + 1 21 | 22 | return c1 == c2 23 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/backtrack/combination_sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a set of candidate numbers (C) (without duplicates) and a target number 3 | (T), find all unique combinations in C where the candidate numbers sums to T. 4 | 5 | The same repeated number may be chosen from C unlimited number of times. 6 | 7 | Note: 8 | All numbers (including target) will be positive integers. 9 | The solution set must not contain duplicate combinations. 10 | For example, given candidate set [2, 3, 6, 7] and target 7, 11 | A solution set is: 12 | [ 13 | [7], 14 | [2, 2, 3] 15 | ] 16 | """ 17 | 18 | 19 | def combination_sum(candidates, target): 20 | 21 | def dfs(nums, target, index, path, res): 22 | if target < 0: 23 | return # backtracking 24 | if target == 0: 25 | res.append(path) 26 | return 27 | for i in range(index, len(nums)): 28 | dfs(nums, target-nums[i], i, path+[nums[i]], res) 29 | 30 | res = [] 31 | candidates.sort() 32 | dfs(candidates, target, 0, [], res) 33 | return res 34 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/backtrack/generate_abbreviations.py: -------------------------------------------------------------------------------- 1 | """ 2 | given input word, return the list of abbreviations. 3 | ex) 4 | word => ['word', 'wor1', 'wo1d', 'wo2', 'w1rd', 'w1r1', 'w2d', 'w3', '1ord', '1or1', '1o1d', '1o2', '2rd', '2r1', '3d', '4'] 5 | """ 6 | 7 | 8 | def generate_abbreviations(word): 9 | 10 | def backtrack(result, word, pos, count, cur): 11 | if pos == len(word): 12 | if count > 0: 13 | cur += str(count) 14 | result.append(cur) 15 | return 16 | 17 | if count > 0: # add the current word 18 | backtrack(result, word, pos+1, 0, cur+str(count)+word[pos]) 19 | else: 20 | backtrack(result, word, pos+1, 0, cur+word[pos]) 21 | # skip the current word 22 | backtrack(result, word, pos+1, count+1, cur) 23 | 24 | result = [] 25 | backtrack(result, word, 0, 0, "") 26 | return result 27 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/backtrack/generate_parenthesis.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given n pairs of parentheses, write a function to generate 3 | all combinations of well-formed parentheses. 4 | 5 | For example, given n = 3, a solution set is: 6 | 7 | [ 8 | "((()))", 9 | "(()())", 10 | "(())()", 11 | "()(())", 12 | "()()()" 13 | ] 14 | """ 15 | 16 | 17 | def generate_parenthesis_v1(n): 18 | def add_pair(res, s, left, right): 19 | if left == 0 and right == 0: 20 | res.append(s) 21 | return 22 | if right > 0: 23 | add_pair(res, s + ")", left, right - 1) 24 | if left > 0: 25 | add_pair(res, s + "(", left - 1, right + 1) 26 | 27 | res = [] 28 | add_pair(res, "", n, 0) 29 | return res 30 | 31 | 32 | def generate_parenthesis_v2(n): 33 | def add_pair(res, s, left, right): 34 | if left == 0 and right == 0: 35 | res.append(s) 36 | if left > 0: 37 | add_pair(res, s + "(", left - 1, right) 38 | if right > 0 and left < right: 39 | add_pair(res, s + ")", left, right - 1) 40 | 41 | res = [] 42 | add_pair(res, "", n, n) 43 | return res 44 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/backtrack/letter_combination.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a digit string, return all possible letter 3 | combinations that the number could represent. 4 | 5 | A mapping of digit to letters (just like on the telephone buttons) is given below: 6 | 2: "abc" 7 | 3: "def" 8 | 4: "ghi" 9 | 5: "jkl" 10 | 6: "mno" 11 | 7: "pqrs" 12 | 8: "tuv" 13 | 9: "wxyz" 14 | 15 | Input:Digit string "23" 16 | Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. 17 | """ 18 | 19 | 20 | def letter_combinations(digits): 21 | if digits == "": 22 | return [] 23 | kmaps = { 24 | "2": "abc", 25 | "3": "def", 26 | "4": "ghi", 27 | "5": "jkl", 28 | "6": "mno", 29 | "7": "pqrs", 30 | "8": "tuv", 31 | "9": "wxyz" 32 | } 33 | ans = [""] 34 | for num in digits: 35 | tmp = [] 36 | for an in ans: 37 | for char in kmaps[num]: 38 | tmp.append(an + char) 39 | ans = tmp 40 | return ans 41 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/backtrack/permute_unique.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a collection of numbers that might contain duplicates, 3 | return all possible unique permutations. 4 | 5 | For example, 6 | [1,1,2] have the following unique permutations: 7 | [ 8 | [1,1,2], 9 | [1,2,1], 10 | [2,1,1] 11 | ] 12 | """ 13 | 14 | 15 | def permute_unique(nums): 16 | perms = [[]] 17 | for n in nums: 18 | new_perms = [] 19 | for l in perms: 20 | for i in range(len(l)+1): 21 | new_perms.append(l[:i]+[n]+l[i:]) 22 | if i < len(l) and l[i] == n: 23 | break # handles duplication 24 | perms = new_perms 25 | return perms 26 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/backtrack/subsets_unique.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a collection of integers that might contain duplicates, nums, 3 | return all possible subsets. 4 | 5 | Note: The solution set must not contain duplicate subsets. 6 | 7 | For example, 8 | If nums = [1,2,2], a solution is: 9 | 10 | [ 11 | [2], 12 | [1], 13 | [1,2,2], 14 | [2,2], 15 | [1,2], 16 | [] 17 | ] 18 | """ 19 | 20 | 21 | def subsets_unique(nums): 22 | 23 | def backtrack(res, nums, stack, pos): 24 | if pos == len(nums): 25 | res.add(tuple(stack)) 26 | else: 27 | # take 28 | stack.append(nums[pos]) 29 | backtrack(res, nums, stack, pos+1) 30 | stack.pop() 31 | 32 | # don't take 33 | backtrack(res, nums, stack, pos+1) 34 | 35 | res = set() 36 | backtrack(res, nums, [], 0) 37 | return list(res) 38 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/bfs/__init__.py: -------------------------------------------------------------------------------- 1 | from .count_islands import * 2 | from .maze_search import * 3 | from .shortest_distance_from_all_buildings import * 4 | from .word_ladder import * 5 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/bit/__init__.py: -------------------------------------------------------------------------------- 1 | from .add_bitwise_operator import * 2 | from .count_ones import * 3 | from .find_missing_number import * 4 | from .power_of_two import * 5 | from .reverse_bits import * 6 | from .single_number import * 7 | from .single_number2 import * 8 | from .single_number3 import * 9 | from .subsets import * 10 | from .bit_operation import * 11 | from .swap_pair import * 12 | from .find_difference import * 13 | from .has_alternative_bit import * 14 | from .insert_bit import * 15 | from .remove_bit import * 16 | from .count_flips_to_convert import * 17 | from .flip_bit_longest_sequence import * 18 | from .binary_gap import * 19 | from .bytes_int_conversion import * -------------------------------------------------------------------------------- /test-algorithms/algorithms/bit/add_bitwise_operator.py: -------------------------------------------------------------------------------- 1 | """ 2 | The following code adds two positive integers without using the '+' operator. 3 | The code uses bitwise operations to add two numbers. 4 | 5 | Input: 2 3 6 | Output: 5 7 | """ 8 | def add_bitwise_operator(x, y): 9 | 10 | while y: 11 | carry = x & y 12 | x = x ^ y 13 | y = carry << 1 14 | return x 15 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/bit/bytes_int_conversion.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | 4 | def int_to_bytes_big_endian(num): 5 | bytestr = deque() 6 | while num > 0: 7 | # list.insert(0, ...) is inefficient 8 | bytestr.appendleft(num & 0xff) 9 | num >>= 8 10 | return bytes(bytestr) 11 | 12 | 13 | def int_to_bytes_little_endian(num): 14 | bytestr = [] 15 | while num > 0: 16 | bytestr.append(num & 0xff) 17 | num >>= 8 18 | return bytes(bytestr) 19 | 20 | 21 | def bytes_big_endian_to_int(bytestr): 22 | num = 0 23 | for b in bytestr: 24 | num <<= 8 25 | num += b 26 | return num 27 | 28 | 29 | def bytes_little_endian_to_int(bytestr): 30 | num = 0 31 | e = 0 32 | for b in bytestr: 33 | num += b << e 34 | e += 8 35 | return num 36 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/bit/count_flips_to_convert.py: -------------------------------------------------------------------------------- 1 | """ 2 | Write a function to determine the minimal number of bits you would need to 3 | flip to convert integer A to integer B. 4 | For example: 5 | Input: 29 (or: 11101), 15 (or: 01111) 6 | Output: 2 7 | """ 8 | 9 | 10 | def count_flips_to_convert(a, b): 11 | 12 | diff = a ^ b 13 | 14 | # count number of ones in diff 15 | count = 0 16 | while diff: 17 | diff &= (diff - 1) 18 | count += 1 19 | return count 20 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/bit/count_ones.py: -------------------------------------------------------------------------------- 1 | """ 2 | Write a function that takes an unsigned integer and 3 | returns the number of '1' bits it has 4 | (also known as the Hamming weight). 5 | 6 | For example, the 32-bit integer '11' has binary 7 | representation 00000000000000000000000000001011, 8 | so the function should return 3. 9 | 10 | T(n)- O(k) : k is the number of 1s present in binary representation. 11 | NOTE: this complexity is better than O(log n). 12 | e.g. for n = 00010100000000000000000000000000 13 | only 2 iterations are required. 14 | 15 | Number of loops is 16 | equal to the number of 1s in the binary representation.""" 17 | def count_ones_recur(n): 18 | """Using Brian Kernighan's Algorithm. (Recursive Approach)""" 19 | 20 | if not n: 21 | return 0 22 | return 1 + count_ones_recur(n & (n-1)) 23 | 24 | 25 | def count_ones_iter(n): 26 | """Using Brian Kernighan's Algorithm. (Iterative Approach)""" 27 | 28 | count = 0 29 | while n: 30 | n &= (n-1) 31 | count += 1 32 | return count 33 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/bit/find_difference.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two strings s and t which consist of only lowercase letters. 3 | String t is generated by random shuffling string s and then add one more letter 4 | at a random position. Find the letter that was added in t. 5 | 6 | For example: 7 | Input: 8 | s = "abcd" 9 | t = "abecd" 10 | Output: 'e' 11 | 12 | Explanation: 13 | 'e' is the letter that was added. 14 | """ 15 | 16 | """ 17 | We use the characteristic equation of XOR. 18 | A xor B xor C = A xor C xor B 19 | If A == C, then A xor C = 0 20 | and then, B xor 0 = B 21 | """ 22 | def find_difference(s, t): 23 | ret = 0 24 | for ch in s + t: 25 | # ord(ch) return an integer representing the Unicode code point of that character 26 | ret = ret ^ ord(ch) 27 | # chr(i) Return the string representing a character whose Unicode code point is the integer i 28 | return chr(ret) 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/bit/find_missing_number.py: -------------------------------------------------------------------------------- 1 | """ 2 | Returns the missing number from a sequence of unique integers 3 | in range [0..n] in O(n) time and space. The difference between 4 | consecutive integers cannot be more than 1. If the sequence is 5 | already complete, the next integer in the sequence will be returned. 6 | 7 | For example: 8 | Input: nums = [4, 1, 3, 0, 6, 5, 2] 9 | Output: 7 10 | """ 11 | def find_missing_number(nums): 12 | 13 | missing = 0 14 | for i, num in enumerate(nums): 15 | missing ^= num 16 | missing ^= i + 1 17 | 18 | return missing 19 | 20 | 21 | def find_missing_number2(nums): 22 | 23 | num_sum = sum(nums) 24 | n = len(nums) 25 | total_sum = n*(n+1) // 2 26 | missing = total_sum - num_sum 27 | return missing 28 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/bit/flip_bit_longest_sequence.py: -------------------------------------------------------------------------------- 1 | """ 2 | You have an integer and you can flip exactly one bit from a 0 to 1. 3 | Write code to find the length of the longest sequence of 1s you could create. 4 | For example: 5 | Input: 1775 ( or: 11011101111) 6 | Output: 8 7 | """ 8 | 9 | 10 | def flip_bit_longest_seq(num): 11 | 12 | curr_len = 0 13 | prev_len = 0 14 | max_len = 0 15 | 16 | while num: 17 | if num & 1 == 1: # last digit is 1 18 | curr_len += 1 19 | 20 | elif num & 1 == 0: # last digit is 0 21 | if num & 2 == 0: # second last digit is 0 22 | prev_len = 0 23 | else: 24 | prev_len = curr_len 25 | curr_len = 0 26 | 27 | max_len = max(max_len, prev_len + curr_len) 28 | num = num >> 1 # right shift num 29 | 30 | return max_len + 1 31 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/bit/power_of_two.py: -------------------------------------------------------------------------------- 1 | """ 2 | given an integer, write a function to determine if it is a power of two 3 | """ 4 | def is_power_of_two(n): 5 | """ 6 | :type n: int 7 | :rtype: bool 8 | """ 9 | return n > 0 and not n & (n-1) 10 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/bit/remove_bit.py: -------------------------------------------------------------------------------- 1 | """ 2 | Remove_bit(num, i): remove a bit at specific position. 3 | For example: 4 | 5 | Input: num = 10101 (21) 6 | remove_bit(num, 2): output = 1001 (9) 7 | remove_bit(num, 4): output = 101 (5) 8 | remove_bit(num, 0): output = 1010 (10) 9 | """ 10 | 11 | def remove_bit(num, i): 12 | mask = num >> (i + 1) 13 | mask = mask << i 14 | right = ((1 << i) - 1) & num 15 | return mask | right 16 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/bit/reverse_bits.py: -------------------------------------------------------------------------------- 1 | """ 2 | Reverse bits of a given 32 bits unsigned integer. 3 | 4 | For example, given input 43261596 5 | (represented in binary as 00000010100101000001111010011100), 6 | return 964176192 7 | (represented in binary as 00111001011110000010100101000000). 8 | """ 9 | def reverse_bits(n): 10 | m = 0 11 | i = 0 12 | while i < 32: 13 | m = (m << 1) + (n & 1) 14 | n >>= 1 15 | i += 1 16 | return m 17 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/bit/single_number.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of integers, every element appears 3 | twice except for one. Find that single one. 4 | 5 | NOTE: This also works for finding a number occurring odd 6 | number of times, where all the other numbers appear 7 | even number of times. 8 | 9 | Note: 10 | Your algorithm should have a linear runtime complexity. 11 | Could you implement it without using extra memory? 12 | """ 13 | def single_number(nums): 14 | """ 15 | Returns single number, if found. 16 | Else if all numbers appear twice, returns 0. 17 | :type nums: List[int] 18 | :rtype: int 19 | """ 20 | i = 0 21 | for num in nums: 22 | i ^= num 23 | return i 24 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/bit/single_number2.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of integers, every element appears 3 | three times except for one, which appears exactly once. 4 | Find that single one. 5 | 6 | Note: 7 | Your algorithm should have a linear runtime complexity. 8 | Could you implement it without using extra memory? 9 | 10 | 11 | Solution: 12 | 32 bits for each integer. 13 | Consider 1 bit in it, the sum of each integer's corresponding bit 14 | (except for the single number) 15 | should be 0 if mod by 3. Hence, we sum the bits of all 16 | integers and mod by 3, 17 | the remaining should be the exact bit of the single number. 18 | In this way, you get the 32 bits of the single number. 19 | """ 20 | 21 | # Another awesome answer 22 | def single_number2(nums): 23 | ones, twos = 0, 0 24 | for i in range(len(nums)): 25 | ones = (ones ^ nums[i]) & ~twos 26 | twos = (twos ^ nums[i]) & ~ones 27 | return ones 28 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/bit/swap_pair.py: -------------------------------------------------------------------------------- 1 | """ 2 | Swap_pair: A function swap odd and even bits in an integer with as few instructions 3 | as possible (Ex bit and bit 1 are swapped, bit 2 and bit 3 are swapped) 4 | 5 | For example: 6 | 22: 010110 --> 41: 101001 7 | 10: 1010 --> 5 : 0101 8 | """ 9 | 10 | """ 11 | We can approach this as operating on the odds bit first, and then the even bits. 12 | We can mask all odd bits with 10101010 in binary ('AA') then shift them right by 1 13 | Similarly, we mask all even bit with 01010101 in binary ('55') then shift them left 14 | by 1. Finally, we merge these two values by OR operation. 15 | """ 16 | def swap_pair(num): 17 | # odd bit arithmetic right shift 1 bit 18 | odd = (num & int('AAAAAAAA', 16)) >> 1 19 | # even bit left shift 1 bit 20 | even = (num & int('55555555', 16)) << 1 21 | return odd | even 22 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/compression/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/owl/e444919bdc1547e0458f24cf955a822b4c815539/test-algorithms/algorithms/compression/__init__.py -------------------------------------------------------------------------------- /test-algorithms/algorithms/dfs/__init__.py: -------------------------------------------------------------------------------- 1 | from .all_factors import * 2 | from .count_islands import * 3 | from .pacific_atlantic import * 4 | from .sudoku_solver import * 5 | from .walls_and_gates import * 6 | from .maze_search import * 7 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/dfs/count_islands.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a 2d grid map of '1's (land) and '0's (water), 3 | count the number of islands. 4 | An island is surrounded by water and is formed by 5 | connecting adjacent lands horizontally or vertically. 6 | You may assume all four edges of the grid are all surrounded by water. 7 | 8 | Example 1: 9 | 10 | 11110 11 | 11010 12 | 11000 13 | 00000 14 | Answer: 1 15 | 16 | Example 2: 17 | 18 | 11000 19 | 11000 20 | 00100 21 | 00011 22 | Answer: 3 23 | """ 24 | 25 | def num_islands(grid): 26 | count = 0 27 | for i in range(len(grid)): 28 | for j, col in enumerate(grid[i]): 29 | if col == 1: 30 | dfs(grid, i, j) 31 | count += 1 32 | return count 33 | 34 | 35 | def dfs(grid, i, j): 36 | if (i < 0 or i >= len(grid)) or (j < 0 or j >= len(grid[0])): 37 | return 38 | if grid[i][j] != 1: 39 | return 40 | grid[i][j] = 0 41 | dfs(grid, i+1, j) 42 | dfs(grid, i-1, j) 43 | dfs(grid, i, j+1) 44 | dfs(grid, i, j-1) 45 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/distribution/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/owl/e444919bdc1547e0458f24cf955a822b4c815539/test-algorithms/algorithms/distribution/__init__.py -------------------------------------------------------------------------------- /test-algorithms/algorithms/distribution/histogram.py: -------------------------------------------------------------------------------- 1 | """ 2 | Histogram function. 3 | 4 | Histogram is an accurate representation of the distribution of numerical data. 5 | It is an estimate of the probability distribution of a continuous variable. 6 | https://en.wikipedia.org/wiki/Histogram 7 | 8 | Example: 9 | list_1 = [3, 3, 2, 1] 10 | :return {1: 1, 2: 1, 3: 2} 11 | 12 | list_2 = [2, 3, 5, 5, 5, 6, 4, 3, 7] 13 | :return {2: 1, 3: 2, 4: 1, 5: 3, 6: 1, 7: 1} 14 | """ 15 | 16 | 17 | def get_histogram(input_list: list) -> dict: 18 | """ 19 | Get histogram representation 20 | :param input_list: list with different and unordered values 21 | :return histogram: dict with histogram of input_list 22 | """ 23 | # Create dict to store histogram 24 | histogram = {} 25 | # For each list value, add one to the respective histogram dict position 26 | for i in input_list: 27 | histogram[i] = histogram.get(i, 0) + 1 28 | return histogram 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/dp/__init__.py: -------------------------------------------------------------------------------- 1 | from .buy_sell_stock import * 2 | from .climbing_stairs import * 3 | from .coin_change import * 4 | from .combination_sum import * 5 | from .edit_distance import * 6 | from .egg_drop import * 7 | from .fib import * 8 | from .hosoya_triangle import * 9 | from .house_robber import * 10 | from .job_scheduling import * 11 | from .knapsack import * 12 | from .longest_increasing import * 13 | from .matrix_chain_order import * 14 | from .max_product_subarray import * 15 | from .max_subarray import * 16 | from .min_cost_path import * 17 | from .num_decodings import * 18 | from .regex_matching import * 19 | from .rod_cut import * 20 | from .word_break import * 21 | from .int_divide import * 22 | from .k_factor import * 23 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/dp/climbing_stairs.py: -------------------------------------------------------------------------------- 1 | """ 2 | You are climbing a stair case. 3 | It takes n steps to reach to the top. 4 | 5 | Each time you can either climb 1 or 2 steps. 6 | In how many distinct ways can you climb to the top? 7 | 8 | Note: Given n will be a positive integer. 9 | """ 10 | 11 | 12 | # O(n) space 13 | 14 | def climb_stairs(n): 15 | """ 16 | :type n: int 17 | :rtype: int 18 | """ 19 | arr = [1, 1] 20 | for _ in range(1, n): 21 | arr.append(arr[-1] + arr[-2]) 22 | return arr[-1] 23 | 24 | 25 | # the above function can be optimized as: 26 | # O(1) space 27 | 28 | def climb_stairs_optimized(n): 29 | a = b = 1 30 | for _ in range(n): 31 | a, b = b, a + b 32 | return a 33 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/dp/coin_change.py: -------------------------------------------------------------------------------- 1 | """ 2 | Problem 3 | Given a value n, if we want to make change for N cents, and we have infinite supply of each of 4 | coins = {S1, S2, .. , Sm} valued coins, how many ways can we make the change? 5 | The order of coins doesn't matter. 6 | For example, for n = 4 and coins = [1, 2, 3], there are four solutions: 7 | [1, 1, 1, 1], [1, 1, 2], [2, 2], [1, 3]. 8 | So output should be 4. 9 | 10 | For n = 10 and coins = [2, 5, 3, 6], there are five solutions: 11 | [2, 2, 2, 2, 2], [2, 2, 3, 3], [2, 2, 6], [2, 3, 5] and [5, 5]. 12 | So the output should be 5. 13 | 14 | Time complexity: O(n * m) where n is the value and m is the number of coins 15 | Space complexity: O(n) 16 | """ 17 | 18 | def count(coins, n): 19 | # initialize dp array and set base case as 1 20 | dp = [1] + [0] * n 21 | 22 | # fill dp in a bottom up manner 23 | for coin in coins: 24 | for i in range(coin, n+1): 25 | dp[i] += dp[i-coin] 26 | 27 | return dp[n] 28 | 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/dp/house_robber.py: -------------------------------------------------------------------------------- 1 | """ 2 | You are a professional robber planning to rob houses along a street. 3 | Each house has a certain amount of money stashed, 4 | the only constraint stopping you from robbing each of them 5 | is that adjacent houses have security system connected and 6 | it will automatically contact the police if two adjacent houses 7 | were broken into on the same night. 8 | 9 | Given a list of non-negative integers representing the amount of money 10 | of each house, determine the maximum amount of money you 11 | can rob tonight without alerting the police. 12 | """ 13 | 14 | 15 | def house_robber(houses): 16 | last, now = 0, 0 17 | for house in houses: 18 | last, now = now, max(last + house, now) 19 | return now 20 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/dp/int_divide.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given positive integer n, find an algorithm to find the number of non-negative number division, or descomposition. 3 | 4 | The complexity is O(n^2). 5 | 6 | Example 1: 7 | Input: 4 8 | Output: 5 9 | Explaination: 10 | 4=4 11 | 4=3+1 12 | 4=2+2 13 | 4=2+1+1 14 | 4=1+1+1+1 15 | 16 | Example : 17 | Input: 7 18 | Output: 15 19 | Explaination: 20 | 7=7 21 | 7=6+1 22 | 7=5+2 23 | 7=5+1+1 24 | 7=4+3 25 | 7=4+2+1 26 | 7=4+1+1+1 27 | 7=3+3+1 28 | 7=3+2+2 29 | 7=3+2+1+1 30 | 7=3+1+1+1+1 31 | 7=2+2+2+1 32 | 7=2+2+1+1+1 33 | 7=2+1+1+1+1+1 34 | 7=1+1+1+1+1+1+1 35 | 36 | """ 37 | 38 | 39 | def int_divide(n): 40 | arr = [[0 for i in range(n + 1)] for j in range(n + 1)] 41 | arr[1][1] = 1 42 | for i in range(1, n + 1): 43 | for j in range(1, n + 1): 44 | if i < j: 45 | arr[i][j] = arr[i][i] 46 | elif i == j: 47 | arr[i][j] = 1 + arr[i][j - 1] 48 | else: 49 | arr[i][j] = arr[i][j - 1] + arr[i - j][j] 50 | return arr[n][n] 51 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/dp/knapsack.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given the capacity of the knapsack and items specified by weights and values, 3 | return the maximum summarized value of the items that can be fit in the 4 | knapsack. 5 | 6 | Example: 7 | capacity = 5, items(value, weight) = [(60, 5), (50, 3), (70, 4), (30, 2)] 8 | result = 80 (items valued 50 and 30 can both be fit in the knapsack) 9 | 10 | The time complexity is O(n * m) and the space complexity is O(m), where n is 11 | the total number of items and m is the knapsack's capacity. 12 | """ 13 | 14 | 15 | class Item: 16 | 17 | def __init__(self, value, weight): 18 | self.value = value 19 | self.weight = weight 20 | 21 | 22 | def get_maximum_value(items, capacity): 23 | dp = [0] * (capacity + 1) 24 | for item in items: 25 | for cur_weight in reversed(range(item.weight, capacity+1)): 26 | dp[cur_weight] = max(dp[cur_weight], item.value + dp[cur_weight - item.weight]) 27 | return dp[capacity] 28 | 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/dp/max_subarray.py: -------------------------------------------------------------------------------- 1 | 2 | def max_subarray(array): 3 | max_so_far = max_now = array[0] 4 | for i in range(1, len(array)): 5 | max_now = max(array[i], max_now + array[i]) 6 | max_so_far = max(max_so_far, max_now) 7 | return max_so_far 8 | 9 | a = [1, 2, -3, 4, 5, -7, 23] 10 | print(a) 11 | print(max_subarray(a)) 12 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/dp/rod_cut.py: -------------------------------------------------------------------------------- 1 | # A Dynamic Programming solution for Rod cutting problem 2 | INT_MIN = -32767 3 | 4 | # Returns the best obtainable price for a rod of length n and 5 | # price[] as prices of different pieces 6 | def cut_rod(price): 7 | n = len(price) 8 | val = [0]*(n+1) 9 | 10 | # Build the table val[] in bottom up manner and return 11 | # the last entry from the table 12 | for i in range(1, n+1): 13 | max_val = INT_MIN 14 | for j in range(i): 15 | max_val = max(max_val, price[j] + val[i-j-1]) 16 | val[i] = max_val 17 | 18 | return val[n] 19 | 20 | # Driver program to test above functions 21 | arr = [1, 5, 8, 9, 10, 17, 17, 20] 22 | print("Maximum Obtainable Value is " + str(cut_rod(arr))) 23 | 24 | # This code is contributed by Bhavya Jain 25 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/dp/word_break.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a non-empty string s and a dictionary wordDict 3 | containing a list of non-empty words, 4 | determine if s can be segmented into a space-separated 5 | sequence of one or more dictionary words. 6 | You may assume the dictionary does not contain duplicate words. 7 | 8 | For example, given 9 | s = "leetcode", 10 | dict = ["leet", "code"]. 11 | 12 | Return true because "leetcode" can be segmented as "leet code". 13 | """ 14 | 15 | 16 | """ 17 | s = abc word_dict = ["a","bc"] 18 | True False False False 19 | 20 | """ 21 | 22 | 23 | # TC: O(N^2) SC: O(N) 24 | def word_break(s, word_dict): 25 | """ 26 | :type s: str 27 | :type word_dict: Set[str] 28 | :rtype: bool 29 | """ 30 | dp = [False] * (len(s)+1) 31 | dp[0] = True 32 | for i in range(1, len(s)+1): 33 | for j in range(0, i): 34 | if dp[j] and s[j:i] in word_dict: 35 | dp[i] = True 36 | break 37 | return dp[-1] 38 | 39 | 40 | if __name__ == "__main__": 41 | s = "keonkim" 42 | dic = ["keon", "kim"] 43 | 44 | print(word_break(s, dic)) 45 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/graph/__init__.py: -------------------------------------------------------------------------------- 1 | from .tarjan import * 2 | from .check_bipartite import * 3 | from .maximum_flow import * 4 | from .maximum_flow_bfs import * 5 | from .maximum_flow_dfs import * 6 | from .all_pairs_shortest_path import * 7 | from .bellman_ford import * 8 | from .prims_minimum_spanning import * 9 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/graph/all_pairs_shortest_path.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a n*n adjacency array. 3 | it will give you all pairs shortest path length. 4 | use deepcopy to preserve the original information. 5 | 6 | Time complexity : O(E^3) 7 | 8 | example 9 | 10 | a = [[0, 0.1, 0.101, 0.142, 0.277], [0.465, 0, 0.191, 0.192, 0.587], [0.245, 0.554, 0, 0.333, 0.931], [1.032, 0.668, 0.656, 0, 0.151], [0.867, 0.119, 0.352, 0.398, 0]] 11 | 12 | result 13 | 14 | [[0, 0.1, 0.101, 0.142, 0.277], [0.436, 0, 0.191, 0.192, 0.34299999999999997], [0.245, 0.345, 0, 0.333, 0.484], [0.706, 0.27, 0.46099999999999997, 0, 0.151], [0.5549999999999999, 0.119, 0.31, 0.311, 0]] 15 | 16 | """ 17 | import copy 18 | 19 | def all_pairs_shortest_path(adjacency_matrix): 20 | new_array = copy.deepcopy(adjacency_matrix) 21 | 22 | for k in range(len(new_array)): 23 | for i in range(len(new_array)): 24 | for j in range(len(new_array)): 25 | if new_array[i][j] > new_array[i][k] + new_array[k][j]: 26 | new_array[i][j] = new_array[i][k] + new_array[k][j] 27 | 28 | return new_array -------------------------------------------------------------------------------- /test-algorithms/algorithms/graph/check_bipartite.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Bipartite graph is a graph whose vertices can be divided into two disjoint and independent sets. 4 | (https://en.wikipedia.org/wiki/Bipartite_graph) 5 | 6 | Time complexity is O(|E|) 7 | Space complexity is O(|V|) 8 | 9 | """ 10 | 11 | def check_bipartite(adj_list): 12 | 13 | V = len(adj_list) 14 | 15 | # Divide vertexes in the graph into set_type 1 and 2 16 | # Initialize all set_types as -1 17 | set_type = [-1 for v in range(V)] 18 | set_type[0] = 0 19 | 20 | q = [0] 21 | 22 | while q: 23 | v = q.pop(0) 24 | 25 | # If there is a self-loop, it cannot be bipartite 26 | if adj_list[v][v]: 27 | return False 28 | 29 | for u in range(V): 30 | if adj_list[v][u]: 31 | if set_type[u] == set_type[v]: 32 | return False 33 | elif set_type[u] == -1: 34 | # set type of u opposite of v 35 | set_type[u] = 1 - set_type[v] 36 | q.append(u) 37 | 38 | return True 39 | 40 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/graph/markov_chain.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | my_chain = { 4 | 'A': {'A': 0.6, 5 | 'E': 0.4}, 6 | 'E': {'A': 0.7, 7 | 'E': 0.3} 8 | } 9 | 10 | def __choose_state(state_map): 11 | choice = random.random() 12 | probability_reached = 0 13 | for state, probability in state_map.items(): 14 | probability_reached += probability 15 | if probability_reached > choice: 16 | return state 17 | 18 | def next_state(chain, current_state): 19 | next_state_map = chain.get(current_state) 20 | next_state = __choose_state(next_state_map) 21 | return next_state 22 | 23 | def iterating_markov_chain(chain, state): 24 | while True: 25 | state = next_state(chain, state) 26 | yield state 27 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/graph/prims_minimum_spanning.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This Prim's Algorithm Code is for finding weight of minimum spanning tree 3 | of a connected graph. 4 | For argument graph, it should be a dictionary type 5 | such as 6 | graph = { 7 | 'a': [ [3, 'b'], [8,'c'] ], 8 | 'b': [ [3, 'a'], [5, 'd'] ], 9 | 'c': [ [8, 'a'], [2, 'd'], [4, 'e'] ], 10 | 'd': [ [5, 'b'], [2, 'c'], [6, 'e'] ], 11 | 'e': [ [4, 'c'], [6, 'd'] ] 12 | } 13 | 14 | where 'a','b','c','d','e' are nodes (these can be 1,2,3,4,5 as well) 15 | ''' 16 | 17 | 18 | import heapq # for priority queue 19 | 20 | # prim's algo. to find weight of minimum spanning tree 21 | def prims_minimum_spanning(graph_used): 22 | vis=[] 23 | s=[[0,1]] 24 | prim = [] 25 | mincost=0 26 | 27 | while(len(s)>0): 28 | v=heapq.heappop(s) 29 | x=v[1] 30 | if(x in vis): 31 | continue 32 | 33 | mincost += v[0] 34 | prim.append(x) 35 | vis.append(x) 36 | 37 | for j in graph_used[x]: 38 | i=j[-1] 39 | if(i not in vis): 40 | heapq.heappush(s,j) 41 | 42 | return mincost 43 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/heap/__init__.py: -------------------------------------------------------------------------------- 1 | from .binary_heap import * 2 | from .skyline import * 3 | from .sliding_window_max import * 4 | from .merge_sorted_k_lists import * 5 | from .k_closest_points import * 6 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/linkedlist/__init__.py: -------------------------------------------------------------------------------- 1 | from .reverse import * 2 | from .is_sorted import * 3 | from .remove_range import * 4 | from .swap_in_pairs import * 5 | from .rotate_list import * 6 | from .is_cyclic import * 7 | from .merge_two_list import * 8 | from .is_palindrome import * 9 | from .copy_random_pointer import * 10 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/linkedlist/find_loop_port.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | @author: jayzhen 6 | @email: jayzhen_testing@163.com 7 | @site: https://github.com/gitjayzhen 8 | @software: PyCharm & Python 3.7 9 | @file: find_loop_port 10 | @time: 4/9/21 3:13 PM 11 | 12 | /找到链表中环的入口点 13 | public static Node findLoopPort(Node head){ 14 | //首先判断头结点是否为null 15 | if(head==null||head.next==null) 16 | return null; 17 | Node fast = head,slow=head; 18 | //找到相遇点fast 19 | while (true) { 20 | if (fast == null || fast.next == null) { 21 | return null; 22 | } 23 | //找到 24 | slow = slow.next; 25 | fast = fast.next.next; 26 | 27 | if(fast == slow) 28 | break; 29 | } 30 | //相遇点与链表头分别设定一个指针,每次各走一步,相遇第一个点即为环入口点 31 | slow = head;//slow back to start point 32 | while(slow != fast){ 33 | slow = slow.next; 34 | fast = fast.next; 35 | } 36 | return slow; //when slow == fast, it is where cycle begins 37 | } 38 | """ 39 | 40 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/linkedlist/is_cyclic.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a linked list, determine if it has a cycle in it. 3 | 4 | Follow up: 5 | Can you solve it without using extra space? 6 | """ 7 | class Node: 8 | 9 | def __init__(self, x): 10 | self.val = x 11 | self.next = None 12 | 13 | def is_cyclic(head): 14 | """ 15 | 检查是否有环 16 | :type head: Node 17 | :rtype: bool 18 | """ 19 | if not head: 20 | return False 21 | runner = head 22 | walker = head 23 | while runner.next and runner.next.next: 24 | runner = runner.next.next 25 | walker = walker.next 26 | if runner == walker: 27 | return True 28 | return False 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/linkedlist/is_sorted.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a linked list, is_sort function returns true if the list is in sorted 3 | (increasing) order and return false otherwise. An empty list is considered 4 | to be sorted. 5 | 6 | 给定一个链表,如果链表是有序的,is_sort函数返回真 7 | (递增)顺序,否则返回false。考虑空列表 8 | 待分类。 9 | 10 | For example: 11 | Null :List is sorted 12 | 1 2 3 4 :List is sorted 13 | 1 2 -1 3 :List is not sorted 14 | """ 15 | 16 | 17 | def is_sorted(head): 18 | if not head: 19 | return True 20 | current = head 21 | while current.next: 22 | if current.val > current.next.val: 23 | return False 24 | current = current.next 25 | return True 26 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/linkedlist/linkedlist.py: -------------------------------------------------------------------------------- 1 | # Pros 2 | # Linked Lists have constant-time insertions and deletions in any position, 3 | # in comparison, arrays require O(n) time to do the same thing. 4 | # Linked lists can continue to expand without having to specify 5 | # their size ahead of time (remember our lectures on Array sizing 6 | # form the Array Sequence section of the course!) 7 | 8 | # Cons 9 | # To access an element in a linked list, you need to take O(k) time 10 | # to go from the head of the list to the kth element. 11 | # In contrast, arrays have constant time operations to access 12 | # elements in an array. 13 | 14 | 15 | class DoublyLinkedListNode(object): 16 | """双向链表""" 17 | def __init__(self, value): 18 | self.value = value 19 | self.next = None 20 | self.prev = None 21 | 22 | 23 | class SinglyLinkedListNode(object): 24 | """单向链表""" 25 | def __init__(self, value): 26 | self.value = value 27 | self.next = None 28 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/linkedlist/merge_two_list.py: -------------------------------------------------------------------------------- 1 | """ 2 | Merge two sorted linked lists and return it as a new list. The new list should 3 | be made by splicing together the nodes of the first two lists. 4 | 5 | For example: 6 | Input: 1->2->4, 1->3->4 7 | Output: 1->1->2->3->4->4 8 | """ 9 | class Node: 10 | 11 | def __init__(self, x): 12 | self.val = x 13 | self.next = None 14 | 15 | def merge_two_list(l1, l2): 16 | ret = cur = Node(0) 17 | while l1 and l2: 18 | if l1.val < l2.val: 19 | cur.next = l1 20 | l1 = l1.next 21 | else: 22 | cur.next = l2 23 | l2 = l2.next 24 | cur = cur.next 25 | cur.next = l1 or l2 26 | return ret.next 27 | 28 | # recursively 29 | def merge_two_list_recur(l1, l2): 30 | if not l1 or not l2: 31 | return l1 or l2 32 | if l1.val < l2.val: 33 | l1.next = merge_two_list_recur(l1.next, l2) 34 | return l1 35 | else: 36 | l2.next = merge_two_list_recur(l1, l2.next) 37 | return l2 38 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/linkedlist/remove_range.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a linked list, remove_range function accepts a starting and ending index 3 | as parameters and removes the elements at those indexes (inclusive) from the list 4 | 5 | For example: 6 | List: [8, 13, 17, 4, 9, 12, 98, 41, 7, 23, 0, 92] 7 | remove_range(list, 3, 8); 8 | List becomes: [8, 13, 17, 23, 0, 92] 9 | 10 | legal range of the list (0 < start index < end index < size of list). 11 | """ 12 | def remove_range(head, start, end): 13 | assert(start <= end) 14 | # Case: remove node at head 15 | if start == 0: 16 | for i in range(0, end+1): 17 | if head != None: 18 | head = head.next 19 | else: 20 | current = head 21 | # Move pointer to start position 22 | for i in range(0,start-1): 23 | current = current.next 24 | # Remove data until the end 25 | for i in range(0, end-start + 1): 26 | if current != None and current.next != None: 27 | current.next = current.next.next 28 | return head 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/linkedlist/reverse.py: -------------------------------------------------------------------------------- 1 | """ 2 | Reverse a singly linked list. For example: 3 | 4 | 1 --> 2 --> 3 --> 4 5 | After reverse: 6 | 4 --> 3 --> 2 --> 1 7 | """ 8 | # 9 | # Iterative solution 10 | # T(n)- O(n) 11 | # 12 | def reverse_list(head): 13 | """ 14 | :type head: ListNode 15 | :rtype: ListNode 16 | """ 17 | if not head or not head.next: 18 | return head 19 | prev = None 20 | while head: 21 | current = head 22 | head = head.next 23 | current.next = prev 24 | prev = current 25 | return prev 26 | 27 | 28 | # 29 | # Recursive solution 30 | # T(n)- O(n) 31 | # 32 | def reverse_list_recursive(head): 33 | """ 34 | :type head: ListNode 35 | :rtype: ListNode 36 | """ 37 | if head is None or head.next is None: 38 | return head 39 | p = head.next 40 | head.next = None 41 | revrest = reverse_list_recursive(p) 42 | p.next = head 43 | return revrest 44 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/linkedlist/rotate_list.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a list, rotate the list to the right by k places, 3 | where k is non-negative. 4 | 5 | For example: 6 | Given 1->2->3->4->5->NULL and k = 2, 7 | return 4->5->1->2->3->NULL. 8 | """ 9 | 10 | # Definition for singly-linked list. 11 | # class ListNode(object): 12 | # def __init__(self, x): 13 | # self.val = x 14 | # self.next = None 15 | 16 | 17 | def rotate_right(head, k): 18 | """ 19 | :type head: ListNode 20 | :type k: int 21 | :rtype: ListNode 22 | """ 23 | if not head or not head.next: 24 | return head 25 | current = head 26 | length = 1 27 | # count length of the list 28 | while current.next: 29 | current = current.next 30 | length += 1 31 | # make it circular 32 | current.next = head 33 | k = k % length 34 | # rotate until length-k 35 | for i in range(length-k): 36 | current = current.next 37 | head = current.next 38 | current.next = None 39 | return head 40 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/linkedlist/swap_in_pairs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a linked list, swap every two adjacent nodes 3 | and return its head. 4 | 5 | For example, 6 | Given 1->2->3->4, you should return the list as 2->1->4->3. 7 | 8 | Your algorithm should use only constant space. 9 | You may not modify the values in the list, 10 | only nodes itself can be changed. 11 | """ 12 | class Node(object): 13 | def __init__(self, x): 14 | self.val = x 15 | self.next = None 16 | 17 | def swap_pairs(head): 18 | if not head: 19 | return head 20 | start = Node(0) 21 | start.next = head 22 | current = start 23 | while current.next and current.next.next: 24 | first = current.next 25 | second = current.next.next 26 | first.next = second.next 27 | current.next = second 28 | current.next.next = first 29 | current = current.next.next 30 | return start.next 31 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/map/__init__.py: -------------------------------------------------------------------------------- 1 | from .hashtable import * 2 | from .separate_chaining_hashtable import * 3 | from .word_pattern import * 4 | from .is_isomorphic import * 5 | from .is_anagram import * 6 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/map/is_anagram.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two strings s and t , write a function to determine if t is an anagram of s. 3 | 4 | Example 1: 5 | Input: s = "anagram", t = "nagaram" 6 | Output: true 7 | 8 | Example 2: 9 | Input: s = "rat", t = "car" 10 | Output: false 11 | 12 | Note: 13 | You may assume the string contains only lowercase alphabets. 14 | 15 | Reference: https://leetcode.com/problems/valid-anagram/description/ 16 | """ 17 | def is_anagram(s, t): 18 | """ 19 | :type s: str 20 | :type t: str 21 | :rtype: bool 22 | """ 23 | maps = {} 24 | mapt = {} 25 | for i in s: 26 | maps[i] = maps.get(i, 0) + 1 27 | for i in t: 28 | mapt[i] = mapt.get(i, 0) + 1 29 | return maps == mapt 30 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/map/is_isomorphic.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two strings s and t, determine if they are isomorphic. 3 | Two strings are isomorphic if the characters in s can be replaced to get t. 4 | All occurrences of a character must be replaced with another character while 5 | preserving the order of characters. No two characters may map to the same 6 | character but a character may map to itself. 7 | 8 | Example 1: 9 | Input: s = "egg", t = "add" 10 | Output: true 11 | 12 | Example 2: 13 | Input: s = "foo", t = "bar" 14 | Output: false 15 | 16 | Example 3: 17 | Input: s = "paper", t = "title" 18 | Output: true 19 | Reference: https://leetcode.com/problems/isomorphic-strings/description/ 20 | """ 21 | def is_isomorphic(s, t): 22 | """ 23 | :type s: str 24 | :type t: str 25 | :rtype: bool 26 | """ 27 | if len(s) != len(t): 28 | return False 29 | dict = {} 30 | set_value = set() 31 | for i in range(len(s)): 32 | if s[i] not in dict: 33 | if t[i] in set_value: 34 | return False 35 | dict[s[i]] = t[i] 36 | set_value.add(t[i]) 37 | else: 38 | if dict[s[i]] != t[i]: 39 | return False 40 | return True 41 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/map/longest_common_subsequence.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given string a and b, with b containing all distinct characters, 3 | find the longest common sub sequence's length. 4 | 5 | Expected complexity O(n logn). 6 | """ 7 | 8 | 9 | def max_common_sub_string(s1, s2): 10 | # Assuming s2 has all unique chars 11 | s2dic = {s2[i]: i for i in range(len(s2))} 12 | maxr = 0 13 | subs = '' 14 | i = 0 15 | while i < len(s1): 16 | if s1[i] in s2dic: 17 | j = s2dic[s1[i]] 18 | k = i 19 | while j < len(s2) and k < len(s1) and s1[k] == s2[j]: 20 | k += 1 21 | j += 1 22 | if k - i > maxr: 23 | maxr = k-i 24 | subs = s1[i:k] 25 | i = k 26 | else: 27 | i += 1 28 | return subs 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/map/valid_sudoku.py: -------------------------------------------------------------------------------- 1 | """ 2 | Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. 3 | 4 | The Sudoku board could be partially filled, where empty cells are filled with 5 | the character '.'. 6 | """ 7 | 8 | def is_valid_sudoku(self, board): 9 | seen = [] 10 | for i, row in enumerate(board): 11 | for j, c in enumerate(row): 12 | if c != '.': 13 | seen += [(c,j),(i,c),(i/3,j/3,c)] 14 | return len(seen) == len(set(seen)) 15 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/__init__.py: -------------------------------------------------------------------------------- 1 | from .base_conversion import * 2 | from .decimal_to_binary_ip import * 3 | from .euler_totient import * 4 | from .extended_gcd import * 5 | from .factorial import * 6 | from .gcd import * 7 | from .generate_strobogrammtic import * 8 | from .is_strobogrammatic import * 9 | from .modular_exponential import * 10 | from .next_perfect_square import * 11 | from .prime_check import * 12 | from .primes_sieve_of_eratosthenes import * 13 | from .pythagoras import * 14 | from .rabin_miller import * 15 | from .rsa import * 16 | from .combination import * 17 | from .cosine_similarity import * 18 | from .find_order_simple import * 19 | from .find_primitive_root_simple import * 20 | from .diffie_hellman_key_exchange import * 21 | from .num_digits import * 22 | from .power import * 23 | from .magic_number import * 24 | from .krishnamurthy_number import * 25 | 26 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/combination.py: -------------------------------------------------------------------------------- 1 | def combination(n, r): 2 | """This function calculates nCr.""" 3 | if n == r or r == 0: 4 | return 1 5 | else: 6 | return combination(n-1, r-1) + combination(n-1, r) 7 | 8 | def combination_memo(n, r): 9 | """This function calculates nCr using memoization method.""" 10 | memo = {} 11 | def recur(n, r): 12 | if n == r or r == 0: 13 | return 1 14 | if (n, r) not in memo: 15 | memo[(n, r)] = recur(n - 1, r - 1) + recur(n - 1, r) 16 | return memo[(n, r)] 17 | return recur(n, r) 18 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/cosine_similarity.py: -------------------------------------------------------------------------------- 1 | """ 2 | Calculate cosine similarity between given two 1d list. 3 | Two list must have the same length. 4 | 5 | Example: 6 | cosine_similarity([1, 1, 1], [1, 2, -1]) # output : 0.47140452079103173 7 | """ 8 | import math 9 | 10 | 11 | def _l2_distance(vec): 12 | """ 13 | Calculate l2 distance from two given vectors. 14 | """ 15 | norm = 0. 16 | for e in vec: 17 | norm += e * e 18 | norm = math.sqrt(norm) 19 | return norm 20 | 21 | 22 | def cosine_similarity(a, b): 23 | """ 24 | Calculate cosine similarity between given two vectors 25 | :type a: list 26 | :type b: list 27 | """ 28 | if len(a) != len(b): 29 | raise ValueError("The two vectors must be the same length. Got shape " + str(len(a)) + " and " + str(len(b))) 30 | 31 | norm_a = _l2_distance(a) 32 | norm_b = _l2_distance(b) 33 | 34 | similarity = 0. 35 | 36 | # Calculate the dot product of two vectors 37 | for ae, be in zip(a, b): 38 | similarity += ae * be 39 | 40 | similarity /= (norm_a * norm_b) 41 | 42 | return similarity 43 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/decimal_to_binary_ip.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an ip address in dotted-decimal representation, determine the 3 | binary representation. For example, 4 | decimal_to_binary(255.0.0.5) returns 11111111.00000000.00000000.00000101 5 | accepts string 6 | returns string 7 | """ 8 | 9 | def decimal_to_binary_util(val): 10 | bits = [128, 64, 32, 16, 8, 4, 2, 1] 11 | val = int(val) 12 | binary_rep = '' 13 | for bit in bits: 14 | if val >= bit: 15 | binary_rep += str(1) 16 | val -= bit 17 | else: 18 | binary_rep += str(0) 19 | 20 | return binary_rep 21 | 22 | def decimal_to_binary_ip(ip): 23 | values = ip.split('.') 24 | binary_list = [] 25 | for val in values: 26 | binary_list.append(decimal_to_binary_util(val)) 27 | return '.'.join(binary_list) 28 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/euler_totient.py: -------------------------------------------------------------------------------- 1 | """ 2 | Euler's totient function, also known as phi-function ϕ(n), 3 | counts the number of integers between 1 and n inclusive, 4 | which are coprime to n. 5 | (Two numbers are coprime if their greatest common divisor (GCD) equals 1). 6 | """ 7 | def euler_totient(n): 8 | """Euler's totient function or Phi function. 9 | Time Complexity: O(sqrt(n)).""" 10 | result = n; 11 | for i in range(2, int(n ** 0.5) + 1): 12 | if n % i == 0: 13 | while n % i == 0: 14 | n //= i 15 | result -= result // i 16 | if n > 1: 17 | result -= result // n; 18 | return result; 19 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/extended_gcd.py: -------------------------------------------------------------------------------- 1 | def extended_gcd(a, b): 2 | """Extended GCD algorithm. 3 | Return s, t, g 4 | such that a * s + b * t = GCD(a, b) 5 | and s and t are co-prime. 6 | """ 7 | 8 | old_s, s = 1, 0 9 | old_t, t = 0, 1 10 | old_r, r = a, b 11 | 12 | while r != 0: 13 | quotient = old_r / r 14 | 15 | old_r, r = r, old_r - quotient * r 16 | old_s, s = s, old_s - quotient * s 17 | old_t, t = t, old_t - quotient * t 18 | 19 | return old_s, old_t, old_r 20 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/factorial.py: -------------------------------------------------------------------------------- 1 | def factorial(n, mod=None): 2 | """Calculates factorial iteratively. 3 | If mod is not None, then return (n! % mod) 4 | Time Complexity - O(n)""" 5 | if not (isinstance(n, int) and n >= 0): 6 | raise ValueError("'n' must be a non-negative integer.") 7 | if mod is not None and not (isinstance(mod, int) and mod > 0): 8 | raise ValueError("'mod' must be a positive integer") 9 | result = 1 10 | if n == 0: 11 | return 1 12 | for i in range(2, n+1): 13 | result *= i 14 | if mod: 15 | result %= mod 16 | return result 17 | 18 | 19 | def factorial_recur(n, mod=None): 20 | """Calculates factorial recursively. 21 | If mod is not None, then return (n! % mod) 22 | Time Complexity - O(n)""" 23 | if not (isinstance(n, int) and n >= 0): 24 | raise ValueError("'n' must be a non-negative integer.") 25 | if mod is not None and not (isinstance(mod, int) and mod > 0): 26 | raise ValueError("'mod' must be a positive integer") 27 | if n == 0: 28 | return 1 29 | result = n * factorial(n - 1, mod) 30 | if mod: 31 | result %= mod 32 | return result 33 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/find_order_simple.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | """ 4 | For positive integer n and given integer a that satisfies gcd(a, n) = 1, 5 | the order of a modulo n is the smallest positive integer k that satisfies 6 | pow (a, k) % n = 1. In other words, (a^k) ≡ 1 (mod n). 7 | Order of certain number may or may not be exist. If so, return -1. 8 | """ 9 | def find_order(a, n): 10 | if ((a == 1) & (n == 1)): 11 | return 1 12 | """ Exception Handeling : 13 | 1 is the order of of 1 """ 14 | else: 15 | if (math.gcd(a, n) != 1): 16 | print ("a and n should be relative prime!") 17 | return -1 18 | else: 19 | for i in range(1, n): 20 | if (pow(a, i) % n == 1): 21 | return i 22 | return -1 23 | 24 | """ 25 | Time complexity only for calculating order = O(nlog(n)) 26 | O(n) for iteration loop, O(log(n)) for built-in power function 27 | """ 28 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/hailstone.py: -------------------------------------------------------------------------------- 1 | def hailstone(n): 2 | """Return the 'hailstone sequence' from n to 1 3 | n: The starting point of the hailstone sequence 4 | """ 5 | 6 | sequence = [n] 7 | while n > 1: 8 | if n%2 != 0: 9 | n = 3*n + 1 10 | else: 11 | n = int(n/2) 12 | sequence.append(n) 13 | return sequence -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/is_strobogrammatic.py: -------------------------------------------------------------------------------- 1 | """ 2 | A strobogrammatic number is a number that looks 3 | the same when rotated 180 degrees (looked at upside down). 4 | 5 | Write a function to determine if a number is strobogrammatic. 6 | The number is represented as a string. 7 | 8 | For example, the numbers "69", "88", and "818" are all strobogrammatic. 9 | """ 10 | 11 | 12 | def is_strobogrammatic(num): 13 | """ 14 | :type num: str 15 | :rtype: bool 16 | """ 17 | comb = "00 11 88 69 96" 18 | i = 0 19 | j = len(num) - 1 20 | while i <= j: 21 | x = comb.find(num[i]+num[j]) 22 | if x == -1: 23 | return False 24 | i += 1 25 | j -= 1 26 | return True 27 | 28 | 29 | def is_strobogrammatic2(num: str): 30 | """Another implementation.""" 31 | return num == num[::-1].replace('6', '#').replace('9', '6').replace('#', '9') 32 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/modular_exponential.py: -------------------------------------------------------------------------------- 1 | def modular_exponential(base, exponent, mod): 2 | """Computes (base ^ exponent) % mod. 3 | Time complexity - O(log n) 4 | Use similar to Python in-built function pow.""" 5 | if exponent < 0: 6 | raise ValueError("Exponent must be positive.") 7 | base %= mod 8 | result = 1 9 | 10 | while exponent > 0: 11 | # If the last bit is 1, add 2^k. 12 | if exponent & 1: 13 | result = (result * base) % mod 14 | exponent = exponent >> 1 15 | # Utilize modular multiplication properties to combine the computed mod C values. 16 | base = (base * base) % mod 17 | 18 | return result 19 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/modular_inverse.py: -------------------------------------------------------------------------------- 1 | # extended_gcd(a, b) modified from 2 | # https://github.com/keon/algorithms/blob/master/algorithms/maths/extended_gcd.py 3 | 4 | def extended_gcd(a: int, b: int) -> [int, int, int]: 5 | """Extended GCD algorithm. 6 | Return s, t, g 7 | such that a * s + b * t = GCD(a, b) 8 | and s and t are co-prime. 9 | """ 10 | 11 | old_s, s = 1, 0 12 | old_t, t = 0, 1 13 | old_r, r = a, b 14 | 15 | while r != 0: 16 | quotient = old_r // r 17 | 18 | old_r, r = r, old_r - quotient * r 19 | old_s, s = s, old_s - quotient * s 20 | old_t, t = t, old_t - quotient * t 21 | 22 | return old_s, old_t, old_r 23 | 24 | 25 | def modular_inverse(a: int, m: int) -> int: 26 | """ 27 | Returns x such that a * x = 1 (mod m) 28 | a and m must be coprime 29 | """ 30 | 31 | s, t, g = extended_gcd(a, m) 32 | if g != 1: 33 | raise ValueError("a and m must be coprime") 34 | return s % m 35 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/next_perfect_square.py: -------------------------------------------------------------------------------- 1 | """ 2 | This program will look for the next perfect square. 3 | Check the argument to see if it is a perfect square itself, if it is not then return -1 otherwise look for the next perfect square 4 | for instance if you pass 121 then the script should return the next perfect square which is 144. 5 | """ 6 | 7 | def find_next_square(sq): 8 | root = sq ** 0.5 9 | if root.is_integer(): 10 | return (root + 1)**2 11 | return -1 12 | 13 | 14 | # Another way: 15 | 16 | def find_next_square2(sq): 17 | x = sq**0.5 18 | return -1 if x % 1 else (x+1)**2 19 | 20 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/nth_digit.py: -------------------------------------------------------------------------------- 1 | def find_nth_digit(n): 2 | """find the nth digit of given number. 3 | 1. find the length of the number where the nth digit is from. 4 | 2. find the actual number where the nth digit is from 5 | 3. find the nth digit and return 6 | """ 7 | length = 1 8 | count = 9 9 | start = 1 10 | while n > length * count: 11 | n -= length * count 12 | length += 1 13 | count *= 10 14 | start *= 10 15 | start += (n-1) / length 16 | s = str(start) 17 | return int(s[(n-1) % length]) -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/num_digits.py: -------------------------------------------------------------------------------- 1 | """ 2 | num_digits() method will return the number of digits of a number in O(1) time using math.log10() method. 3 | """ 4 | 5 | import math 6 | 7 | def num_digits(n): 8 | n=abs(n) 9 | if(n==0): 10 | return 1; 11 | return int(math.log10(n))+1 12 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/power.py: -------------------------------------------------------------------------------- 1 | def power(a: int, n: int, r: int = None): 2 | """ 3 | Iterative version of binary exponentiation 4 | 5 | Calculate a ^ n 6 | if r is specified, return the result modulo r 7 | 8 | Time Complexity : O(log(n)) 9 | Space Complexity : O(1) 10 | """ 11 | ans = 1 12 | while n: 13 | if n & 1: 14 | ans = ans * a 15 | a = a * a 16 | if r: 17 | ans %= r 18 | a %= r 19 | n >>= 1 20 | return ans 21 | 22 | 23 | def power_recur(a: int, n: int, r: int = None): 24 | """ 25 | Recursive version of binary exponentiation 26 | 27 | Calculate a ^ n 28 | if r is specified, return the result modulo r 29 | 30 | Time Complexity : O(log(n)) 31 | Space Complexity : O(log(n)) 32 | """ 33 | if n == 0: 34 | ans = 1 35 | elif n == 1: 36 | ans = a 37 | else: 38 | ans = power_recur(a, n // 2, r) 39 | ans = ans * ans 40 | if n % 2: 41 | ans = ans * a 42 | if r: 43 | ans %= r 44 | return ans 45 | 46 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/prime_check.py: -------------------------------------------------------------------------------- 1 | def prime_check(n): 2 | """Return True if n is a prime number 3 | Else return False. 4 | """ 5 | 6 | if n <= 1: 7 | return False 8 | if n == 2 or n == 3: 9 | return True 10 | if n % 2 == 0 or n % 3 == 0: 11 | return False 12 | j = 5 13 | while j * j <= n: 14 | if n % j == 0 or n % (j + 2) == 0: 15 | return False 16 | j += 6 17 | return True 18 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/pythagoras.py: -------------------------------------------------------------------------------- 1 | """ 2 | input two of the three side in right angled triangle and return the third. use "?" to indicate the unknown side. 3 | """ 4 | 5 | def pythagoras(opposite,adjacent,hypotenuse): 6 | try: 7 | if opposite == str("?"): 8 | return ("Opposite = " + str(((hypotenuse**2) - (adjacent**2))**0.5)) 9 | elif adjacent == str("?"): 10 | return ("Adjacent = " + str(((hypotenuse**2) - (opposite**2))**0.5)) 11 | elif hypotenuse == str("?"): 12 | return ("Hypotenuse = " + str(((opposite**2) + (adjacent**2))**0.5)) 13 | else: 14 | return "You already know the answer!" 15 | except: 16 | raise ValueError("invalid argument were given.") 17 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/recursive_binomial_coefficient.py: -------------------------------------------------------------------------------- 1 | def recursive_binomial_coefficient(n,k): 2 | """Calculates the binomial coefficient, C(n,k), with n>=k using recursion 3 | Time complexity is O(k), so can calculate fairly quickly for large values of k. 4 | 5 | >>> recursive_binomial_coefficient(5,0) 6 | 1 7 | 8 | >>> recursive_binomial_coefficient(8,2) 9 | 28 10 | 11 | >>> recursive_binomial_coefficient(500,300) 12 | 5054949849935535817667719165973249533761635252733275327088189563256013971725761702359997954491403585396607971745777019273390505201262259748208640 13 | 14 | """ 15 | 16 | if k>n: 17 | raise ValueError('Invalid Inputs, ensure that n >= k') 18 | #function is only defined for n>=k 19 | if k == 0 or n == k: 20 | #C(n,0) = C(n,n) = 1, so this is our base case. 21 | return 1 22 | if k > n/2: 23 | #C(n,k) = C(n,n-k), so if n/2 is sufficiently small, we can reduce the problem size. 24 | return recursive_binomial_coefficient(n,n-k) 25 | else: 26 | #else, we know C(n,k) = (n/k)C(n-1,k-1), so we can use this to reduce our problem size. 27 | return int((n/k)*recursive_binomial_coefficient(n-1,k-1)) 28 | 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/maths/sqrt_precision_factor.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a positive integer N and a precision factor P, 3 | it produces an output 4 | with a maximum error P from the actual square root of N. 5 | 6 | Example: 7 | Given N = 5 and P = 0.001, can produce output x such that 8 | 2.235 < x < 2.237. Actual square root of 5 being 2.236. 9 | """ 10 | 11 | 12 | def square_root(n, epsilon=0.001): 13 | """Return square root of n, with maximum absolute error epsilon""" 14 | guess = n / 2 15 | 16 | while abs(guess * guess - n) > epsilon: 17 | guess = (guess + (n / guess)) / 2 18 | 19 | return guess 20 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/matrix/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/owl/e444919bdc1547e0458f24cf955a822b4c815539/test-algorithms/algorithms/matrix/__init__.py -------------------------------------------------------------------------------- /test-algorithms/algorithms/matrix/multiply.py: -------------------------------------------------------------------------------- 1 | """ 2 | This algorithm takes two compatible two dimensional matrix 3 | and return their product 4 | Space complexity: O(n^2) 5 | Possible edge case: the number of columns of multiplicand not consistent with 6 | the number of rows of multiplier, will raise exception 7 | """ 8 | 9 | 10 | def multiply(multiplicand: list, multiplier: list) -> list: 11 | """ 12 | :type A: List[List[int]] 13 | :type B: List[List[int]] 14 | :rtype: List[List[int]] 15 | """ 16 | multiplicand_row, multiplicand_col = len( 17 | multiplicand), len(multiplicand[0]) 18 | multiplier_row, multiplier_col = len(multiplier), len(multiplier[0]) 19 | if(multiplicand_col != multiplier_row): 20 | raise Exception( 21 | "Multiplicand matrix not compatible with Multiplier matrix.") 22 | # create a result matrix 23 | result = [[0] * multiplier_col for i in range(multiplicand_row)] 24 | for i in range(multiplicand_row): 25 | for j in range(multiplier_col): 26 | for k in range(len(multiplier)): 27 | result[i][j] += multiplicand[i][k] * multiplier[k][j] 28 | return result 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/matrix/rotate_image.py: -------------------------------------------------------------------------------- 1 | """ 2 | You are given an n x n 2D mat representing an image. 3 | 4 | Rotate the image by 90 degrees (clockwise). 5 | 6 | Follow up: 7 | Could you do this in-place? 8 | """ 9 | 10 | 11 | # clockwise rotate 12 | # first reverse up to down, then swap the symmetry 13 | # 1 2 3 7 8 9 7 4 1 14 | # 4 5 6 => 4 5 6 => 8 5 2 15 | # 7 8 9 1 2 3 9 6 3 16 | 17 | def rotate(mat): 18 | if not mat: 19 | return mat 20 | mat.reverse() 21 | for i in range(len(mat)): 22 | for j in range(i): 23 | mat[i][j], mat[j][i] = mat[j][i], mat[i][j] 24 | return mat 25 | 26 | 27 | if __name__ == "__main__": 28 | mat = [[1,2,3], 29 | [4,5,6], 30 | [7,8,9]] 31 | print(mat) 32 | rotate(mat) 33 | print(mat) 34 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/matrix/search_in_sorted_matrix.py: -------------------------------------------------------------------------------- 1 | # 2 | # Search a key in a row wise and column wise sorted (non-decreasing) matrix. 3 | # m- Number of rows in the matrix 4 | # n- Number of columns in the matrix 5 | # T(n)- O(m+n) 6 | # 7 | 8 | 9 | def search_in_a_sorted_matrix(mat, m, n, key): 10 | i, j = m-1, 0 11 | while i >= 0 and j < n: 12 | if key == mat[i][j]: 13 | print ('Key %s found at row- %s column- %s' % (key, i+1, j+1)) 14 | return 15 | if key < mat[i][j]: 16 | i -= 1 17 | else: 18 | j += 1 19 | print ('Key %s not found' % (key)) 20 | 21 | 22 | def main(): 23 | mat = [ 24 | [2, 5, 7], 25 | [4, 8, 13], 26 | [9, 11, 15], 27 | [12, 17, 20] 28 | ] 29 | key = 13 30 | print (mat) 31 | search_in_a_sorted_matrix(mat, len(mat), len(mat[0]), key) 32 | 33 | 34 | if __name__ == '__main__': 35 | main() 36 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/matrix/sum_sub_squares.py: -------------------------------------------------------------------------------- 1 | # Function to find sum of all 2 | # sub-squares of size k x k in a given 3 | # square matrix of size n x n 4 | def sum_sub_squares(matrix, k): 5 | n = len(matrix) 6 | result = [[0 for i in range(k)] for j in range(k)] 7 | 8 | if k > n: 9 | return 10 | for i in range(n - k + 1): 11 | l = 0 12 | for j in range(n - k + 1): 13 | sum = 0 14 | 15 | # Calculate and print sum of current sub-square 16 | for p in range(i, k + i): 17 | for q in range(j, k + j): 18 | sum += matrix[p][q] 19 | 20 | result[i][l] = sum 21 | l += 1 22 | 23 | return result 24 | 25 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/ml/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: __init__.py 8 | @time: 2024/3/28 15:21 9 | """ 10 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/ml/nearest_neighbor.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def distance(x,y): 4 | """[summary] 5 | HELPER-FUNCTION 6 | calculates the (eulidean) distance between vector x and y. 7 | 8 | Arguments: 9 | x {[tuple]} -- [vector] 10 | y {[tuple]} -- [vector] 11 | """ 12 | assert len(x) == len(y), "The vector must have same length" 13 | result = () 14 | sum = 0 15 | for i in range(len(x)): 16 | result += (x[i] -y[i],) 17 | for component in result: 18 | sum += component**2 19 | return math.sqrt(sum) 20 | 21 | 22 | def nearest_neighbor(x, tSet): 23 | """[summary] 24 | Implements the nearest neighbor algorithm 25 | 26 | Arguments: 27 | x {[tupel]} -- [vector] 28 | tSet {[dict]} -- [training set] 29 | 30 | Returns: 31 | [type] -- [result of the AND-function] 32 | """ 33 | assert isinstance(x, tuple) and isinstance(tSet, dict) 34 | current_key = () 35 | min_d = float('inf') 36 | for key in tSet: 37 | d = distance(x, key) 38 | if d < min_d: 39 | min_d = d 40 | current_key = key 41 | return tSet[current_key] 42 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/queues/__init__.py: -------------------------------------------------------------------------------- 1 | from .queue import * 2 | from .max_sliding_window import * 3 | from .reconstruct_queue import * 4 | from .priority_queue import * 5 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/queues/max_sliding_window.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array and a number k 3 | Find the max elements of each of its sub-arrays of length k. 4 | 5 | Keep indexes of good candidates in deque d. 6 | The indexes in d are from the current window, they're increasing, 7 | and their corresponding nums are decreasing. 8 | Then the first deque element is the index of the largest window value. 9 | 10 | For each index i: 11 | 12 | 1. Pop (from the end) indexes of smaller elements (they'll be useless). 13 | 2. Append the current index. 14 | 3. Pop (from the front) the index i - k, if it's still in the deque 15 | (it falls out of the window). 16 | 4. If our window has reached size k, 17 | append the current window maximum to the output. 18 | """ 19 | 20 | import collections 21 | def max_sliding_window(arr, k): 22 | qi = collections.deque() # queue storing indexes of elements 23 | result = [] 24 | for i, n in enumerate(arr): 25 | while qi and arr[qi[-1]] < n: 26 | qi.pop() 27 | qi.append(i) 28 | if qi[0] == i - k: 29 | qi.popleft() 30 | if i >= k - 1: 31 | result.append(arr[qi[0]]) 32 | return result 33 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/queues/moving_average.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | from collections import deque 3 | 4 | 5 | class MovingAverage(object): 6 | def __init__(self, size): 7 | """ 8 | Initialize your data structure here. 9 | :type size: int 10 | """ 11 | self.queue = deque(maxlen=size) 12 | 13 | def next(self, val): 14 | """ 15 | :type val: int 16 | :rtype: float 17 | """ 18 | self.queue.append(val) 19 | return sum(self.queue) / len(self.queue) 20 | 21 | 22 | # Given a stream of integers and a window size, 23 | # calculate the moving average of all integers in the sliding window. 24 | if __name__ == '__main__': 25 | m = MovingAverage(3) 26 | assert m.next(1) == 1 27 | assert m.next(10) == (1 + 10) / 2 28 | assert m.next(3) == (1 + 10 + 3) / 3 29 | assert m.next(5) == (10 + 3 + 5) / 3 30 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/queues/reconstruct_queue.py: -------------------------------------------------------------------------------- 1 | # Suppose you have a random list of people standing in a queue. 2 | # Each person is described by a pair of integers (h, k), 3 | # where h is the height of the person and k is the number of people 4 | # in front of this person who have a height greater than or equal to h. 5 | # Write an algorithm to reconstruct the queue. 6 | 7 | # Note: 8 | # The number of people is less than 1,100. 9 | 10 | # Example 11 | 12 | # Input: 13 | # [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]] 14 | 15 | # Output: 16 | # [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]] 17 | 18 | def reconstruct_queue(people): 19 | """ 20 | :type people: List[List[int]] 21 | :rtype: List[List[int]] 22 | """ 23 | queue = [] 24 | people.sort(key=lambda x: (-x[0], x[1])) 25 | for h, k in people: 26 | queue.insert(k, [h, k]) 27 | return queue 28 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/queues/zigzagiterator.py: -------------------------------------------------------------------------------- 1 | class ZigZagIterator: 2 | def __init__(self, v1, v2): 3 | """ 4 | Initialize your data structure here. 5 | :type v1: List[int] 6 | :type v2: List[int] 7 | """ 8 | self.queue=[_ for _ in (v1,v2) if _] 9 | print(self.queue) 10 | 11 | def next(self): 12 | """ 13 | :rtype: int 14 | """ 15 | v=self.queue.pop(0) 16 | ret=v.pop(0) 17 | if v: self.queue.append(v) 18 | return ret 19 | 20 | def has_next(self): 21 | """ 22 | :rtype: bool 23 | """ 24 | if self.queue: return True 25 | return False 26 | 27 | l1 = [1, 2] 28 | l2 = [3, 4, 5, 6] 29 | it = ZigZagIterator(l1, l2) 30 | while it.has_next(): 31 | print(it.next()) 32 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/search/__init__.py: -------------------------------------------------------------------------------- 1 | from .binary_search import * 2 | from .ternary_search import * 3 | from .first_occurrence import * 4 | from .last_occurrence import * 5 | from .linear_search import * 6 | from .search_insert import * 7 | from .two_sum import * 8 | from .search_range import * 9 | from .find_min_rotate import * 10 | from .search_rotate import * 11 | from .jump_search import * 12 | from .next_greatest_letter import * 13 | from .interpolation_search import * 14 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/search/find_max_substring.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | @author: jayzhen 6 | @email: jayzhen_testing@163.com 7 | @site: https://github.com/gitjayzhen 8 | @software: PyCharm & Python 3.7 9 | @file: find_max_substring 10 | @time: 4/23/21 10:26 AM 11 | """ 12 | 13 | 14 | def find_longest_no_repeat_substr(one_str): 15 | ''' 16 | 找出来一个字符串中最长不重复子串 17 | :param one_str: 18 | :return: 19 | ''' 20 | res_list = [] 21 | length = len(one_str) 22 | for i in range(length): 23 | tmp = one_str[i] 24 | for j in range(i+1, length): 25 | if one_str[j] not in tmp: 26 | tmp += one_str[j] 27 | else: 28 | break 29 | res_list.append(tmp) 30 | res_list.sort(lambda x,y: cmp(len(x),len(y))) 31 | return res_list[-1] 32 | 33 | 34 | if __name__ == '__main__': 35 | str_list = ['120135435', 'abdfkjkgdok', '123456780423349'] 36 | for one_str in str_list: 37 | res = find_longest_no_repeat_substr(one_str) 38 | print('{0}最长非重复子串为:{1}'.format(one_str, res)) 39 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/search/find_min_rotate.py: -------------------------------------------------------------------------------- 1 | """ 2 | Suppose an array sorted in ascending order is rotated at some pivot unknown 3 | to you beforehand. (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). 4 | 5 | Find the minimum element. The complexity must be O(logN) 6 | 7 | You may assume no duplicate exists in the array. 8 | """ 9 | def find_min_rotate(array): 10 | low = 0 11 | high = len(array) - 1 12 | while low < high: 13 | mid = (low + high) // 2 14 | if array[mid] > array[high]: 15 | low = mid + 1 16 | else: 17 | high = mid 18 | 19 | return array[low] 20 | 21 | def find_min_rotate_recur(array, low, high): 22 | mid = (low + high) // 2 23 | if mid == low: 24 | return array[low] 25 | elif array[mid] > array[high]: 26 | return find_min_rotate_recur(array, mid + 1, high) 27 | else: 28 | return find_min_rotate_recur(array, low, mid) 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/search/first_occurrence.py: -------------------------------------------------------------------------------- 1 | # 2 | # Find first occurance of a number in a sorted array (increasing order) 3 | # Approach- Binary Search 4 | # T(n)- O(log n) 5 | # 6 | def first_occurrence(array, query): 7 | lo, hi = 0, len(array) - 1 8 | while lo <= hi: 9 | mid = (lo + hi) // 2 10 | #print("lo: ", lo, " hi: ", hi, " mid: ", mid) 11 | if lo == hi: 12 | break 13 | if array[mid] < query: 14 | lo = mid + 1 15 | else: 16 | hi = mid 17 | if array[lo] == query: 18 | return lo 19 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/search/last_occurrence.py: -------------------------------------------------------------------------------- 1 | # 2 | # Find last occurance of a number in a sorted array (increasing order) 3 | # Approach- Binary Search 4 | # T(n)- O(log n) 5 | # 6 | def last_occurrence(array, query): 7 | lo, hi = 0, len(array) - 1 8 | while lo <= hi: 9 | mid = (hi + lo) // 2 10 | if (array[mid] == query and mid == len(array)-1) or \ 11 | (array[mid] == query and array[mid+1] > query): 12 | return mid 13 | elif (array[mid] <= query): 14 | lo = mid + 1 15 | else: 16 | hi = mid - 1 17 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/search/linear_search.py: -------------------------------------------------------------------------------- 1 | # 2 | # Linear search works in any array. 3 | # 4 | # T(n): O(n) 5 | # 6 | 7 | def linear_search(array, query): 8 | for i in range(len(array)): 9 | if array[i] == query: 10 | return i 11 | 12 | return -1 13 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/search/search_insert.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a sorted array and a target value, return the index if the target is 3 | found. If not, return the index where it would be if it were inserted in order. 4 | 5 | For example: 6 | [1,3,5,6], 5 -> 2 7 | [1,3,5,6], 2 -> 1 8 | [1,3,5,6], 7 -> 4 9 | [1,3,5,6], 0 -> 0 10 | """ 11 | def search_insert(array, val): 12 | low = 0 13 | high = len(array) - 1 14 | while low <= high: 15 | mid = low + (high - low) // 2 16 | if val > array[mid]: 17 | low = mid + 1 18 | else: 19 | high = mid - 1 20 | return low 21 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/search/search_range.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of integers nums sorted in ascending order, find the starting 3 | and ending position of a given target value. If the target is not found in the 4 | array, return [-1, -1]. 5 | 6 | For example: 7 | Input: nums = [5,7,7,8,8,8,10], target = 8 8 | Output: [3,5] 9 | Input: nums = [5,7,7,8,8,8,10], target = 11 10 | Output: [-1,-1] 11 | """ 12 | def search_range(nums, target): 13 | """ 14 | :type nums: List[int] 15 | :type target: int 16 | :rtype: List[int] 17 | """ 18 | low = 0 19 | high = len(nums) - 1 20 | while low <= high: 21 | mid = low + (high - low) // 2 22 | if target < nums[mid]: 23 | high = mid - 1 24 | elif target > nums[mid]: 25 | low = mid + 1 26 | else: 27 | break 28 | 29 | for j in range(len(nums) - 1, -1, -1): 30 | if nums[j] == target: 31 | return [mid, j] 32 | 33 | return [-1, -1] 34 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/set/__init__.py: -------------------------------------------------------------------------------- 1 | from .find_keyboard_row import * 2 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/set/find_keyboard_row.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a List of words, return the words that can be typed using letters of 3 | alphabet on only one row's of American keyboard. 4 | 5 | For example: 6 | Input: ["Hello", "Alaska", "Dad", "Peace"] 7 | Output: ["Alaska", "Dad"] 8 | 9 | Reference: https://leetcode.com/problems/keyboard-row/description/ 10 | """ 11 | def find_keyboard_row(words): 12 | """ 13 | :type words: List[str] 14 | :rtype: List[str] 15 | """ 16 | keyboard = [ 17 | set('qwertyuiop'), 18 | set('asdfghjkl'), 19 | set('zxcvbnm'), 20 | ] 21 | result = [] 22 | for word in words: 23 | for key in keyboard: 24 | if set(word.lower()).issubset(key): 25 | result.append(word) 26 | return result 27 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/__init__.py: -------------------------------------------------------------------------------- 1 | from .bitonic_sort import * 2 | from .bogo_sort import * 3 | from .bubble_sort import * 4 | from .comb_sort import * 5 | from .counting_sort import * 6 | from .cycle_sort import * 7 | from .heap_sort import * 8 | from .insertion_sort import * 9 | from .merge_sort import * 10 | from .pancake_sort import * 11 | from .pigeonhole_sort import * 12 | from .quick_sort import * 13 | from .selection_sort import * 14 | from .top_sort import * 15 | from .bucket_sort import * 16 | from .shell_sort import * 17 | from .stooge_sort import * 18 | from .radix_sort import * 19 | from .gnome_sort import * 20 | from .cocktail_shaker_sort import * 21 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/bogo_sort.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def bogo_sort(arr, simulation=False): 4 | """Bogo Sort 5 | Best Case Complexity: O(n) 6 | Worst Case Complexity: O(∞) 7 | Average Case Complexity: O(n(n-1)!) 8 | """ 9 | 10 | iteration = 0 11 | if simulation: 12 | print("iteration",iteration,":",*arr) 13 | 14 | def is_sorted(arr): 15 | #check the array is inorder 16 | i = 0 17 | arr_len = len(arr) 18 | while i+1 < arr_len: 19 | if arr[i] > arr[i+1]: 20 | return False 21 | i += 1 22 | 23 | 24 | return True 25 | while not is_sorted(arr): 26 | random.shuffle(arr) 27 | 28 | if simulation: 29 | iteration = iteration + 1 30 | print("iteration",iteration,":",*arr) 31 | 32 | return arr 33 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/bubble_sort.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | https://en.wikipedia.org/wiki/Bubble_sort 4 | 5 | Worst-case performance: O(N^2) 6 | 7 | If you call bubble_sort(arr,True), you can see the process of the sort 8 | Default is simulation = False 9 | 10 | """ 11 | 12 | 13 | def bubble_sort(arr, simulation=False): 14 | def swap(i, j): 15 | arr[i], arr[j] = arr[j], arr[i] 16 | 17 | n = len(arr) 18 | swapped = True 19 | 20 | iteration = 0 21 | if simulation: 22 | print("iteration",iteration,":",*arr) 23 | x = -1 24 | while swapped: 25 | swapped = False 26 | x = x + 1 27 | for i in range(1, n-x): 28 | if arr[i - 1] > arr[i]: 29 | swap(i - 1, i) 30 | swapped = True 31 | if simulation: 32 | iteration = iteration + 1 33 | print("iteration",iteration,":",*arr) 34 | 35 | return arr 36 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/bucket_sort.py: -------------------------------------------------------------------------------- 1 | def bucket_sort(arr): 2 | ''' Bucket Sort 3 | Complexity: O(n^2) 4 | The complexity is dominated by nextSort 5 | ''' 6 | # The number of buckets and make buckets 7 | num_buckets = len(arr) 8 | buckets = [[] for bucket in range(num_buckets)] 9 | # Assign values into bucket_sort 10 | for value in arr: 11 | index = value * num_buckets // (max(arr) + 1) 12 | buckets[index].append(value) 13 | # Sort 14 | sorted_list = [] 15 | for i in range(num_buckets): 16 | sorted_list.extend(next_sort(buckets[i])) 17 | return sorted_list 18 | 19 | def next_sort(arr): 20 | # We will use insertion sort here. 21 | for i in range(1, len(arr)): 22 | j = i - 1 23 | key = arr[i] 24 | while arr[j] > key and j >= 0: 25 | arr[j+1] = arr[j] 26 | j = j - 1 27 | arr[j + 1] = key 28 | return arr 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/cocktail_shaker_sort.py: -------------------------------------------------------------------------------- 1 | def cocktail_shaker_sort(arr): 2 | """ 3 | Cocktail_shaker_sort 4 | Sorting a given array 5 | mutation of bubble sort 6 | 7 | reference: https://en.wikipedia.org/wiki/Cocktail_shaker_sort 8 | 9 | Worst-case performance: O(N^2) 10 | """ 11 | 12 | def swap(i, j): 13 | arr[i], arr[j] = arr[j], arr[i] 14 | 15 | n = len(arr) 16 | swapped = True 17 | while swapped: 18 | swapped = False 19 | for i in range(1, n): 20 | if arr[i - 1] > arr[i]: 21 | swap(i - 1, i) 22 | swapped = True 23 | if swapped == False: 24 | return arr 25 | swapped = False 26 | for i in range(n-1,0,-1): 27 | if arr[i - 1] > arr[i]: 28 | swap(i - 1, i) 29 | swapped = True 30 | return arr 31 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/comb_sort.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | https://en.wikipedia.org/wiki/Comb_sort 4 | 5 | Worst-case performance: O(N^2) 6 | 7 | """ 8 | 9 | 10 | def comb_sort(arr): 11 | def swap(i, j): 12 | arr[i], arr[j] = arr[j], arr[i] 13 | 14 | n = len(arr) 15 | gap = n 16 | shrink = 1.3 17 | sorted = False 18 | while not sorted: 19 | gap = int(gap / shrink) 20 | if gap > 1: 21 | sorted = False 22 | else: 23 | gap = 1 24 | sorted = True 25 | 26 | i = 0 27 | while i + gap < n: 28 | if arr[i] > arr[i + gap]: 29 | swap(i, i + gap) 30 | sorted = False 31 | i = i + 1 32 | return arr 33 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/gnome_sort.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Gnome Sort 4 | Best case performance is O(n) 5 | Worst case performance is O(n^2) 6 | 7 | """ 8 | 9 | 10 | def gnome_sort(arr): 11 | n = len(arr) 12 | index = 0 13 | while index < n: 14 | if index == 0 or arr[index] >= arr[index-1]: 15 | index = index + 1 16 | else: 17 | arr[index], arr[index-1] = arr[index-1], arr[index] 18 | index = index - 1 19 | return arr 20 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/insertion_sort.py: -------------------------------------------------------------------------------- 1 | def insertion_sort(arr, simulation=False): 2 | """ Insertion Sort 3 | Complexity: O(n^2) 4 | """ 5 | 6 | iteration = 0 7 | if simulation: 8 | print("iteration",iteration,":",*arr) 9 | 10 | for i in range(len(arr)): 11 | cursor = arr[i] 12 | pos = i 13 | 14 | while pos > 0 and arr[pos - 1] > cursor: 15 | # Swap the number down the list 16 | arr[pos] = arr[pos - 1] 17 | pos = pos - 1 18 | # Break and do the final swap 19 | arr[pos] = cursor 20 | 21 | if simulation: 22 | iteration = iteration + 1 23 | print("iteration",iteration,":",*arr) 24 | 25 | return arr 26 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/meeting_rooms.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of meeting time intervals consisting of 3 | start and end times [[s1,e1],[s2,e2],...] (si < ei), 4 | determine if a person could attend all meetings. 5 | 6 | For example, 7 | Given [[0, 30],[5, 10],[15, 20]], 8 | return false. 9 | """ 10 | 11 | 12 | def can_attend_meetings(intervals): 13 | """ 14 | :type intervals: List[Interval] 15 | :rtype: bool 16 | """ 17 | intervals = sorted(intervals, key=lambda x: x.start) 18 | for i in range(1, len(intervals)): 19 | if intervals[i].start < intervals[i - 1].end: 20 | return False 21 | return True 22 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/pancake_sort.py: -------------------------------------------------------------------------------- 1 | def pancake_sort(arr): 2 | """ 3 | Pancake_sort 4 | Sorting a given array 5 | mutation of selection sort 6 | 7 | reference: https://www.geeksforgeeks.org/pancake-sorting/ 8 | 9 | Overall time complexity : O(N^2) 10 | """ 11 | 12 | len_arr = len(arr) 13 | if len_arr <= 1: 14 | return arr 15 | for cur in range(len(arr), 1, -1): 16 | #Finding index of maximum number in arr 17 | index_max = arr.index(max(arr[0:cur])) 18 | if index_max+1 != cur: 19 | #Needs moving 20 | if index_max != 0: 21 | #reverse from 0 to index_max 22 | arr[:index_max+1] = reversed(arr[:index_max+1]) 23 | # Reverse list 24 | arr[:cur] = reversed(arr[:cur]) 25 | return arr 26 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/pigeonhole_sort.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | https://en.wikipedia.org/wiki/Pigeonhole_sort 4 | 5 | Time complexity: O(n + Range) where n = number of elements and Range = possible values in the array 6 | 7 | Suitable for lists where the number of elements and key values are mostly the same. 8 | 9 | """ 10 | 11 | 12 | def pigeonhole_sort(arr): 13 | Max = max(arr) 14 | Min = min(arr) 15 | size = Max - Min + 1 16 | 17 | holes = [0]*size 18 | 19 | for i in arr: 20 | holes[i-Min] += 1 21 | 22 | i = 0 23 | for count in range(size): 24 | while holes[count] > 0: 25 | holes[count] -= 1 26 | arr[i] = count + Min 27 | i += 1 28 | return arr 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/radix_sort.py: -------------------------------------------------------------------------------- 1 | """ 2 | radix sort 3 | complexity: O(nk + n) . n is the size of input list and k is the digit length of the number 4 | """ 5 | def radix_sort(arr, simulation=False): 6 | position = 1 7 | max_number = max(arr) 8 | 9 | iteration = 0 10 | if simulation: 11 | print("iteration", iteration, ":", *arr) 12 | 13 | while position <= max_number: 14 | queue_list = [list() for _ in range(10)] 15 | 16 | for num in arr: 17 | digit_number = num // position % 10 18 | queue_list[digit_number].append(num) 19 | 20 | index = 0 21 | for numbers in queue_list: 22 | for num in numbers: 23 | arr[index] = num 24 | index += 1 25 | 26 | if simulation: 27 | iteration = iteration + 1 28 | print("iteration", iteration, ":", *arr) 29 | 30 | position *= 10 31 | return arr 32 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/selection_sort.py: -------------------------------------------------------------------------------- 1 | def selection_sort(arr, simulation=False): 2 | """ Selection Sort 3 | Complexity: O(n^2) 4 | """ 5 | iteration = 0 6 | if simulation: 7 | print("iteration",iteration,":",*arr) 8 | 9 | for i in range(len(arr)): 10 | minimum = i 11 | 12 | for j in range(i + 1, len(arr)): 13 | # "Select" the correct value 14 | if arr[j] < arr[minimum]: 15 | minimum = j 16 | 17 | arr[minimum], arr[i] = arr[i], arr[minimum] 18 | 19 | if simulation: 20 | iteration = iteration + 1 21 | print("iteration",iteration,":",*arr) 22 | 23 | return arr 24 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/shell_sort.py: -------------------------------------------------------------------------------- 1 | def shell_sort(arr): 2 | ''' Shell Sort 3 | Complexity: O(n^2) 4 | ''' 5 | n = len(arr) 6 | # Initialize size of the gap 7 | gap = n//2 8 | 9 | while gap > 0: 10 | y_index = gap 11 | while y_index < len(arr): 12 | y = arr[y_index] 13 | x_index = y_index - gap 14 | while x_index >= 0 and y < arr[x_index]: 15 | arr[x_index + gap] = arr[x_index] 16 | x_index = x_index - gap 17 | arr[x_index + gap] = y 18 | y_index = y_index + 1 19 | gap = gap//2 20 | 21 | return arr 22 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/sort_colors.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array with n objects colored red, 3 | white or blue, sort them so that objects of the same color 4 | are adjacent, with the colors in the order red, white and blue. 5 | 6 | Here, we will use the integers 0, 1, and 2 to represent 7 | the color red, white, and blue respectively. 8 | 9 | Note: 10 | You are not suppose to use the library's sort function for this problem. 11 | """ 12 | 13 | 14 | def sort_colors(nums): 15 | i = j = 0 16 | for k in range(len(nums)): 17 | v = nums[k] 18 | nums[k] = 2 19 | if v < 2: 20 | nums[j] = 1 21 | j += 1 22 | if v == 0: 23 | nums[i] = 0 24 | i += 1 25 | 26 | 27 | if __name__ == "__main__": 28 | nums = [0, 1, 1, 1, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 2, 2] 29 | sort_colors(nums) 30 | print(nums) 31 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/stooge_sort.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 3 | Stooge Sort 4 | Time Complexity : O(n2.709) 5 | Reference: https://www.geeksforgeeks.org/stooge-sort/ 6 | 7 | ''' 8 | 9 | 10 | 11 | def stoogesort(arr, l, h): 12 | if l >= h: 13 | return 14 | 15 | # If first element is smaller 16 | # than last, swap them 17 | if arr[l]>arr[h]: 18 | t = arr[l] 19 | arr[l] = arr[h] 20 | arr[h] = t 21 | 22 | # If there are more than 2 elements in 23 | # the array 24 | if h-l + 1 > 2: 25 | t = (int)((h-l + 1)/3) 26 | 27 | # Recursively sort first 2 / 3 elements 28 | stoogesort(arr, l, (h-t)) 29 | 30 | # Recursively sort last 2 / 3 elements 31 | stoogesort(arr, l + t, (h)) 32 | 33 | # Recursively sort first 2 / 3 elements 34 | # again to confirm 35 | stoogesort(arr, l, (h-t)) 36 | 37 | 38 | if __name__ == "__main__": 39 | array = [1,3,64,5,7,8] 40 | n = len(array) 41 | stoogesort(array, 0, n-1) 42 | for i in range(0, n): 43 | print(array[i], end = ' ') 44 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/sort/wiggle_sort.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an unsorted array nums, reorder it such that nums[0] < nums[1] > nums[2] < nums[3].... 3 | """ 4 | def wiggle_sort(nums): 5 | for i in range(len(nums)): 6 | if (i % 2 == 1) == (nums[i-1] > nums[i]): 7 | nums[i-1], nums[i] = nums[i], nums[i-1] 8 | 9 | if __name__ == "__main__": 10 | array = [3, 5, 2, 1, 6, 4] 11 | 12 | print(array) 13 | wiggle_sort(array) 14 | print(array) 15 | 16 | 17 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/stack/__init__.py: -------------------------------------------------------------------------------- 1 | from .stack import * 2 | from .is_consecutive import * 3 | from .is_sorted import * 4 | from .remove_min import * 5 | from .stutter import * 6 | from .switch_pairs import * 7 | from .valid_parenthesis import * 8 | from .simplify_path import * 9 | from .stack import * 10 | from .ordered_stack import * 11 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/stack/is_sorted.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a stack, a function is_sorted accepts a stack as a parameter and returns 3 | true if the elements in the stack occur in ascending increasing order from 4 | bottom, and false otherwise. That is, the smallest element should be at bottom 5 | 6 | For example: 7 | bottom [6, 3, 5, 1, 2, 4] top 8 | The function should return false 9 | bottom [1, 2, 3, 4, 5, 6] top 10 | The function should return true 11 | """ 12 | def is_sorted(stack): 13 | storage_stack = [] 14 | for i in range(len(stack)): 15 | if len(stack) == 0: 16 | break 17 | first_val = stack.pop() 18 | if len(stack) == 0: 19 | break 20 | second_val = stack.pop() 21 | if first_val < second_val: 22 | return False 23 | storage_stack.append(first_val) 24 | stack.append(second_val) 25 | 26 | # Backup stack 27 | for i in range(len(storage_stack)): 28 | stack.append(storage_stack.pop()) 29 | 30 | return True 31 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/stack/ordered_stack.py: -------------------------------------------------------------------------------- 1 | #The stack remains always ordered such that the highest value is at the top and the lowest at the bottom 2 | 3 | class OrderedStack: 4 | def __init__(self): 5 | self.items = [] 6 | 7 | def is_empty(self): 8 | return self.items == [] 9 | 10 | def push_t(self, item): 11 | self.items.append(item) 12 | 13 | def push(self, item): #push method to maintain order when pushing new elements 14 | temp_stack = OrderedStack() 15 | if self.is_empty() or item > self.peek(): 16 | self.push_t(item) 17 | else: 18 | while item < self.peek() and not self.is_empty(): 19 | temp_stack.push_t(self.pop()) 20 | self.push_t(item) 21 | while not temp_stack.is_empty(): 22 | self.push_t(temp_stack.pop()) 23 | 24 | def pop(self): 25 | if self.is_empty(): 26 | raise IndexError("Stack is empty") 27 | return self.items.pop() 28 | 29 | def peek(self): 30 | return self.items[len(self.items) - 1] 31 | 32 | def size(self): 33 | return len(self.items) 34 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/stack/remove_min.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a stack, a function remove_min accepts a stack as a parameter 3 | and removes the smallest value from the stack. 4 | 5 | For example: 6 | bottom [2, 8, 3, -6, 7, 3] top 7 | After remove_min(stack): 8 | bottom [2, 8, 3, 7, 3] top 9 | 10 | """ 11 | def remove_min(stack): 12 | storage_stack = [] 13 | if len(stack) == 0: # Stack is empty 14 | return stack 15 | # Find the smallest value 16 | min = stack.pop() 17 | stack.append(min) 18 | for i in range(len(stack)): 19 | val = stack.pop() 20 | if val <= min: 21 | min = val 22 | storage_stack.append(val) 23 | # Back up stack and remove min value 24 | for i in range(len(storage_stack)): 25 | val = storage_stack.pop() 26 | if val != min: 27 | stack.append(val) 28 | return stack 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/stack/simplify_path.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an absolute path for a file (Unix-style), simplify it. 3 | 4 | For example, 5 | path = "/home/", => "/home" 6 | path = "/a/./b/../../c/", => "/c" 7 | 8 | * Did you consider the case where path = "/../"? 9 | In this case, you should return "/". 10 | * Another corner case is the path might contain multiple slashes '/' together, such as "/home//foo/". 11 | In this case, you should ignore redundant slashes and return "/home/foo". 12 | """ 13 | def simplify_path(path): 14 | """ 15 | :type path: str 16 | :rtype: str 17 | """ 18 | skip = {'..', '.', ''} 19 | stack = [] 20 | paths = path.split('/') 21 | for tok in paths: 22 | if tok == '..': 23 | if stack: 24 | stack.pop() 25 | elif tok not in skip: 26 | stack.append(tok) 27 | return '/' + '/'.join(stack) 28 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/stack/valid_parenthesis.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a string containing just the characters 3 | '(', ')', '{', '}', '[' and ']', 4 | determine if the input string is valid. 5 | 6 | The brackets must close in the correct order, 7 | "()" and "()[]{}" are all valid but "(]" and "([)]" are not. 8 | """ 9 | def is_valid(s: str) -> bool: 10 | stack = [] 11 | dic = {")": "(", 12 | "}": "{", 13 | "]": "["} 14 | for char in s: 15 | if char in dic.values(): 16 | stack.append(char) 17 | elif char in dic: 18 | if not stack or dic[char] != stack.pop(): 19 | return False 20 | return not stack 21 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/streaming/__init__.py: -------------------------------------------------------------------------------- 1 | from .one_sparse_recovery import * 2 | from .misra_gries import * 3 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/add_binary.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two binary strings, 3 | return their sum (also a binary string). 4 | 5 | For example, 6 | a = "11" 7 | b = "1" 8 | Return "100". 9 | """ 10 | 11 | 12 | def add_binary(a, b): 13 | s = "" 14 | c, i, j = 0, len(a)-1, len(b)-1 15 | zero = ord('0') 16 | while (i >= 0 or j >= 0 or c == 1): 17 | if (i >= 0): 18 | c += ord(a[i]) - zero 19 | i -= 1 20 | if (j >= 0): 21 | c += ord(b[j]) - zero 22 | j -= 1 23 | s = chr(c % 2 + zero) + s 24 | c //= 2 25 | 26 | return s 27 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/atbash_cipher.py: -------------------------------------------------------------------------------- 1 | """ 2 | Atbash cipher is mapping the alphabet to it's reverse. 3 | So if we take "a" as it is the first letter, we change it to the last - z. 4 | 5 | Example: 6 | Attack at dawn --> Zggzxp zg wzdm 7 | 8 | Complexity: O(n) 9 | """ 10 | 11 | def atbash(s): 12 | translated = "" 13 | for i in range(len(s)): 14 | n = ord(s[i]) 15 | 16 | if s[i].isalpha(): 17 | 18 | if s[i].isupper(): 19 | x = n - ord('A') 20 | translated += chr(ord('Z') - x) 21 | 22 | if s[i].islower(): 23 | x = n - ord('a') 24 | translated += chr(ord('z') - x) 25 | else: 26 | translated += s[i] 27 | return translated -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/caesar_cipher.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Julius Caesar protected his confidential information by encrypting it using a cipher. 4 | Caesar's cipher shifts each letter by a number of letters. If the shift takes you 5 | past the end of the alphabet, just rotate back to the front of the alphabet. 6 | In the case of a rotation by 3, w, x, y and z would map to z, a, b and c. 7 | Original alphabet: abcdefghijklmnopqrstuvwxyz 8 | Alphabet rotated +3: defghijklmnopqrstuvwxyzabc 9 | """ 10 | def caesar_cipher(s, k): 11 | result = "" 12 | for char in s: 13 | n = ord(char) 14 | if 64 < n < 91: 15 | n = ((n - 65 + k) % 26) + 65 16 | if 96 < n < 123: 17 | n = ((n - 97 + k) % 26) + 97 18 | result = result + chr(n) 19 | return result 20 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/check_pangram.py: -------------------------------------------------------------------------------- 1 | """ 2 | Algorithm that checks if a given string is a pangram or not 3 | """ 4 | 5 | def check_pangram(input_string): 6 | alphabet = "abcdefghijklmnopqrstuvwxyz" 7 | for ch in alphabet: 8 | if ch not in input_string.lower(): 9 | return False 10 | return True -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/contain_string.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implement strStr(). 3 | 4 | Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack. 5 | 6 | Example 1: 7 | Input: haystack = "hello", needle = "ll" 8 | Output: 2 9 | 10 | Example 2: 11 | Input: haystack = "aaaaa", needle = "bba" 12 | Output: -1 13 | Reference: https://leetcode.com/problems/implement-strstr/description/ 14 | """ 15 | def contain_string(haystack, needle): 16 | if len(needle) == 0: 17 | return 0 18 | if len(needle) > len(haystack): 19 | return -1 20 | for i in range(len(haystack)): 21 | if len(haystack) - i < len(needle): 22 | return -1 23 | if haystack[i:i+len(needle)] == needle: 24 | return i 25 | return -1 26 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/delete_reoccurring.py: -------------------------------------------------------------------------------- 1 | """ 2 | QUESTION: Given a string as your input, delete any reoccurring 3 | character, and return the new string. 4 | 5 | This is a Google warmup interview question that was asked duirng phone screening 6 | at my university. 7 | """ 8 | 9 | # time complexity O(n) 10 | def delete_reoccurring_characters(string): 11 | seen_characters = set() 12 | output_string = '' 13 | for char in string: 14 | if char not in seen_characters: 15 | seen_characters.add(char) 16 | output_string += char 17 | return output_string 18 | 19 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/domain_extractor.py: -------------------------------------------------------------------------------- 1 | """ 2 | Write a function that when given a URL as a string, parses out just the domain name and returns it as a string. 3 | 4 | Examples: 5 | domain_name("http://github.com/SaadBenn") == "github" 6 | domain_name("http://www.zombie-bites.com") == "zombie-bites" 7 | domain_name("https://www.cnet.com") == "cnet" 8 | 9 | Note: The idea is not to use any built-in libraries such as re (regular expression) or urlparse except .split() built-in function 10 | """ 11 | 12 | # Non pythonic way 13 | def domain_name_1(url): 14 | #grab only the non http(s) part 15 | full_domain_name = url.split('//')[-1] 16 | #grab the actual one depending on the len of the list 17 | actual_domain = full_domain_name.split('.') 18 | 19 | # case when www is in the url 20 | if (len(actual_domain) > 2): 21 | return actual_domain[1] 22 | # case when www is not in the url 23 | return actual_domain[0] 24 | 25 | 26 | # pythonic one liner 27 | def domain_name_2(url): 28 | return url.split("//")[-1].split("www.")[-1].split(".")[0] 29 | 30 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/encode_decode.py: -------------------------------------------------------------------------------- 1 | """ Design an algorithm to encode a list of strings to a string. 2 | The encoded mystring is then sent over the network and is decoded 3 | back to the original list of strings. 4 | """ 5 | 6 | # Implement the encode and decode methods. 7 | 8 | def encode(strs): 9 | """Encodes a list of strings to a single string. 10 | :type strs: List[str] 11 | :rtype: str 12 | """ 13 | res = '' 14 | for string in strs.split(): 15 | res += str(len(string)) + ":" + string 16 | return res 17 | 18 | def decode(s): 19 | """Decodes a single string to a list of strings. 20 | :type s: str 21 | :rtype: List[str] 22 | """ 23 | strs = [] 24 | i = 0 25 | while i < len(s): 26 | index = s.find(":", i) 27 | size = int(s[i:index]) 28 | strs.append(s[index+1: index+1+size]) 29 | i = index+1+size 30 | return strs -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/first_unique_char.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a string, find the first non-repeating character in it and return it's 3 | index. If it doesn't exist, return -1. 4 | 5 | For example: 6 | s = "leetcode" 7 | return 0. 8 | 9 | s = "loveleetcode", 10 | return 2. 11 | 12 | Reference: https://leetcode.com/problems/first-unique-character-in-a-string/description/ 13 | """ 14 | def first_unique_char(s): 15 | """ 16 | :type s: str 17 | :rtype: int 18 | """ 19 | if (len(s) == 1): 20 | return 0 21 | ban = [] 22 | for i in range(len(s)): 23 | if all(s[i] != s[k] for k in range(i + 1, len(s))) == True and s[i] not in ban: 24 | return i 25 | else: 26 | ban.append(s[i]) 27 | return -1 28 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/group_anagrams.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of strings, group anagrams together. 3 | 4 | For example, given: ["eat", "tea", "tan", "ate", "nat", "bat"], 5 | Return: 6 | 7 | [ 8 | ["ate", "eat","tea"], 9 | ["nat","tan"], 10 | ["bat"] 11 | ] 12 | """ 13 | 14 | 15 | def group_anagrams(strs): 16 | d = {} 17 | ans = [] 18 | k = 0 19 | for str in strs: 20 | sstr = ''.join(sorted(str)) 21 | if sstr not in d: 22 | d[sstr] = k 23 | k += 1 24 | ans.append([]) 25 | ans[-1].append(str) 26 | else: 27 | ans[d[sstr]].append(str) 28 | return ans 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/int_to_roman.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer, convert it to a roman numeral. 3 | Input is guaranteed to be within the range from 1 to 3999. 4 | """ 5 | 6 | def int_to_roman(num): 7 | """ 8 | :type num: int 9 | :rtype: str 10 | """ 11 | m = ["", "M", "MM", "MMM"]; 12 | c = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"]; 13 | x = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"]; 14 | i = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]; 15 | return m[num//1000] + c[(num%1000)//100] + x[(num%100)//10] + i[num%10]; 16 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/is_rotated.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two strings s1 and s2, determine if s2 is a rotated version of s1. 3 | For example, 4 | is_rotated("hello", "llohe") returns True 5 | is_rotated("hello", "helol") returns False 6 | 7 | accepts two strings 8 | returns bool 9 | Reference: https://leetcode.com/problems/rotate-string/description/ 10 | """ 11 | 12 | def is_rotated(s1, s2): 13 | if len(s1) == len(s2): 14 | return s2 in s1 + s1 15 | else: 16 | return False 17 | 18 | """ 19 | Another solution: brutal force 20 | Complexity: O(N^2) 21 | """ 22 | def is_rotated_v1(s1, s2): 23 | if len(s1) != len(s2): 24 | return False 25 | if len(s1) == 0: 26 | return True 27 | 28 | for c in range(len(s1)): 29 | if all(s1[(c + i) % len(s1)] == s2[i] for i in range(len(s1))): 30 | return True 31 | return False 32 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/judge_circle.py: -------------------------------------------------------------------------------- 1 | """ 2 | Initially, there is a Robot at position (0, 0). Given a sequence of its moves, 3 | judge if this robot makes a circle, which means it moves back to the original place. 4 | 5 | The move sequence is represented by a string. And each move is represent by a 6 | character. The valid robot moves are R (Right), L (Left), U (Up) and D (down). 7 | The output should be true or false representing whether the robot makes a circle. 8 | 9 | Example 1: 10 | Input: "UD" 11 | Output: true 12 | Example 2: 13 | Input: "LL" 14 | Output: false 15 | """ 16 | def judge_circle(moves): 17 | dict_moves = { 18 | 'U' : 0, 19 | 'D' : 0, 20 | 'R' : 0, 21 | 'L' : 0 22 | } 23 | for char in moves: 24 | dict_moves[char] = dict_moves[char] + 1 25 | return dict_moves['L'] == dict_moves['R'] and dict_moves['U'] == dict_moves['D'] 26 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/knuth_morris_pratt.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two strings text and pattern, 3 | return the list of start indexes in text that matches with the pattern 4 | using knuth_morris_pratt algorithm. 5 | If idx is in the list, text[idx : idx + M] matches with pattern. 6 | Time complexity : O(N+M) 7 | N and M is the length of text and pattern, respectively. 8 | """ 9 | 10 | def knuth_morris_pratt(text, pattern): 11 | n = len(text) 12 | m = len(pattern) 13 | pi = [0 for i in range(m)] 14 | i = 0 15 | j = 0 16 | # making pi table 17 | for i in range(1, m): 18 | while j and pattern[i] != pattern[j]: 19 | j = pi[j - 1] 20 | if pattern[i] == pattern[j]: 21 | j += 1 22 | pi[i] = j 23 | # finding pattern 24 | j = 0 25 | ret = [] 26 | for i in range(n): 27 | while j and text[i] != pattern[j]: 28 | j = pi[j - 1] 29 | if text[i] == pattern[j]: 30 | j += 1 31 | if j == m: 32 | ret.append(i - m + 1) 33 | j = pi[j - 1] 34 | return ret 35 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/license_number.py: -------------------------------------------------------------------------------- 1 | 2 | def license_number(key, k): 3 | res, alnum = [], [] 4 | for char in key: 5 | if char != "-": 6 | alnum.append(char) 7 | for i, char in enumerate(reversed(alnum)): 8 | res.append(char) 9 | if (i+1) % k == 0 and i != len(alnum)-1: 10 | res.append("-") 11 | return "".join(res[::-1]) 12 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/longest_palindromic_substring.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Given string s, find the longest palindromic substring. 3 | 4 | Example1: 5 | 6 | * input: "dasdasdasdasdasdadsa" 7 | * output: "asdadsa" 8 | 9 | Example2: 10 | 11 | * input: "acdbbdaa" 12 | * output: "dbbd" 13 | 14 | Manacher's algorithm 15 | 16 | ''' 17 | 18 | def longest_palindrome(s): 19 | if len(s) < 2: 20 | return s 21 | 22 | n_str = '#' + '#'.join(s) + '#' 23 | p = [0] * len(n_str) 24 | mx, loc = 0, 0 25 | index, maxlen = 0, 0 26 | for i in range(len(n_str)): 27 | if i < mx and 2 * loc - i < len(n_str): 28 | p[i] = min(mx - i, p[2 * loc - i]) 29 | else: 30 | p[i] = 1 31 | 32 | while p[i] + i < len(n_str) and i - p[i] >= 0 and n_str[ 33 | i - p[i]] == n_str[i + p[i]]: 34 | p[i] += 1 35 | 36 | if i + p[i] > mx: 37 | mx = i + p[i] 38 | loc = i 39 | 40 | if p[i] > maxlen: 41 | index = i 42 | maxlen = p[i] 43 | s = n_str[index - p[index] + 1:index + p[index]] 44 | return s.replace('#', '') 45 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/make_sentence.py: -------------------------------------------------------------------------------- 1 | """ 2 | For a given string and dictionary, how many sentences can you make from the 3 | string, such that all the words are contained in the dictionary. 4 | 5 | eg: for given string -> "appletablet" 6 | "apple", "tablet" 7 | "applet", "able", "t" 8 | "apple", "table", "t" 9 | "app", "let", "able", "t" 10 | 11 | "applet", {app, let, apple, t, applet} => 3 12 | "thing", {"thing"} -> 1 13 | """ 14 | 15 | count = 0 16 | 17 | 18 | def make_sentence(str_piece, dictionaries): 19 | global count 20 | if len(str_piece) == 0: 21 | return True 22 | for i in range(0, len(str_piece)): 23 | prefix, suffix = str_piece[0:i], str_piece[i:] 24 | if prefix in dictionaries: 25 | if suffix in dictionaries or make_sentence(suffix, dictionaries): 26 | count += 1 27 | return True 28 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/min_distance.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two words word1 and word2, find the minimum number of steps required to 3 | make word1 and word2 the same, where in each step you can delete one character 4 | in either string. 5 | 6 | For example: 7 | Input: "sea", "eat" 8 | Output: 2 9 | Explanation: You need one step to make "sea" to "ea" and another step to make "eat" to "ea". 10 | 11 | Reference: https://leetcode.com/problems/delete-operation-for-two-strings/description/ 12 | """ 13 | 14 | def min_distance(word1, word2): 15 | return len(word1) + len(word2) - 2 * lcs(word1, word2, len(word1), len(word2)) 16 | 17 | def lcs(s1, s2, i, j): 18 | """ 19 | The length of longest common subsequence among the two given strings s1 and s2 20 | """ 21 | if i == 0 or j == 0: 22 | return 0 23 | elif s1[i - 1] == s2[j - 1]: 24 | return 1 + lcs(s1, s2, i - 1, j - 1) 25 | else: 26 | return max(lcs(s1, s2, i - 1, j), lcs(s1, s2, i, j - 1)) 27 | 28 | # TODO: Using dynamic programming 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/multiply_strings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two non-negative integers num1 and num2 represented as strings, 3 | return the product of num1 and num2. 4 | 5 | Note: 6 | 7 | The length of both num1 and num2 is < 110. 8 | Both num1 and num2 contains only digits 0-9. 9 | Both num1 and num2 does not contain any leading zero. 10 | You must not use any built-in BigInteger library or convert 11 | the inputs to integer directly. 12 | """ 13 | 14 | 15 | def multiply(num1: "str", num2: "str") -> "str": 16 | interm = [] 17 | zero = ord('0') 18 | i_pos = 1 19 | for i in reversed(num1): 20 | j_pos = 1 21 | add = 0 22 | for j in reversed(num2): 23 | mult = (ord(i)-zero) * (ord(j)-zero) * j_pos * i_pos 24 | j_pos *= 10 25 | add += mult 26 | i_pos *= 10 27 | interm.append(add) 28 | return str(sum(interm)) 29 | 30 | 31 | if __name__ == "__main__": 32 | print(multiply("1", "23")) 33 | print(multiply("23", "23")) 34 | print(multiply("100", "23")) 35 | print(multiply("100", "10000")) 36 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/one_edit_distance.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two strings S and T, determine if they are both one edit distance apart. 3 | """ 4 | 5 | 6 | def is_one_edit(s, t): 7 | """ 8 | :type s: str 9 | :type t: str 10 | :rtype: bool 11 | """ 12 | if len(s) > len(t): 13 | return is_one_edit(t, s) 14 | if len(t) - len(s) > 1 or t == s: 15 | return False 16 | for i in range(len(s)): 17 | if s[i] != t[i]: 18 | return s[i+1:] == t[i+1:] or s[i:] == t[i+1:] 19 | return True 20 | 21 | 22 | def is_one_edit2(s, t): 23 | l1, l2 = len(s), len(t) 24 | if l1 > l2: 25 | return is_one_edit2(t, s) 26 | if len(t) - len(s) > 1 or t == s: 27 | return False 28 | for i in range(len(s)): 29 | if s[i] != t[i]: 30 | if l1 == l2: 31 | s = s[:i]+t[i]+s[i+1:] # modify 32 | else: 33 | s = s[:i]+t[i]+s[i:] # insertion 34 | break 35 | return s == t or s == t[:-1] 36 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/repeat_string.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two strings A and B, find the minimum number of times A has to be repeated such that B is a substring of it. If no such solution, return -1. 3 | 4 | For example, with A = "abcd" and B = "cdabcdab". 5 | 6 | Return 3, because by repeating A three times (“abcdabcdabcd”), B is a substring of it; and B is not a substring of A repeated two times ("abcdabcd"). 7 | 8 | Note: 9 | The length of A and B will be between 1 and 10000. 10 | 11 | Reference: https://leetcode.com/problems/repeated-string-match/description/ 12 | """ 13 | def repeat_string(A, B): 14 | count = 1 15 | tmp = A 16 | max_count = (len(B) / len(A)) + 1 17 | while not(B in tmp): 18 | tmp = tmp + A 19 | if (count > max_count): 20 | count = -1 21 | break 22 | count = count + 1 23 | 24 | return count 25 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/repeat_substring.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a non-empty string check if it can be constructed by taking 3 | a substring of it and appending multiple copies of the substring together. 4 | 5 | For example: 6 | Input: "abab" 7 | Output: True 8 | Explanation: It's the substring "ab" twice. 9 | 10 | Input: "aba" 11 | Output: False 12 | 13 | Input: "abcabcabcabc" 14 | Output: True 15 | Explanation: It's the substring "abc" four times. 16 | 17 | Reference: https://leetcode.com/problems/repeated-substring-pattern/description/ 18 | """ 19 | def repeat_substring(s): 20 | """ 21 | :type s: str 22 | :rtype: bool 23 | """ 24 | str = (s + s)[1:-1] 25 | return s in str 26 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/reverse_string.py: -------------------------------------------------------------------------------- 1 | def recursive(s): 2 | l = len(s) 3 | if l < 2: 4 | return s 5 | return recursive(s[l//2:]) + recursive(s[:l//2]) 6 | 7 | def iterative(s): 8 | r = list(s) 9 | i, j = 0, len(s) - 1 10 | while i < j: 11 | r[i], r[j] = r[j], r[i] 12 | i += 1 13 | j -= 1 14 | return "".join(r) 15 | 16 | def pythonic(s): 17 | r = list(reversed(s)) 18 | return "".join(r) 19 | 20 | def ultra_pythonic(s): 21 | return s[::-1] 22 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/reverse_vowel.py: -------------------------------------------------------------------------------- 1 | 2 | def reverse_vowel(s): 3 | vowels = "AEIOUaeiou" 4 | i, j = 0, len(s)-1 5 | s = list(s) 6 | while i < j: 7 | while i < j and s[i] not in vowels: 8 | i += 1 9 | while i < j and s[j] not in vowels: 10 | j -= 1 11 | s[i], s[j] = s[j], s[i] 12 | i, j = i + 1, j - 1 13 | return "".join(s) 14 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/reverse_words.py: -------------------------------------------------------------------------------- 1 | 2 | def reverse(array, i, j): 3 | while i < j: 4 | array[i], array[j] = array[j], array[i] 5 | i += 1 6 | j -= 1 7 | 8 | 9 | def reverse_words(string): 10 | arr = string.strip().split() # arr is list of words 11 | n = len(arr) 12 | reverse(arr, 0, n-1) 13 | 14 | return " ".join(arr) 15 | 16 | 17 | if __name__ == "__main__": 18 | test = "I am keon kim and I like pizza" 19 | print(test) 20 | print(reverse_words(test)) 21 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/roman_to_int.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a roman numeral, convert it to an integer. 3 | Input is guaranteed to be within the range from 1 to 3999. 4 | """ 5 | 6 | 7 | def roman_to_int(s:"str")->"int": 8 | number = 0 9 | roman = {'M':1000, 'D':500, 'C': 100, 'L':50, 'X':10, 'V':5, 'I':1} 10 | for i in range(len(s)-1): 11 | if roman[s[i]] < roman[s[i+1]]: 12 | number -= roman[s[i]] 13 | else: 14 | number += roman[s[i]] 15 | return number + roman[s[-1]] 16 | 17 | 18 | if __name__ == "__main__": 19 | roman = "DCXXI" 20 | print(roman_to_int(roman)) 21 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/strings/rotate.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a strings s and int k, return a string that rotates k times 3 | 4 | For example, 5 | rotate("hello", 2) return "llohe" 6 | rotate("hello", 5) return "hello" 7 | rotate("hello", 6) return "elloh" 8 | rotate("hello", 7) return "llohe" 9 | 10 | accepts two strings 11 | returns bool 12 | """ 13 | def rotate(s, k): 14 | double_s = s + s 15 | if k <= len(s): 16 | return double_s[k:k + len(s)] 17 | else: 18 | return double_s[k-len(s):k] 19 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/owl/e444919bdc1547e0458f24cf955a822b4c815539/test-algorithms/algorithms/tree/__init__.py -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/avl/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/owl/e444919bdc1547e0458f24cf955a822b4c815539/test-algorithms/algorithms/tree/avl/__init__.py -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/bin_tree_to_list.py: -------------------------------------------------------------------------------- 1 | from tree.tree import TreeNode 2 | 3 | 4 | def bin_tree_to_list(root): 5 | """ 6 | type root: root class 7 | """ 8 | if not root: 9 | return root 10 | root = bin_tree_to_list_util(root) 11 | while root.left: 12 | root = root.left 13 | return root 14 | 15 | 16 | def bin_tree_to_list_util(root): 17 | if not root: 18 | return root 19 | if root.left: 20 | left = bin_tree_to_list_util(root.left) 21 | while left.right: 22 | left = left.right 23 | left.right = root 24 | root.left = left 25 | if root.right: 26 | right = bin_tree_to_list_util(root.right) 27 | while right.left: 28 | right = right.left 29 | right.left = root 30 | root.right = right 31 | return root 32 | 33 | 34 | def print_tree(root): 35 | while root: 36 | print(root.val) 37 | root = root.right 38 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/binary_tree_paths.py: -------------------------------------------------------------------------------- 1 | def binary_tree_paths(root): 2 | res = [] 3 | if root is None: 4 | return res 5 | dfs(res, root, str(root.val)) 6 | return res 7 | 8 | 9 | def dfs(res, root, cur): 10 | if root.left is None and root.right is None: 11 | res.append(cur) 12 | if root.left: 13 | dfs(res, root.left, cur+'->'+str(root.left.val)) 14 | if root.right: 15 | dfs(res, root.right, cur+'->'+str(root.right.val)) 16 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/bst/BSTIterator.py: -------------------------------------------------------------------------------- 1 | 2 | class BSTIterator: 3 | def __init__(self, root): 4 | self.stack = [] 5 | while root: 6 | self.stack.append(root) 7 | root = root.left 8 | 9 | def has_next(self): 10 | return bool(self.stack) 11 | 12 | def next(self): 13 | node = self.stack.pop() 14 | tmp = node 15 | if tmp.right: 16 | tmp = tmp.right 17 | while tmp: 18 | self.stack.append(tmp) 19 | tmp = tmp.left 20 | return node.val 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/bst/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: __init__.py 8 | @time: 2024/3/28 15:21 9 | """ 10 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/bst/array_to_bst.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array where elements are sorted in ascending order, 3 | convert it to a height balanced BST. 4 | """ 5 | 6 | 7 | class TreeNode(object): 8 | def __init__(self, x): 9 | self.val = x 10 | self.left = None 11 | self.right = None 12 | 13 | 14 | def array_to_bst(nums): 15 | if not nums: 16 | return None 17 | mid = len(nums)//2 18 | node = TreeNode(nums[mid]) 19 | node.left = array_to_bst(nums[:mid]) 20 | node.right = array_to_bst(nums[mid+1:]) 21 | return node 22 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/bst/bst_closest_value.py: -------------------------------------------------------------------------------- 1 | # Given a non-empty binary search tree and a target value, 2 | # find the value in the BST that is closest to the target. 3 | 4 | # Note: 5 | # Given target value is a floating point. 6 | # You are guaranteed to have only one unique value in the BST 7 | # that is closest to the target. 8 | 9 | 10 | # Definition for a binary tree node. 11 | # class TreeNode(object): 12 | # def __init__(self, x): 13 | # self.val = x 14 | # self.left = None 15 | # self.right = None 16 | 17 | def closest_value(root, target): 18 | """ 19 | :type root: TreeNode 20 | :type target: float 21 | :rtype: int 22 | """ 23 | a = root.val 24 | kid = root.left if target < a else root.right 25 | if not kid: 26 | return a 27 | b = closest_value(kid, target) 28 | return min((a,b), key=lambda x: abs(target-x)) 29 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/bst/is_bst.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a binary tree, determine if it is a valid binary search tree (BST). 3 | 4 | Assume a BST is defined as follows: 5 | 6 | The left subtree of a node contains only nodes 7 | with keys less than the node's key. 8 | The right subtree of a node contains only nodes 9 | with keys greater than the node's key. 10 | Both the left and right subtrees must also be binary search trees. 11 | Example 1: 12 | 2 13 | / \ 14 | 1 3 15 | Binary tree [2,1,3], return true. 16 | Example 2: 17 | 1 18 | / \ 19 | 2 3 20 | Binary tree [1,2,3], return false. 21 | """ 22 | 23 | def is_bst(root): 24 | """ 25 | :type root: TreeNode 26 | :rtype: bool 27 | """ 28 | 29 | stack = [] 30 | pre = None 31 | 32 | while root or stack: 33 | while root: 34 | stack.append(root) 35 | root = root.left 36 | root = stack.pop() 37 | if pre and root.val <= pre.val: 38 | return False 39 | pre = root 40 | root = root.right 41 | 42 | return True 43 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/bst/predecessor.py: -------------------------------------------------------------------------------- 1 | def predecessor(root, node): 2 | pred = None 3 | while root: 4 | if node.val > root.val: 5 | pred = root 6 | root = root.right 7 | else: 8 | root = root.left 9 | return pred 10 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/bst/serialize_deserialize.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class TreeNode(object): 4 | def __init__(self, x): 5 | self.val = x 6 | self.left = None 7 | self.right = None 8 | 9 | 10 | def serialize(root): 11 | def build_string(node): 12 | if node: 13 | vals.append(str(node.val)) 14 | build_string(node.left) 15 | build_string(node.right) 16 | else: 17 | vals.append("#") 18 | vals = [] 19 | build_string(root) 20 | return " ".join(vals) 21 | 22 | 23 | def deserialize(data): 24 | def build_tree(): 25 | val = next(vals) 26 | if val == "#": 27 | return None 28 | node = TreeNode(int(val)) 29 | node.left = build_tree() 30 | node.right = build_tree() 31 | return node 32 | vals = iter(data.split()) 33 | return build_tree() 34 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/bst/successor.py: -------------------------------------------------------------------------------- 1 | def successor(root, node): 2 | succ = None 3 | while root: 4 | if node.val < root.val: 5 | succ = root 6 | root = root.left 7 | else: 8 | root = root.right 9 | return succ 10 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/bst/unique_bst.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given n, how many structurally unique BST's 3 | (binary search trees) that store values 1...n? 4 | 5 | For example, 6 | Given n = 3, there are a total of 5 unique BST's. 7 | 8 | 1 3 3 2 1 9 | \ / / / \ \ 10 | 3 2 1 1 3 2 11 | / / \ \ 12 | 2 1 2 3 13 | """ 14 | 15 | 16 | """ 17 | Taking 1~n as root respectively: 18 | 1 as root: # of trees = F(0) * F(n-1) // F(0) == 1 19 | 2 as root: # of trees = F(1) * F(n-2) 20 | 3 as root: # of trees = F(2) * F(n-3) 21 | ... 22 | n-1 as root: # of trees = F(n-2) * F(1) 23 | n as root: # of trees = F(n-1) * F(0) 24 | 25 | So, the formulation is: 26 | F(n) = F(0) * F(n-1) + F(1) * F(n-2) + F(2) * F(n-3) + ... + F(n-2) * F(1) + F(n-1) * F(0) 27 | """ 28 | 29 | def num_trees(n): 30 | """ 31 | :type n: int 32 | :rtype: int 33 | """ 34 | dp = [0] * (n+1) 35 | dp[0] = 1 36 | dp[1] = 1 37 | for i in range(2, n+1): 38 | for j in range(i+1): 39 | dp[i] += dp[i-j] * dp[j-1] 40 | return dp[-1] 41 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/deepest_left.py: -------------------------------------------------------------------------------- 1 | # Given a binary tree, find the deepest node 2 | # that is the left child of its parent node. 3 | 4 | # Example: 5 | 6 | # 1 7 | # / \ 8 | # 2 3 9 | # / \ \ 10 | # 4 5 6 11 | # \ 12 | # 7 13 | # should return 4. 14 | 15 | from tree.tree import TreeNode 16 | 17 | 18 | class DeepestLeft: 19 | def __init__(self): 20 | self.depth = 0 21 | self.Node = None 22 | 23 | 24 | def find_deepest_left(root, is_left, depth, res): 25 | if not root: 26 | return 27 | if is_left and depth > res.depth: 28 | res.depth = depth 29 | res.Node = root 30 | find_deepest_left(root.left, True, depth + 1, res) 31 | find_deepest_left(root.right, False, depth + 1, res) 32 | 33 | 34 | if __name__ == '__main__': 35 | root = TreeNode(1) 36 | root.left = TreeNode(2) 37 | root.right = TreeNode(3) 38 | root.left.left = TreeNode(4) 39 | root.left.right = TreeNode(5) 40 | root.right.right = TreeNode(6) 41 | root.right.right.right = TreeNode(7) 42 | 43 | res = DeepestLeft() 44 | find_deepest_left(root, True, 1, res) 45 | if res.Node: 46 | print(res.Node.val) 47 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/fenwick_tree/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: __init__.py 8 | @time: 2024/3/28 15:21 9 | """ 10 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/invert_tree.py: -------------------------------------------------------------------------------- 1 | # invert a binary tree 2 | 3 | def reverse(root): 4 | if root is None: 5 | return 6 | root.left, root.right = root.right, root.left 7 | if root.left: 8 | reverse(root.left) 9 | if root.right: 10 | reverse(root.right) 11 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/is_balanced.py: -------------------------------------------------------------------------------- 1 | def is_balanced(root): 2 | return __is_balanced_recursive(root) 3 | 4 | 5 | def __is_balanced_recursive(root): 6 | """ 7 | O(N) solution 8 | """ 9 | return -1 != __get_depth(root) 10 | 11 | 12 | def __get_depth(root): 13 | """ 14 | return 0 if unbalanced else depth + 1 15 | """ 16 | if root is None: 17 | return 0 18 | left = __get_depth(root.left) 19 | right = __get_depth(root.right) 20 | if abs(left-right) > 1 or -1 in [left, right]: 21 | return -1 22 | return 1 + max(left, right) 23 | 24 | 25 | # def is_balanced(root): 26 | # """ 27 | # O(N^2) solution 28 | # """ 29 | # left = max_height(root.left) 30 | # right = max_height(root.right) 31 | # return abs(left-right) <= 1 and is_balanced(root.left) and is_balanced(root.right) 32 | 33 | # def max_height(root): 34 | # if root is None: 35 | # return 0 36 | # return max(max_height(root.left), max_height(root.right)) + 1 37 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/longest_consecutive.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a binary tree, find the length of the longest consecutive sequence path. 3 | 4 | The path refers to any sequence of nodes from some starting node to any node 5 | in the tree along the parent-child connections. 6 | The longest consecutive path need to be from parent to child 7 | (cannot be the reverse). 8 | 9 | For example, 10 | 1 11 | \ 12 | 3 13 | / \ 14 | 2 4 15 | \ 16 | 5 17 | Longest consecutive sequence path is 3-4-5, so return 3. 18 | 2 19 | \ 20 | 3 21 | / 22 | 2 23 | / 24 | 1 25 | """ 26 | 27 | 28 | def longest_consecutive(root): 29 | """ 30 | :type root: TreeNode 31 | :rtype: int 32 | """ 33 | if root is None: 34 | return 0 35 | max_len = 0 36 | dfs(root, 0, root.val, max_len) 37 | return max_len 38 | 39 | 40 | def dfs(root, cur, target, max_len): 41 | if root is None: 42 | return 43 | if root.val == target: 44 | cur += 1 45 | else: 46 | cur = 1 47 | max_len = max(cur, max_len) 48 | dfs(root.left, cur, root.val+1, max_len) 49 | dfs(root.right, cur, root.val+1, max_len) 50 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/max_path_sum.py: -------------------------------------------------------------------------------- 1 | def max_path_sum(root): 2 | maximum = float("-inf") 3 | helper(root, maximum) 4 | return maximum 5 | 6 | 7 | def helper(root, maximum): 8 | if root is None: 9 | return 0 10 | left = helper(root.left, maximum) 11 | right = helper(root.right, maximum) 12 | maximum = max(maximum, left+right+root.val) 13 | return root.val + maximum 14 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/pretty_print.py: -------------------------------------------------------------------------------- 1 | # a -> Adam -> Book -> 4 2 | # b -> Bill -> Computer -> 5 3 | # -> TV -> 6 4 | # Jill -> Sports -> 1 5 | # c -> Bill -> Sports -> 3 6 | # d -> Adam -> Computer -> 3 7 | # Quin -> Computer -> 3 8 | # e -> Quin -> Book -> 5 9 | # -> TV -> 2 10 | # f -> Adam -> Computer -> 7 11 | 12 | from __future__ import print_function 13 | 14 | 15 | def tree_print(tree): 16 | for key in tree: 17 | print(key, end=' ') # end=' ' prevents a newline character 18 | tree_element = tree[key] # multiple lookups is expensive, even amortized O(1)! 19 | for subElem in tree_element: 20 | print(" -> ", subElem, end=' ') 21 | if type(subElem) != str: # OP wants indenting after digits 22 | print("\n ") # newline and a space to match indenting 23 | print() # forces a newline 24 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/red_black_tree/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: __init__.py 8 | @time: 2024/3/28 15:21 9 | """ 10 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/same_tree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two binary trees, write a function to check 3 | if they are equal or not. 4 | 5 | Two binary trees are considered equal if they are 6 | structurally identical and the nodes have the same value. 7 | """ 8 | 9 | 10 | def is_same_tree(p, q): 11 | if p is None and q is None: 12 | return True 13 | if p is not None and q is not None and p.val == q.val: 14 | return is_same_tree(p.left, q.left) and is_same_tree(p.right, q.right) 15 | return False 16 | 17 | # Time Complexity O(min(N,M)) 18 | # where N and M are the number of nodes for the trees. 19 | 20 | # Space Complexity O(min(height1, height2)) 21 | # levels of recursion is the mininum height between the two trees. 22 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/segment_tree/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: __init__.py 8 | @time: 2024/3/28 15:21 9 | """ 10 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/traversal/__init__.py: -------------------------------------------------------------------------------- 1 | from .preorder import * 2 | from .postorder import * 3 | from .inorder import * 4 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/traversal/level_order.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a binary tree, return the level order traversal of 3 | its nodes' values. (ie, from left to right, level by level). 4 | 5 | For example: 6 | Given binary tree [3,9,20,null,null,15,7], 7 | 3 8 | / \ 9 | 9 20 10 | / \ 11 | 15 7 12 | return its level order traversal as: 13 | [ 14 | [3], 15 | [9,20], 16 | [15,7] 17 | ] 18 | """ 19 | 20 | 21 | def level_order(root): 22 | ans = [] 23 | if not root: 24 | return ans 25 | level = [root] 26 | while level: 27 | current = [] 28 | new_level = [] 29 | for node in level: 30 | current.append(node.val) 31 | if node.left: 32 | new_level.append(node.left) 33 | if node.right: 34 | new_level.append(node.right) 35 | level = new_level 36 | ans.append(current) 37 | return ans 38 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/traversal/postorder.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Time complexity : O(n) 3 | ''' 4 | 5 | class Node: 6 | 7 | def __init__(self, val, left=None, right=None): 8 | self.val = val 9 | self.left = left 10 | self.right = right 11 | 12 | 13 | def postorder(root): 14 | res_temp = [] 15 | res = [] 16 | if not root: 17 | return res 18 | stack = [] 19 | stack.append(root) 20 | while stack: 21 | root = stack.pop() 22 | res_temp.append(root.val) 23 | if root.left: 24 | stack.append(root.left) 25 | if root.right: 26 | stack.append(root.right) 27 | while res_temp: 28 | res.append(res_temp.pop()) 29 | return res 30 | 31 | # Recursive Implementation 32 | def postorder_rec(root, res=None): 33 | if root is None: 34 | return [] 35 | if res is None: 36 | res = [] 37 | postorder_rec(root.left, res) 38 | postorder_rec(root.right, res) 39 | res.append(root.val) 40 | return res 41 | 42 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/traversal/preorder.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Time complexity : O(n) 3 | ''' 4 | 5 | class Node: 6 | 7 | def __init__(self, val, left=None, right=None): 8 | self.val = val 9 | self.left = left 10 | self.right = right 11 | 12 | 13 | def preorder(root): 14 | res = [] 15 | if not root: 16 | return res 17 | stack = [] 18 | stack.append(root) 19 | while stack: 20 | root = stack.pop() 21 | res.append(root.val) 22 | if root.right: 23 | stack.append(root.right) 24 | if root.left: 25 | stack.append(root.left) 26 | return res 27 | 28 | # Recursive Implementation 29 | def preorder_rec(root, res=None): 30 | if root is None: 31 | return [] 32 | if res is None: 33 | res = [] 34 | res.append(root.val) 35 | preorder_rec(root.left, res) 36 | preorder_rec(root.right, res) 37 | return res 38 | 39 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/traversal/zigzag.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a binary tree, return the zigzag level order traversal 3 | of its nodes' values. 4 | (ie, from left to right, then right to left 5 | for the next level and alternate between). 6 | 7 | For example: 8 | Given binary tree [3,9,20,null,null,15,7], 9 | 3 10 | / \ 11 | 9 20 12 | / \ 13 | 15 7 14 | return its zigzag level order traversal as: 15 | [ 16 | [3], 17 | [20,9], 18 | [15,7] 19 | ] 20 | """ 21 | 22 | 23 | def zigzag_level(root): 24 | res = [] 25 | if not root: 26 | return res 27 | level = [root] 28 | flag = 1 29 | while level: 30 | current = [] 31 | new_level = [] 32 | for node in level: 33 | current.append(node.val) 34 | if node.left: 35 | new_level.append(node.left) 36 | if node.right: 37 | new_level.append(node.right) 38 | level = new_level 39 | res.append(current[::flag]) 40 | flag *= -1 41 | return res 42 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/tree.py: -------------------------------------------------------------------------------- 1 | class TreeNode: 2 | def __init__(self, val=0): 3 | self.val = val 4 | self.left = None 5 | self.right = None 6 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/trie/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: __init__.py 8 | @time: 2024/3/28 15:21 9 | """ 10 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/tree/trie/trie.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implement a trie with insert, search, and startsWith methods. 3 | 4 | Note: 5 | You may assume that all inputs are consist of lowercase letters a-z. 6 | """ 7 | import collections 8 | 9 | 10 | class TrieNode: 11 | def __init__(self): 12 | self.children = collections.defaultdict(TrieNode) 13 | self.is_word = False 14 | 15 | 16 | class Trie: 17 | def __init__(self): 18 | self.root = TrieNode() 19 | 20 | def insert(self, word): 21 | current = self.root 22 | for letter in word: 23 | current = current.children[letter] 24 | current.is_word = True 25 | 26 | def search(self, word): 27 | current = self.root 28 | for letter in word: 29 | current = current.children.get(letter) 30 | if current is None: 31 | return False 32 | return current.is_word 33 | 34 | def starts_with(self, prefix): 35 | current = self.root 36 | for letter in prefix: 37 | current = current.children.get(letter) 38 | if current is None: 39 | return False 40 | return True 41 | 42 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/unionfind/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: __init__.py 8 | @time: 2024/3/28 15:21 9 | """ 10 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/unix/__init__.py: -------------------------------------------------------------------------------- 1 | from .path.join_with_slash import * 2 | from .path.full_path import * 3 | from .path.split import * 4 | from .path.simplify_path import * 5 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/unix/path/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: __init__.py 8 | @time: 2024/3/28 15:21 9 | """ 10 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/unix/path/full_path.py: -------------------------------------------------------------------------------- 1 | """ 2 | Get a full absolute path a file 3 | """ 4 | import os 5 | def full_path(file): 6 | return os.path.abspath(os.path.expanduser(file)) 7 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/unix/path/join_with_slash.py: -------------------------------------------------------------------------------- 1 | """ 2 | Both URL and file path joins use slashes as dividers between their parts. 3 | For example: 4 | 5 | path/to/dir + file --> path/to/dir/file 6 | path/to/dir/ + file --> path/to/dir/file 7 | http://algorithms.com/ + part --> http://algorithms.com/part 8 | http://algorithms.com + part --> http://algorithms/part 9 | """ 10 | import os 11 | 12 | def join_with_slash(base, suffix): 13 | # Remove / trailing 14 | base = base.rstrip('/') 15 | # Remove / leading 16 | suffix = suffix.lstrip('/').rstrip() 17 | full_path = "{}/{}".format(base, suffix) 18 | return full_path 19 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/unix/path/simplify_path.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an absolute path for a file (Unix-style), simplify it. 3 | 4 | For example, 5 | path = "/home/", => "/home" 6 | path = "/a/./b/../../c/", => "/c" 7 | 8 | Corner Cases: 9 | 10 | Did you consider the case where path = "/../"? 11 | In this case, you should return "/". 12 | Another corner case is the path might contain multiple slashes '/' together, such as "/home//foo/". 13 | In this case, you should ignore redundant slashes and return "/home/foo". 14 | 15 | Reference: https://leetcode.com/problems/simplify-path/description/ 16 | """ 17 | 18 | import os 19 | def simplify_path_v1(path): 20 | return os.path.abspath(path) 21 | 22 | def simplify_path_v2(path): 23 | stack, tokens = [], path.split("/") 24 | for token in tokens: 25 | if token == ".." and stack: 26 | stack.pop() 27 | elif token != ".." and token != "." and token: 28 | stack.append(token) 29 | return "/" + "/".join(stack) 30 | -------------------------------------------------------------------------------- /test-algorithms/algorithms/unix/path/split.py: -------------------------------------------------------------------------------- 1 | """ 2 | Splitting a path into 2 parts 3 | Example: 4 | Input: https://algorithms/unix/test.py (for url) 5 | Output: 6 | part[0]: https://algorithms/unix 7 | part[1]: test.py 8 | 9 | Input: test-algorithms/unix/test.py (for file path) 10 | Output: 11 | part[0]: test-algorithms/unix 12 | part[1]: test.py 13 | """ 14 | import os 15 | 16 | def split(path): 17 | parts = [] 18 | split_part = path.rpartition('/') 19 | # Takt the origin path without the last part 20 | parts.append(split_part[0]) 21 | # Take the last element of list 22 | parts.append(split_part[2]) 23 | return parts 24 | -------------------------------------------------------------------------------- /test-algorithms/demo_jieba.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: demo_jieba.py 8 | @time: 2024/3/29 10:51 9 | """ 10 | 11 | import jieba 12 | import pandas as pd 13 | 14 | if __name__ == '__main__': 15 | 16 | # 原句 17 | sentence = "我昨天去了超市,买了很多东西,然后又去了图书馆还借了几本书回家看。" 18 | 19 | # 使用 jieba 分词 20 | words = jieba.cut(sentence, cut_all=False) 21 | 22 | stopWords = pd.read_csv("/Users/jayzhen/Downloads/百度停用词表.txt", sep='hahaha') 23 | stopWords = ['\n', '还'] + list(stopWords.iloc[:, 0]) 24 | processed_words = [i for i in words if i not in stopWords] 25 | 26 | # 去除冗词赘述并重组结构 27 | # processed_words = [word for word in words if "昨天" not in word] 28 | 29 | # 提炼关键信息 30 | # key_info = ["购物" if "超市" in word else "阅读" for word in processed_words] 31 | 32 | # 组合精简后的句子 33 | simple_sentence = "".join(processed_words) 34 | 35 | print(simple_sentence) 36 | -------------------------------------------------------------------------------- /test-algorithms/interview/1.两数之和.py: -------------------------------------------------------------------------------- 1 | # 2 | # @lc app=leetcode.cn id=1 lang=python 3 | # 4 | # [1] 两数之和 5 | # target = a + b 6 | # 7 | 8 | # @lc code=start 9 | 10 | 11 | class Solution(object): 12 | def twoSum(self, nums, target): 13 | """ 14 | :type nums: List[int] 15 | :type target: int 16 | :rtype: List[int] 17 | """ 18 | # 利用 dict 的能力 19 | item_map = {} 20 | for index, value in enumerate(nums): 21 | tmp = target - value 22 | if tmp in item_map: 23 | return [item_map.get(tmp), index] 24 | item_map[value] = index 25 | return [] 26 | 27 | # @lc code=end 28 | 29 | -------------------------------------------------------------------------------- /test-algorithms/interview/2.两数相加.py: -------------------------------------------------------------------------------- 1 | # 2 | # @lc app=leetcode.cn id=2 lang=python 3 | # 4 | # [2] 两数相加 5 | # 6 | 7 | # @lc code=start 8 | # Definition for singly-linked list. 9 | # class ListNode(object): 10 | # def __init__(self, val=0, next=None): 11 | # self.val = val 12 | # self.next = next 13 | class Solution(object): 14 | def addTwoNumbers(self, l1, l2): 15 | """ 16 | :type l1: ListNode 17 | :type l2: ListNode 18 | :rtype: ListNode 19 | """ 20 | 21 | result = head = ListNode(0) 22 | mod_val = 0 23 | while l1 or l2: 24 | v1 = l1.val if l1 else 0 25 | v2 = l2.val if l2 else 0 26 | tmp = v1 + v2 + mod_val 27 | mod_val = tmp // 10 28 | head.next = ListNode(tmp % 10) 29 | head = head.next 30 | if l1: 31 | l1 = l1.next 32 | if l2: 33 | l2 = l2.next 34 | if mod_val > 0: 35 | head.next = ListNode(mod_val) 36 | 37 | return result.next 38 | 39 | # @lc code=end 40 | 41 | -------------------------------------------------------------------------------- /test-algorithms/interview/20220726-最长重复子串.py: -------------------------------------------------------------------------------- 1 | 2 | def length_of_longest_sub_string(s: str) -> str: 3 | left, right = 0, 1 4 | result = s[0] 5 | while right < len(s): 6 | while s[right] == s[right-1] and right < len(s) - 1: 7 | right += 1 8 | result = s[left:right] if right - left > len(result) else result 9 | left = right 10 | right += 1 11 | # print(result, s[left:right], left, right) 12 | return result 13 | 14 | 15 | if __name__ == '__main__': 16 | print(length_of_longest_sub_string('xxxxxdxxdddddwddddedddwdddd')) 17 | -------------------------------------------------------------------------------- /test-algorithms/interview/3.无重复字符的最长子串.py: -------------------------------------------------------------------------------- 1 | # 2 | # @lc app=leetcode.cn id=3 lang=python 3 | # 4 | # [3] 无重复字符的最长子串 5 | # 6 | 7 | # @lc code=start 8 | class Solution(object): 9 | def lengthOfLongestSubstring(self, s): 10 | """ 11 | :type s: str 12 | :rtype: int 13 | """ 14 | ''' 15 | 标签:滑动窗口 16 | 暴力解法时间复杂度较高,会达到 O(n^2)O(n 17 | 2 18 | ),故而采取滑动窗口的方法降低时间复杂度 19 | 定义一个 map 数据结构存储 (k, v),其中 key 值为字符,value 值为字符位置 +1,加 1 表示从字符位置后一个才开始不重复 20 | 我们定义不重复子串的开始位置为 start,结束位置为 end 21 | 随着 end 不断遍历向后,会遇到与 [start, end] 区间内字符相同的情况,此时将字符作为 key 值,获取其 value 值,并更新 start,此时 [start, end] 区间内不存在重复字符 22 | 无论是否更新 start,都会更新其 map 数据结构和结果 ans。 23 | 时间复杂度:O(n)O(n) 24 | ''' 25 | d_map = {} 26 | start, end, result = 0, 0, 0 27 | for end in range(len(s)): 28 | if s[end] in d_map: 29 | start = max(d_map.get(s[end]), start) 30 | result = max(end - start + 1, result) 31 | d_map[s[end]] = end + 1 32 | return result 33 | # @lc code=end 34 | 35 | -------------------------------------------------------------------------------- /test-algorithms/interview/5.最长回文子串.py: -------------------------------------------------------------------------------- 1 | # 2 | # @lc app=leetcode.cn id=5 lang=python 3 | # 4 | # [5] 最长回文子串 5 | # 6 | # https://leetcode.cn/problems/longest-palindromic-substring/description/ 7 | # 8 | # algorithms 9 | # Medium (37.84%) 10 | # Likes: 6884 11 | # Dislikes: 0 12 | # Total Accepted: 1.5M 13 | # Total Submissions: 4.1M 14 | # Testcase Example: '"babad"' 15 | # 16 | # 给你一个字符串 s,找到 s 中最长的回文子串。 17 | # 18 | # 如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。 19 | # 20 | # 21 | # 22 | # 示例 1: 23 | # 24 | # 25 | # 输入:s = "babad" 26 | # 输出:"bab" 27 | # 解释:"aba" 同样是符合题意的答案。 28 | # 29 | # 30 | # 示例 2: 31 | # 32 | # 33 | # 输入:s = "cbbd" 34 | # 输出:"bb" 35 | # 36 | # 37 | # 38 | # 39 | # 提示: 40 | # 41 | # 42 | # 1 <= s.length <= 1000 43 | # s 仅由数字和英文字母组成 44 | # 45 | # 46 | # 47 | 48 | # @lc code=start 49 | class Solution(object): 50 | def longestPalindrome(self, s): 51 | """ 52 | :type s: str 53 | :rtype: str 54 | """ 55 | 56 | if s == s[::-1]: 57 | return s 58 | 59 | 60 | 61 | # @lc code=end 62 | 63 | -------------------------------------------------------------------------------- /test-algorithms/interview/attr_read_only.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | @author: jayzhen 6 | @share: https://github.com/gitjayzhen 7 | @file: attr_read_only.py 8 | @time: 4/27/21 2:01 PM 9 | """ 10 | 11 | 12 | class A(): 13 | 14 | def __init__(self): 15 | self.__age = 10 # 实例对象无法使用 .__age 的方式来获取参数和设置参数, 且无法通过.__getattribute__获取 16 | self._address = "a" 17 | 18 | def age(self): 19 | return self.__age 20 | 21 | 22 | class B(): 23 | 24 | __age = 10 # 实例对象无法使用 .__age 的方式来获取参数和设置参数, 且无法通过.__getattribute__获取 25 | _address = "b" # protected 的属性 可以被直接访问 26 | 27 | @property 28 | def age(self): 29 | return self.__age 30 | 31 | @property 32 | def address(self): 33 | return self._address 34 | 35 | 36 | if __name__ == '__main__': 37 | # a = A() 38 | # a._address = "b" 39 | # print(dir(a)) 40 | # print(a._address) 41 | # print(a.age()) 42 | 43 | b = B() 44 | print(b._address) 45 | b._address = "c" 46 | print(b._address) 47 | -------------------------------------------------------------------------------- /test-algorithms/interview/merge_ordered_arrays.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | @author: jayzhen 6 | @share: https://github.com/gitjayzhen 7 | @file: merge_ordered_arrays 8 | @time: 4/27/21 10:03 AM 9 | """ 10 | 11 | 12 | def main(a_list, b_list): 13 | """ 14 | 合并两个升序的数组 15 | 16 | 思路: 17 | 利用两个都是升序的特性,采用双循环下标的方式,使用while的方式,来操作里面的数据 18 | :param a_list: 升序 19 | :param b_list: 升序 20 | :return: 返回合并的数组,且为升序 21 | """ 22 | a_len = len(a_list) 23 | b_len = len(b_list) 24 | a = 0 25 | b = 0 26 | res = list() 27 | while a < a_len and b < b_len: 28 | if a_list[a] < b_list[b]: 29 | res.append(a_list[a]) 30 | a += 1 31 | else: 32 | res.append(b_list[b]) 33 | b += 1 34 | while a < a_len: 35 | res.append(a_list[a]) 36 | a += 1 37 | while b < b_len: 38 | res.append(b_list[b]) 39 | b += 1 40 | return res 41 | 42 | 43 | if __name__ == "__main__": 44 | a = [-1, 10, 100, 123, 333, 1000] 45 | b = [1, 3, 5, 34, 10000] 46 | print(main(a, b)) 47 | -------------------------------------------------------------------------------- /test-algorithms/interview/prime_number.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | @author: jayzhen 6 | @share: https://github.com/gitjayzhen 7 | @file: prime_number.py 8 | @time: 4/27/21 10:56 AM 9 | """ 10 | 11 | 12 | def is_sushu(i): 13 | 14 | for x in range(2, i//2+1): 15 | if i % x == 0: 16 | return False 17 | return True 18 | 19 | 20 | def main(): 21 | """ 22 | 获取1000-10000之间的所有素数,素数是只能被1和自身整除 23 | 24 | 思路: 25 | 1. 第一步的思想就是for循环处理,这里可能时间复杂度比较高,可以优化验证素数的方法,降低循环的次数 26 | 27 | :return: 28 | """ 29 | for i in range(1000, 10001): 30 | res = is_sushu(i) 31 | if res: 32 | print(i) 33 | 34 | 35 | if __name__ == '__main__': 36 | main() 37 | -------------------------------------------------------------------------------- /test-algorithms/interview/readme.md: -------------------------------------------------------------------------------- 1 | # 刷题 2 | 3 | ## 题目 4 | 5 | ```text 6 | :数据结构:: 7 | 常规:两数之和、三数之和、买卖股票最佳时机I II、无重复的最长子串、最长回文子串、寻找两个正序数组的中位数、旋转图像、回行矩阵遍历I II、替换空格、有效括号、生存人数、一次编辑、消失的数字、交换数字(不用临时变量)、整数翻转、合并区间、合并两个有序数组(原地)、最长连续序列、只出现一次的数字、翻转字符串里的单词 8 | 链表:翻转链表、两两交换链表的节点、K个一组翻转链表、删除链表重复元素 9 | 查找:搜索二维矩阵(有序)、搜索旋转排序数组 10 | 双针:删除链表的倒数第N个节点、环形链表、盛最多水的容器、分发饼干、回文排列、合并有序数组、两数组最小差、数组中平方相同 11 | 双队:滑动窗口最大值、每日温度、Top K、无序数组第K大、 12 | 动态:爬楼梯、不同路径、零钱兑换、最大子序和、按摩师 13 | 递归:电话号码字母组合、岛屿数量、括号生成、二叉树的最近公共祖先、二叉树层次遍历、二叉树的最大深度、二叉树中的最大路径和、二叉树前/中/后序遍历(及非递归)、合并K个排序链表、删除给定值的叶子节点、 14 | 系统:LRU缓存(及O(1))、两个栈实现一个队列、多线程打印 15 | 基础:快排、归并排、堆排序、冒泡、选择、插入排序、二分查找、AVL树原理、Trie树原理、二叉树增删原理、 16 | ``` 17 | 18 | 面试的算法题主要在: 19 | 二分法、递归、分治、排序、动态规划、双指针 20 | 21 | 对应的数据结构: 22 | 栈(单调栈、最小栈)、队列、列表、链表、二叉树、哈希表、堆(小顶堆,大顶堆) 23 | 24 | 解题方式: 25 | 缩小问题的规模 26 | 确定复杂度 27 | 优化思路 28 | 29 | DFS (LIFO) 使用递归或栈 与 BFS (FIFO) 使用队列 30 | 递归解决方案的优点是它更容易实现。 但是,存在一个很大的缺点:如果递归的深度太高,你将遭受堆栈溢出。 在这种情况下,您可能会希望使用 BFS,或使用显式栈实现 DFS。 31 | 32 | 33 | 前序遍历性质: 节点按照 [ 根节点 | 左子树 | 右子树 ] 排序。 34 | 中序遍历性质: 节点按照 [ 左子树 | 根节点 | 右子树 ] 排序 35 | 36 | 常见的 DFS : 先序遍历、中序遍历、后序遍历; 37 | 常见的 BFS : 层序遍历(即按层遍历)。 38 | -------------------------------------------------------------------------------- /test-algorithms/interview/test_opencv.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @site: https://github.com/gitjayzhen 6 | @version: 1.0.0 7 | @license: Apache Licence 8 | @software: PyCharm & Python 3.7+ 9 | @file: test_opencv.py 10 | @time: 2023/7/25 16:28 11 | """ 12 | 13 | import cv2 14 | 15 | # 读取图像 16 | image = cv2.imread('/Users/jayzhen/Desktop/Energy Consumption.png') 17 | 18 | # 绘制矩形 19 | start_point = (100, 100) 20 | end_point = (300, 300) 21 | color = (0, 255, 0) # BGR颜色格式,这里使用绿色 22 | thickness = 2 23 | cv2.rectangle(image, start_point, end_point, color, thickness) 24 | 25 | # 绘制圆形 26 | center_coordinates = (200, 200) 27 | radius = 50 28 | cv2.circle(image, center_coordinates, radius, color, thickness) 29 | 30 | # 绘制线段 31 | start_point = (100, 400) 32 | end_point = (300, 400) 33 | cv2.line(image, start_point, end_point, color, thickness) 34 | 35 | # 显示标记后的图像 36 | cv2.imshow('Marked Image', image) 37 | cv2.waitKey(0) 38 | cv2.destroyAllWindows() 39 | -------------------------------------------------------------------------------- /test-algorithms/interview/thread_sync.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | @author: jayzhen 6 | @share: https://github.com/gitjayzhen 7 | @file: thread_sync 8 | @time: 5/8/21 10:17 AM 9 | """ 10 | 11 | 12 | import threading 13 | import time 14 | 15 | 16 | def thread(): 17 | time.sleep(2) 18 | print('---子线程结束---') 19 | 20 | 21 | def main(): 22 | t1 = threading.Thread(target=thread) 23 | # t1.setDaemon(True) # 设置子线程守护主线程 24 | t1.start() 25 | t1.join(timeout=1) # 会先等子线程结束在结束主线程 26 | print('---主线程结束---') 27 | 28 | 29 | if __name__ == '__main__': 30 | main() 31 | # 执行结果 ---主线程结束--- #只有主线程结束,子线程来不及执行就被强制结束 32 | -------------------------------------------------------------------------------- /test-algorithms/interview/worker-need.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/owl/e444919bdc1547e0458f24cf955a822b4c815539/test-algorithms/interview/worker-need.png -------------------------------------------------------------------------------- /test-algorithms/interview/z1.随机红包.py: -------------------------------------------------------------------------------- 1 | from decimal import Decimal 2 | import random 3 | 4 | # [0, 1) round Decimal(random.random() * _max / 2).quantize(Decimal("0.00")) 5 | # 群发红包 6 | 7 | def get_data(size, member): 8 | result = [] 9 | _min = 0.01 10 | _max = size - member * _min 11 | consume = 0.0 12 | for _ in range(member - 1): 13 | tmp = round(random.random() * _max, 2) 14 | tmp = tmp if tmp != 0 else _min 15 | consume += tmp 16 | result.append(tmp) 17 | _max = round(_max - tmp, 2) if _max - tmp > 0 else 0.01 18 | print(size, _max, consume) 19 | result.append(round(size - consume, 2)) 20 | return result 21 | 22 | 23 | data = get_data(100, 10) 24 | result = 0.0 25 | for i in data: 26 | result += i 27 | print(result, data) 28 | -------------------------------------------------------------------------------- /test-algorithms/interview/z2.获取最大版本号.py: -------------------------------------------------------------------------------- 1 | 2 | def get_max_version(version_list): 3 | """求版本号中的最大版本号 4 | 5 | Args: 6 | version_list (_type_): 版本号列表 7 | 8 | Returns: 9 | _type_: 返回最大的那个版本号 10 | """ 11 | if not version_list: 12 | return '' 13 | result = version_list[0] 14 | for version in version_list[1:]: 15 | i_len, res_len = len(version), len(result) 16 | max_len = max(i_len, res_len) 17 | n = 0 18 | while n < max_len: 19 | a = version[n] if n < i_len else 0 20 | b = result[n] if n < res_len else 0 21 | if a != '.' and b != '.' and int(a) > int(b): 22 | result = version 23 | break 24 | n += 1 25 | return result 26 | 27 | print(get_max_version(['6.2.0', '6.3.1', '6.3.1.2', '6.3.1.0'])) -------------------------------------------------------------------------------- /test-algorithms/interview/z3.多线程打印字符串.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import threading 4 | 5 | # abc, def, ghi 输出 adg,beh, cfi 6 | 7 | 8 | def str_to_list(s, result): 9 | tmp = [[x] for x in s] 10 | for i in range(len(tmp)): 11 | result[i].extend(tmp[i]) 12 | 13 | def main(): 14 | result = [[],[],[]] 15 | v_1 = threading.Thread(target=str_to_list, args=("abc", result)) 16 | v_2 = threading.Thread(target=str_to_list, args=("def", result)) 17 | v_3 = threading.Thread(target=str_to_list, args=("ghi", result)) 18 | for i in [v_1, v_2, v_3]: 19 | i.start() 20 | i.join() 21 | for n in result: 22 | print("".join(n)) 23 | 24 | if __name__ == "__main__": 25 | main() -------------------------------------------------------------------------------- /test-algorithms/interview/z4.删除升序数组里重复.py: -------------------------------------------------------------------------------- 1 | #!/usr/evn/bin python 2 | # -*- coding=utf-8 -*- 3 | 4 | """ 5 | 原地删除升序数组里重复的数字,并返回去重后的数组长度和数组 6 | """ 7 | 8 | 9 | def get_filter_list(nums): 10 | if not nums: 11 | return 0, [] 12 | index = 0 13 | current = nums[index] 14 | while index < len(nums) - 1: 15 | if nums[index + 1] == current: 16 | nums.pop(index + 1) 17 | continue 18 | index += 1 19 | current = nums[index] 20 | return len(nums), nums 21 | 22 | 23 | def length_of_longest_sub_string(s: str) -> str: 24 | left, right = 0, 1 25 | result = s[0] 26 | while right < len(s): 27 | while s[right] == s[right-1] and right < len(s) - 1: 28 | right += 1 29 | result = s[left:right] if right - left > len(result) else result 30 | left = right 31 | right += 1 32 | print(result, s[left:right], left, right) 33 | return result 34 | 35 | 36 | if __name__ == '__main__': 37 | # print(get_filter_list([1, 1, 2, 2, 2, 2, 2, 5, 6, 6])) 38 | # print(get_filter_list([1, 1, 2, 3, 3, 4, 4, 5, 6, 6])) 39 | 40 | print(length_of_longest_sub_string('xxxxxdxxdddddwddddedddwdddd')) 41 | -------------------------------------------------------------------------------- /test-algorithms/interview/z5.快速排序.py: -------------------------------------------------------------------------------- 1 | def partition(arr, low, high): 2 | i = (low - 1) # 最小元素索引 3 | pivot = arr[high] 4 | for j in range(low, high): 5 | # 当前元素小于或等于 pivot 6 | if arr[j] <= pivot: 7 | i = i + 1 8 | arr[i], arr[j] = arr[j], arr[i] 9 | arr[i + 1], arr[high] = arr[high], arr[i + 1] 10 | print(arr) 11 | return (i + 1) 12 | 13 | 14 | # arr[] --> 排序数组 15 | # low --> 起始索引 16 | # high --> 结束索引 17 | 18 | # 快速排序函数 19 | def quick_sort(arr, low, high): 20 | if low < high: 21 | pi = partition(arr, low, high) 22 | quick_sort(arr, low, pi - 1) 23 | quick_sort(arr, pi + 1, high) 24 | 25 | 26 | if __name__ == '__main__': 27 | arr = [10, 7, 8, 9, 1, 5] 28 | quick_sort(arr, 0, len(arr) - 1) 29 | print("排序后的数组:", arr) 30 | -------------------------------------------------------------------------------- /test-algorithms/interview/z6.快速排序2.py: -------------------------------------------------------------------------------- 1 | def quick_sort(lists, i, j): 2 | if i >= j: 3 | return lists 4 | pivot = lists[i] 5 | low = i 6 | high = j 7 | while i < j: 8 | while i < j and lists[j] >= pivot: 9 | j -= 1 10 | lists[i] = lists[j] 11 | while i < j and lists[i] <= pivot: 12 | i += 1 13 | lists[j] = lists[i] 14 | lists[j] = pivot 15 | quick_sort(lists, low, i-1) 16 | quick_sort(lists, i+1, high) 17 | return lists 18 | 19 | 20 | if __name__ == "__main__": 21 | lists = [30,24,5,58,18,36,12,42,39] 22 | print("排序前的序列为:") 23 | for i in lists: 24 | print(i,end =" ") 25 | print("\n排序后的序列为:") 26 | for i in quick_sort(lists,0,len(lists)-1): 27 | print(i,end=" ") -------------------------------------------------------------------------------- /test-algorithms/interview/z8.最大价值.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | 你要去环游世界了!如果可能的话,你肯定想往背包里塞无数东西,但航空公司有规定,行李不能超过一定重量。 4 | 为了确保带上旅行中最有价值的物品,你决定给所有物品打分,来表示这些物品的价值。你想要让带的东西具备最大的价值。 5 | 实现一个函数,来计算背包能携带的最大物品价值。函数参数由三个数组组成,第一个是得分,第二个是权重。两个参数总是等长的有效数组,因此不用验证输入。第三个参数是背包不能超过的最大重量。 6 | 例如,给定这些输入: 7 | scores = [15, 10, 9, 5] 8 | weights = [1, 5, 3, 4] 9 | capacity = 8 10 | 最高分为29,来自于第1、3和4项。 11 | """ 12 | 13 | def solution(scores, weights, capacity): 14 | result = 0 15 | pre = 0 16 | for w,s in zip(weights, scores): 17 | 18 | 19 | 20 | print(solution([15, 10, 9, 5], [1, 5, 3, 4], 8)) -------------------------------------------------------------------------------- /test-algorithms/tests/test_histogram.py: -------------------------------------------------------------------------------- 1 | from algorithms.distribution.histogram import get_histogram 2 | 3 | import unittest 4 | 5 | 6 | class TestListsInHistogram(unittest.TestCase): 7 | def test_histogram(self): 8 | list_1 = [3, 3, 2, 1] 9 | list_2 = [2, 3, 5, 5, 5, 6, 4, 3, 7] 10 | 11 | self.assertEqual(get_histogram(list_1), {1: 1, 2: 1, 3: 2}) 12 | self.assertEqual(get_histogram(list_2), 13 | {2: 1, 3: 2, 4: 1, 5: 3, 6: 1, 7: 1}) 14 | 15 | 16 | if __name__ == '__main__': 17 | unittest.main() 18 | -------------------------------------------------------------------------------- /test-algorithms/tests/test_set.py: -------------------------------------------------------------------------------- 1 | from algorithms.set import ( 2 | find_keyboard_row 3 | ) 4 | 5 | import unittest 6 | 7 | class TestFindKeyboardRow(unittest.TestCase): 8 | def test_find_keyboard_row(self): 9 | self.assertEqual(["Alaska", "Dad"], 10 | find_keyboard_row(["Hello", "Alaska", "Dad", "Peace"])) 11 | -------------------------------------------------------------------------------- /test-algorithms/tests/test_sqrt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | @author: jayzhen 6 | @email: jayzhen_testing@163.com 7 | @site: https://github.com/gitjayzhen 8 | @software: PyCharm & Python 3.7 9 | @file: test_sqrt 10 | @time: 4/9/21 7:01 PM 11 | """ 12 | import math 13 | 14 | 15 | def sqrt(x): 16 | 17 | a = math.sqrt(x) 18 | print(int(a)) 19 | print(round(a)) 20 | 21 | 22 | if __name__ == '__main__': 23 | sqrt(3) 24 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/owl/e444919bdc1547e0458f24cf955a822b4c815539/tests/__init__.py -------------------------------------------------------------------------------- /tests/configs/appium-service.ini: -------------------------------------------------------------------------------- 1 | [emulator-5554] 2 | run = 0 3 | emulator-5554 = 4490 4 | bp = 2233 5 | 6 | [90d1894b] 7 | 90d1894b = 4490 8 | bp = 2233 9 | run = 0 10 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: conftest.py 8 | @time: 2024/4/8 11:33 9 | """ 10 | 11 | import pytest 12 | 13 | 14 | @pytest.fixture(scope='session', autouse=True) 15 | def init_data(): 16 | """ 17 | 初始化,获取session 18 | :return: 19 | """ 20 | print(f'test init data') 21 | 22 | 23 | def pytest_collection_modifyitems(items): 24 | """ 25 | 测试用例收集完成时,将收集到的 item 的 name 和 nodeid 的中文显示在控制台上,防止 pytest-html 报告中文乱码 26 | """ 27 | for item in items: 28 | item.name = item.name 29 | item._nodeid = item.nodeid -------------------------------------------------------------------------------- /tests/data/interface-test-case.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/owl/e444919bdc1547e0458f24cf955a822b4c815539/tests/data/interface-test-case.xlsx -------------------------------------------------------------------------------- /tests/data/users-login-case.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitjayzhen/owl/e444919bdc1547e0458f24cf955a822b4c815539/tests/data/users-login-case.xls -------------------------------------------------------------------------------- /tests/owl/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @version: 1.0.0 5 | @license: Apache Licence 6 | @software: PyCharm & Python 3.7+ 7 | @file: __init__.py 8 | @time: 2023/9/4 15:28 9 | """ 10 | -------------------------------------------------------------------------------- /tests/owl/appium/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: __init__.py 8 | @time: 2024/3/29 16:50 9 | """ 10 | -------------------------------------------------------------------------------- /tests/owl/appium/test_appium_case.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @software: PyCharm & Python 3.7+ 7 | @file: test_appium_case.py 8 | @time: 2023/8/17 14:10 9 | """ 10 | import pytest 11 | from appium.webdriver.common.mobileby import MobileBy 12 | 13 | from owl.api.mobile.base_testcase import BaseTestCase 14 | 15 | 16 | class TestAppiumBaseApi(BaseTestCase): 17 | """ 18 | emulator -avd Nexus_5X_API_23 -netdelay none -netspeed full 19 | """ 20 | 21 | # @pytest.mark.skip("skip 'test_is_displayed' func") 22 | def test_is_displayed(self): 23 | print(self.driver.is_displayed(MobileBy.ID, "com.youku.phone:id/img_user")) 24 | 25 | @pytest.mark.skip("skip 'test_find_element_by_want' func") 26 | def test_find_element_by_want(self): 27 | print(self.driver.find_element_by_want(MobileBy.ID, "com.youku.phone:id/img_user", 5)) 28 | 29 | def test_get_current_activity(self): 30 | print(self.driver.get_current_activity()) 31 | -------------------------------------------------------------------------------- /tests/owl/selenium/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: __init__.py 8 | @time: 2024/3/28 15:24 9 | """ 10 | -------------------------------------------------------------------------------- /tests/owl/selenium/docker/chrome-119: -------------------------------------------------------------------------------- 1 | FROM selenium/standalone-chrome:latest 2 | 3 | USER root 4 | RUN echo 'echo "webdriver-executable = \"/opt/selenium/chromedriver-120.0.6099.71\"" >> "$FILENAME"' >> /opt/bin/generate_config 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/owl/selenium/docker/custom-chrome: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/amd64 python:3.10 2 | # https://github.com/SeleniumHQ/docker-selenium/blob/trunk/NodeChrome/Dockerfile 3 | 4 | # Install Chrome browser dependencies 5 | RUN apt-get update && \ 6 | apt-get install -y \ 7 | curl \ 8 | wget \ 9 | gnupg \ 10 | unzip \ 11 | fonts-liberation 12 | 13 | # Download and install Chrome browser 14 | RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - 15 | RUN sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' 16 | RUN apt-get -y update 17 | RUN apt-get install -y google-chrome-stable 18 | 19 | # Install specific version of chromedriver 20 | RUN CHROME_DRIVER_VERSION=120.0.6099.71 && \ 21 | wget --no-verbose -O /tmp/chromedriver.zip https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/$CHROME_DRIVER_VERSION/linux64/chromedriver-linux64.zip && \ 22 | unzip /tmp/chromedriver.zip -d /usr/local/bin && \ 23 | rm /tmp/chromedriver.zip 24 | 25 | # Install Selenium and other required packages 26 | RUN pip install selenium -------------------------------------------------------------------------------- /tests/owl/selenium/docker/dockerfile: -------------------------------------------------------------------------------- 1 | ARG NAMESPACE 2 | ARG VERSION 3 | ARG AUTHORS 4 | ARG BASE 5 | FROM ${NAMESPACE}/${BASE}:${VERSION} 6 | LABEL authors=${AUTHORS} 7 | 8 | USER 1200 9 | 10 | #==================================== 11 | # Scripts to run Selenium Standalone 12 | #==================================== 13 | COPY start-selenium-standalone.sh /opt/bin/start-selenium-standalone.sh 14 | 15 | #============================== 16 | # Supervisor configuration file 17 | #============================== 18 | COPY selenium.conf /etc/supervisor/conf.d/ 19 | 20 | # Copying configuration script generator 21 | COPY generate_config /opt/bin/generate_config 22 | 23 | # Boolean value, maps "--relax-checks" 24 | ENV SE_RELAX_CHECKS true 25 | 26 | EXPOSE 4444 27 | 28 | -------------------------------------------------------------------------------- /tests/owl/selenium/docker/start-selenium-server-alone.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # IMPORTANT: Change this file only in directory Standalone! 4 | 5 | if [ ! -z "$SE_SUB_PATH" ]; then 6 | echo "Using SE_SUB_PATH: ${SE_SUB_PATH}" 7 | SUB_PATH_CONFIG="--sub-path ${SE_SUB_PATH}" 8 | fi 9 | 10 | if [ ! -z "$SE_OPTS" ]; then 11 | echo "Appending Selenium options: ${SE_OPTS}" 12 | fi 13 | 14 | /opt/bin/generate_config 15 | 16 | echo "Selenium Grid Standalone configuration: " 17 | cat /opt/docker/config.toml 18 | echo "Starting Selenium Grid Standalone..." 19 | 20 | EXTRA_LIBS="/opt/selenium/selenium-http-jdk-client.jar" 21 | 22 | if [ ! -z "$SE_ENABLE_TRACING" ]; then 23 | EXTERNAL_JARS=$( se.log 2>&1 & -------------------------------------------------------------------------------- /tests/owl/selenium/test_selenium_case.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | @author: jayzhen 6 | @file: test_selenium_case.py 7 | @time: 2023/3/25 12:49 8 | """ 9 | import time 10 | 11 | from owl.api.browser.base_testcase import BaseTestCase 12 | from owl.domain.selector_enum import FindBy 13 | 14 | 15 | class TestSeleniumInLocal(BaseTestCase): 16 | 17 | def test_local_webdriver_run(self): 18 | self.driver.get("https://baidu.com") 19 | self.driver.send_keys(FindBy.CSS_SELECTOR, "#kw", "jayzhen") 20 | self.driver.click(FindBy.CSS_SELECTOR, "#su") 21 | time.sleep(5) 22 | self.driver.capture() 23 | -------------------------------------------------------------------------------- /tests/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | markers = 3 | smoke : 'smoke test' 4 | regression : 'regression test' 5 | 6 | addopts = --strict-markers -------------------------------------------------------------------------------- /tests/run_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: jayzhen 5 | @license: Apache Licence 6 | @version: Python 3.8+ 7 | @file: run_test.py 8 | @time: 2024/4/8 11:32 9 | """ 10 | 11 | import os 12 | import shutil 13 | import pytest 14 | 15 | config = object() 16 | 17 | 18 | def run_cases(): 19 | # if os.path.exists(config.log_path): 20 | # shutil.rmtree(config.log_path) 21 | # 22 | # if os.path.exists(config.report_path): 23 | # shutil.rmtree(config.report_path) 24 | 25 | pytest.main(['./test_http_one.py', './owl/test_file_inspector.py', '-sv', '--reruns=2', '--alluredir=logs/report', '--clean-alluredir']) 26 | os.system('allure generate logs/report -o logs/html --clean') 27 | os.system('allure serve logs/report') 28 | 29 | 30 | if __name__ == '__main__': 31 | run_cases() 32 | --------------------------------------------------------------------------------