├── .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 |
--------------------------------------------------------------------------------