├── .gitignore ├── .travis.yml ├── CNAME ├── LANGS.md ├── README.md ├── book.json ├── codes └── algorithm-java │ ├── .gitignore │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── basic │ │ │ └── DataStructure.java │ └── resources │ │ └── log4j.properties │ └── test │ └── java │ └── basic │ ├── DataStructureTest.java │ ├── QueueTest.java │ └── StackTest.java ├── conf ├── 10-latin.conf ├── 15-noto-cjksc.conf ├── 20-noto-cjk.conf └── qiniu_sync.json ├── contributing.md ├── cover.jpg ├── cover_small.jpg ├── en ├── README.md ├── SUMMARY.md ├── basics_data_structure │ ├── README.md │ └── string.md ├── basics_sorting │ └── quick_sort.md ├── binary_search │ └── search_in_rotated_sorted_array.md ├── cover.jpg ├── cover_small.jpg ├── faq │ ├── README.md │ └── guidelines_for_contributing.md ├── integer_array │ ├── kth_largest_element.md │ └── partition_array_by_odd_and_even.md ├── linked_list │ ├── README.md │ └── reverse_linked_list.md ├── part_i_basics │ └── README.md ├── string │ ├── README.md │ └── strstr.md ├── styles │ └── website.css └── tags.md ├── scripts ├── check_summary.py ├── gitls.sh ├── main.py ├── parse_md.py ├── rename_ebook.sh ├── sitemap │ ├── __init__.py │ └── templates │ │ └── sitemap.xml ├── sitemap_gen.py └── util.py ├── shared-files ├── README.md ├── SUMMARY.md ├── docs │ └── oj_templates │ │ └── cpp_templates.cpp └── images │ ├── Binary-reflected_Gray_code_construction.png │ ├── Heapsort-example.gif │ ├── alipay_billryan_qr15x15.jpg │ ├── binary_tree_summary.png │ ├── binary_tree_traversal.png │ ├── bipatial_graph_part_i_1.png │ ├── bipatial_graph_part_i_2.png │ ├── bubble_sort.gif │ ├── copy_list_with_random_pointer.jpg │ ├── gitbook_editor.png │ ├── huffman_algorithm.gif │ ├── insertion_sort.gif │ ├── insertion_sort_list.png │ ├── linked_list_cycle.png │ ├── linked_list_cycle_ii.png │ ├── linked_list_summary.png │ ├── linked_list_summary_en.png │ ├── merge_sort.gif │ ├── problem_b_professor_qs_software.png │ ├── qsort1.png │ ├── qsort2.png │ ├── qsort3.gif │ ├── remove_duplicates_from_sorted_list.jpg │ ├── resume-zh_CN.png │ ├── reverse_linked_list_i.jpg │ ├── rotated_array.png │ ├── selection_sort.gif │ ├── subsets.jpg │ ├── topological-sorting.jpeg │ ├── topological_sorting.jpeg │ ├── tree_diameter.gif │ ├── valid-sudoku.png │ └── wechat_billryan_qr15x15.jpg ├── zh-hans ├── GLOSSARY.md ├── README.md ├── SUMMARY.md ├── appendix_i_interview_and_resume │ ├── README.md │ ├── interview.md │ └── resume.md ├── basics_algorithm │ ├── README.md │ ├── binary_search.md │ ├── bitmap.md │ ├── divide_and_conquer.md │ ├── knapsack.md │ ├── math │ │ ├── README.md │ │ ├── gcd.md │ │ └── prime.md │ └── probability │ │ ├── README.md │ │ └── shuffle.md ├── basics_data_structure │ ├── README.md │ ├── binary_tree.md │ ├── graph.md │ ├── heap.md │ ├── huffman_compression.md │ ├── linked_list.md │ ├── map.md │ ├── queue.md │ ├── set.md │ ├── stack.md │ └── string.md ├── basics_misc │ ├── README.md │ └── bit_manipulation.md ├── basics_sorting │ ├── README.md │ ├── bubble_sort.md │ ├── bucket_sort.md │ ├── counting_sort.md │ ├── heap_sort.md │ ├── insertion_sort.md │ ├── merge_sort.md │ ├── quick_sort.md │ ├── radix_sort.md │ └── selection_sort.md ├── bigdata │ ├── README.md │ ├── k_closest_points.md │ ├── top_k_frequent_words.md │ ├── top_k_frequent_words_ii.md │ ├── top_k_frequent_words_map_reduce.md │ ├── top_k_largest_numbers.md │ └── top_k_largest_numbers_ii.md ├── binary_search │ ├── README.md │ ├── find_minimum_in_rotated_sorted_array.md │ ├── find_minimum_in_rotated_sorted_array_ii.md │ ├── find_peak_element.md │ ├── first_bad_version.md │ ├── first_position_of_target.md │ ├── median_of_two_sorted_arrays.md │ ├── search_a_2d_matrix.md │ ├── search_a_2d_matrix_ii.md │ ├── search_for_a_range.md │ ├── search_in_rotated_sorted_array.md │ ├── search_in_rotated_sorted_array_ii.md │ ├── search_insert_position.md │ ├── sqrt_x.md │ └── wood_cut.md ├── binary_search_tree │ ├── README.md │ ├── binary_search_tree_iterator.md │ ├── convert_sorted_array_to_binary_search_tree.md │ ├── convert_sorted_list_to_binary_search_tree.md │ ├── insert_node_in_a_binary_search_tree.md │ ├── minimum_absolute_difference_in_bst.md │ ├── search_range_in_binary_search_tree.md │ └── validate_binary_search_tree.md ├── binary_tree │ ├── README.md │ ├── balanced_binary_tree.md │ ├── binary_tree_inorder_traversal.md │ ├── binary_tree_level_order_traversal.md │ ├── binary_tree_level_order_traversal_ii.md │ ├── binary_tree_maximum_path_sum.md │ ├── binary_tree_postorder_traversal.md │ ├── binary_tree_preorder_traversal.md │ ├── binary_tree_serialization.md │ ├── binary_tree_zigzag_level_order_traversal.md │ ├── construct_binary_tree_from_inorder_and_postorder_traversal.md │ ├── construct_binary_tree_from_preorder_and_inorder_traversal.md │ ├── diameter_of_a_binary_tree.md │ ├── invert_binary_tree.md │ ├── lowest_common_ancestor.md │ ├── maximum_depth_of_binary_tree.md │ └── subtree.md ├── cover.jpg ├── cover_small.jpg ├── data_structure │ ├── README.md │ ├── heapify.md │ ├── implement_queue_by_two_stacks.md │ ├── longest_words.md │ ├── min_stack.md │ └── sliding_window_maximum.md ├── dynamic_programming │ ├── README.md │ ├── backpack.md │ ├── backpack_ii.md │ ├── best_time_to_buy_and_sell_stock.md │ ├── best_time_to_buy_and_sell_stock_ii.md │ ├── best_time_to_buy_and_sell_stock_iii.md │ ├── best_time_to_buy_and_sell_stock_iv.md │ ├── climbing_stairs.md │ ├── distinct_subsequences.md │ ├── edit_distance.md │ ├── interleaving_string.md │ ├── jump_game.md │ ├── jump_game_ii.md │ ├── longest_common_subsequence.md │ ├── longest_increasing_continuous_subsequence.md │ ├── longest_increasing_continuous_subsequence_ii.md │ ├── longest_increasing_subsequence.md │ ├── matrix.md │ ├── maximal_square.md │ ├── maximum_subarray.md │ ├── maximum_subarray_ii.md │ ├── minimum_path_sum.md │ ├── palindrome_partitioning_ii.md │ ├── triangle.md │ ├── unique_paths.md │ ├── unique_paths_ii.md │ └── word_break.md ├── exhaustive_search │ ├── README.md │ ├── combination_sum.md │ ├── combination_sum_ii.md │ ├── combinations.md │ ├── minimum_depth_of_binary_tree.md │ ├── next_permutation.md │ ├── palindrome_partitioning.md │ ├── permutation_index.md │ ├── permutation_index_ii.md │ ├── permutation_sequence.md │ ├── permutations.md │ ├── permutations_ii.md │ ├── previous_permuation.md │ ├── subsets.md │ ├── unique_binary_search_trees_ii.md │ ├── unique_subsets.md │ └── word_search.md ├── faq │ ├── README.md │ └── guidelines_for_contributing.md ├── google_apac │ ├── README.md │ ├── google_apac_2015_round_b │ │ ├── A-large-practice.in │ │ ├── A-small-practice.in │ │ ├── README.md │ │ ├── Solution.java │ │ └── problem_a_password_attacker.md │ └── google_apac_2016_round_d │ │ ├── A-large-practice.in │ │ ├── A-small-practice.in │ │ ├── README.md │ │ ├── Solution.java │ │ └── problem_a_dynamic_grid.md ├── graph │ ├── README.md │ ├── bipartial_graph_part_i.md │ ├── find_the_connected_component_in_the_undirected_graph.md │ ├── route_between_two_nodes_in_graph.md │ ├── topological_sorting.md │ └── word_ladder.md ├── integer_array │ ├── 2_sum.md │ ├── 3_sum.md │ ├── 3_sum_closest.md │ ├── README.md │ ├── first_missing_positive.md │ ├── kth_largest_element.md │ ├── median.md │ ├── merge_sorted_array.md │ ├── merge_sorted_array_ii.md │ ├── partition_array.md │ ├── partition_array_by_odd_and_even.md │ ├── product_of_array_exclude_itself.md │ ├── recover_rotated_sorted_array.md │ ├── remove_duplicates_from_sorted_array.md │ ├── remove_duplicates_from_sorted_array_ii.md │ ├── remove_element.md │ ├── subarray_sum_closest.md │ ├── subarray_sum_k.md │ └── zero_sum_subarray.md ├── interview │ ├── facebook_interview.md │ └── google_interview.md ├── linked_list │ ├── README.md │ ├── add_two_numbers.md │ ├── copy_list_with_random_pointer.md │ ├── insertion_sort_list.md │ ├── linked_list_cycle.md │ ├── linked_list_cycle_ii.md │ ├── lru_cache.md │ ├── merge_k_sorted_lists.md │ ├── merge_two_sorted_lists.md │ ├── palindrome_linked_list.md │ ├── partition_list.md │ ├── remove_duplicates_from_an_unsorted_linked_list.md │ ├── remove_duplicates_from_sorted_list.md │ ├── remove_duplicates_from_sorted_list_ii.md │ ├── remove_linked_list_elements.md │ ├── remove_nth_node_from_end_of_list.md │ ├── reorder_list.md │ ├── reverse_linked_list.md │ ├── reverse_linked_list_ii.md │ ├── rotate_list.md │ ├── sort_list.md │ ├── swap_nodes_in_pairs.md │ └── two_lists_sum_advanced.md ├── math_and_bit_manipulation │ ├── README.md │ ├── a_plus_b_problem.md │ ├── count_1_in_binary.md │ ├── digit_counts.md │ ├── factorial_trailing_zeroes.md │ ├── fast_power.md │ ├── fibonacci.md │ ├── flip_bits.md │ ├── happy_number.md │ ├── hash_function.md │ ├── majority_number.md │ ├── majority_number_ii.md │ ├── majority_number_iii.md │ ├── o1_check_power_of_2.md │ ├── palindrome_number.md │ ├── plus_one.md │ ├── print_numbers_by_recursion.md │ ├── single_number.md │ ├── single_number_ii.md │ ├── single_number_iii.md │ ├── task_scheduler.md │ ├── ugly_number.md │ ├── unique_binary_search_trees.md │ └── update_bits.md ├── microsoft │ ├── README.md │ ├── mstest2015april │ │ ├── README.md │ │ ├── problem_a_magic_box.md │ │ ├── problem_b_professor_qs_software.md │ │ ├── problem_c_islands_travel.md │ │ └── problem_d_recruitment.md │ ├── mstest2015april2 │ │ ├── README.md │ │ ├── problem_a_lucky_substrings.md │ │ ├── problem_b_numeric_keypad.md │ │ └── problem_c_spring_outing.md │ └── mstest2015sept2 │ │ ├── README.md │ │ └── problem_a_farthest_point.md ├── part_i_basics │ └── README.md ├── part_ii_coding │ └── README.md ├── part_iii_contest │ └── README.md ├── problem_misc │ ├── README.md │ ├── add_binary.md │ ├── continuous_subarray_sum.md │ ├── continuous_subarray_sum_ii.md │ ├── find_the_missing_number.md │ ├── gray_code.md │ ├── insert_interval.md │ ├── longest_consecutive_sequence.md │ ├── matrix_zigzag_traversal.md │ ├── merge_intervals.md │ ├── minimum_subarray.md │ ├── minimum_window_substring.md │ ├── nuts_and_bolts_problem.md │ ├── reverse_integer.md │ ├── string_to_integer.md │ └── valid_sudoku.md ├── string │ ├── README.md │ ├── compare_strings.md │ ├── count_and_say.md │ ├── group_anagrams.md │ ├── length_of_last_word.md │ ├── longest_common_substring.md │ ├── longest_palindromic_substring.md │ ├── reverse_words_in_a_string.md │ ├── rotate_string.md │ ├── space_replacement.md │ ├── strstr.md │ ├── two_strings_are_anagrams.md │ ├── valid_palindrome.md │ └── wildcard_matching.md ├── styles │ └── website.css └── tags.md └── zh-tw ├── README.md ├── SUMMARY.md ├── appendix_i_interview_and_resume └── README.md ├── basics_algorithm ├── README.md ├── binary_search.md ├── bitmap.md ├── divide_and_conquer.md ├── math │ ├── README.md │ ├── gcd.md │ └── prime.md └── probability │ ├── README.md │ └── shuffle.md ├── basics_data_structure ├── README.md ├── binary_tree.md ├── graph.md ├── heap.md ├── huffman_compression.md ├── linked_list.md ├── map.md ├── priority_queue.md ├── queue.md ├── set.md ├── stack.md └── string.md ├── basics_misc ├── README.md └── bit_manipulation.md ├── basics_sorting ├── README.md ├── bubble_sort.md ├── bucket_sort.md ├── counting_sort.md ├── heap_sort.md ├── insertion_sort.md ├── merge_sort.md ├── radix_sort.md └── selection_sort.md ├── binary_search ├── README.md ├── binary_search.md ├── find_peak_element.md ├── first_bad_version.md ├── search_for_a_range.md ├── search_insert_position.md └── sqrt_x.md ├── binary_search_tree ├── README.md └── insert_node_in_a_binary_search_tree.md ├── binary_tree ├── README.md ├── binary_tree_inorder_traversal.md ├── binary_tree_level_order_traversal.md ├── binary_tree_level_order_traversal_ii.md ├── binary_tree_postorder_traversal.md ├── binary_tree_preorder_traversal.md ├── invert_binary_tree.md └── maximum_depth_of_binary_tree.md ├── cover.jpg ├── cover_small.jpg ├── data_structure └── README.md ├── dynamic_programming ├── README.md ├── backpack.md ├── climbing_stairs.md └── triangle.md ├── exhaustive_search ├── README.md ├── minimum_depth_of_binary_tree.md ├── next_permutation.md └── subsets.md ├── faq ├── README.md └── guidelines_for_contributing.md ├── graph └── README.md ├── integer_array ├── 2_sum.md ├── 3_sum.md ├── 3_sum_closest.md ├── README.md ├── first_missing_positive.md ├── merge_sorted_array.md ├── merge_sorted_array_ii.md ├── remove_duplicates_from_sorted_array.md ├── remove_duplicates_from_sorted_array_ii.md └── remove_element.md ├── linked_list ├── README.md ├── linked_list_cycle.md ├── merge_two_sorted_lists.md ├── remove_duplicates_from_sorted_list.md ├── remove_duplicates_from_sorted_list_ii.md ├── remove_linked_list_elements.md ├── reverse_linked_list.md └── two_lists_sum.md ├── math_and_bit_manipulation ├── a_plus_b_problem.md ├── count_1_in_binary.md └── plus_one.md ├── part_i_basics └── README.md ├── part_ii_coding └── README.md ├── part_iii_contest └── README.md ├── problem_misc ├── README.md ├── add_binary.md ├── find_the_missing_number.md ├── minimum_subarray.md ├── reverse_integer.md ├── string_to_integer.md └── valid_sudoku.md ├── string ├── README.md ├── compare_strings.md ├── count_and_say.md ├── longest_palindromic_substring.md ├── rotate_string.md ├── space_replacement.md ├── strstr.md ├── two_strings_are_anagrams.md └── valid_palindrome.md ├── styles └── website.css └── tags.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | *.log 14 | 15 | # MAC OS X 16 | **/.DS_Store 17 | 18 | # Python 19 | *.py[cod] 20 | *$py.class 21 | .python-version 22 | 23 | # Auth 24 | ####### 25 | scripts/auth.conf 26 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | algorithm.yuanbin.me 2 | -------------------------------------------------------------------------------- /LANGS.md: -------------------------------------------------------------------------------- 1 | * [English](en/) 2 | * [繁體中文](zh-tw/) 3 | * [简体中文](zh-hans/) 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Data Structure and Algorithm/leetcode/lintcode 2 | 3 | [![Build Status](https://travis-ci.org/billryan/algorithm-exercise.svg?branch=master)](https://travis-ci.org/billryan/algorithm-exercise) 4 | [![Slack Status](https://slackin4ds-algo.herokuapp.com/badge.svg)](https://slackin4ds-algo.herokuapp.com/) 5 | [![Chat on Slack](https://img.shields.io/badge/chat-on_slack-orange.svg)](https://ds-algo.slack.com/) 6 | 7 | This book is notes about learning data structure and algorithm. It was written in Simplified Chinese but other languages such as English and Traditional Chinese are also working in progress. Contributions are welcome! 8 | 9 | - [English](https://algorithm.yuanbin.me/en/), rarely updated 10 | - [简体中文](https://algorithm.yuanbin.me/zh-hans/), frequently updated 11 | - [繁體中文](https://algorithm.yuanbin.me/zh-tw/), rarely updated 12 | 13 | ## Introduction 14 | 15 | 1. Part I is some brief introduction of basic data structures and algorithm, such as linked lists, stack, queues, trees, sorting. 16 | 2. Part II is the analysis and summary of programming problems, and most of the programming problems come from , , , , . 17 | 3. Part III is the appendix of resume and other supplements. 18 | 19 | This project is hosted on and rendered by [GitBook](https://www.gitbook.com/book/yuanbin/algorithm/details). You can star the repository on the GitHub to keep track of updates. Another choice is to subscribe channel `#github_commit` via Slack . 20 | 21 | Feel free to access with Slack invite automation. 22 | 23 | You can view/search this document online or offline, feel free to read it. :) 24 | 25 | - Online(Rendered by GitBook): 26 | - Site Search via Google: `keywords site:algorithm.yuanbin.me` 27 | - Site Search via Algolia: Click `Type to search` on the top left corner of webpages 28 | - Offline(Compiled by GitBook on Travis-CI): ePub, PDF, MOBI 29 | 30 | ## License 31 | 32 | This work is licensed under the **Creative Commons Attribution-ShareAlike 4.0 International License**. To view a copy of this license, please visit 33 | 34 | ## To Do 35 | 36 | - [ ] add multiple languages support 37 | - [ ] add implementations of `Python`, `C++`, `Go` and `Java` code 38 | - [x] add time and space complexity analysis 39 | - [x] add proper Chinese fonts for PDF output 40 | -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "disqus", 4 | "ga", 5 | "katex", 6 | "richquotes", 7 | "sitemap2", 8 | "github", 9 | "edit-link", 10 | "feed", 11 | "etoc", 12 | "algolia", 13 | "tags" 14 | ], 15 | "pluginsConfig": { 16 | "disqus": { 17 | "shortName": "algorithm4bill" 18 | }, 19 | "ga": { 20 | "token": "UA-32317667-7" 21 | }, 22 | "richquotes": { 23 | "todos": true 24 | }, 25 | "sitemap2": { 26 | "hostname": "http://algorithm.yuanbin.me/" 27 | }, 28 | "github": { 29 | "url": "https://github.com/billryan/algorithm-exercise" 30 | }, 31 | "edit-link": { 32 | "base": "https://github.com/billryan/algorithm-exercise/edit/master", 33 | "label": { 34 | "en": "Edit Page", 35 | "zh-hans": "编辑此页", 36 | "zh-tw": "編輯此頁" 37 | } 38 | }, 39 | "feed": { 40 | "title": "Data Structure and Algorithm notes", 41 | "description": "Data Structure and Algorithm notes/数据结构与算法学习笔记/leetcode/lintcode 题解", 42 | "hostname": "https://algorithm.yuanbin.me", 43 | "author": "billryan", 44 | "categories": [ 45 | "programming", 46 | "algorithm", 47 | "leetcode" 48 | ] 49 | }, 50 | "algolia": { 51 | "index": "algorithm", 52 | "applicationID": "9YBMOZR89J", 53 | "publicKey": "5860a3e55ee72831917b1b9e2a4649ca", 54 | "freeAccount": "true" 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /codes/algorithm-java/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .idea/ 3 | *.iml 4 | project/ 5 | 6 | out/ 7 | target/ 8 | 9 | .DS_Store 10 | 11 | -------------------------------------------------------------------------------- /codes/algorithm-java/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | me.yuanbin 8 | algorithm-java 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 1.8 13 | 1.8 14 | 4.12 15 | 1.7.25 16 | 1.18.8 17 | 18 | 19 | 20 | 21 | org.projectlombok 22 | lombok 23 | ${lombok.version} 24 | provided 25 | 26 | 27 | 28 | org.slf4j 29 | slf4j-log4j12 30 | ${slf4j.version} 31 | provided 32 | 33 | 34 | 35 | junit 36 | junit 37 | ${junit.version} 38 | test 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-compiler-plugin 48 | 3.8.1 49 | 50 | 51 | 52 | org.apache.maven.plugins 53 | maven-shade-plugin 54 | 3.2.1 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /codes/algorithm-java/src/main/java/basic/DataStructure.java: -------------------------------------------------------------------------------- 1 | package basic; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | 6 | import java.util.ArrayDeque; 7 | import java.util.Deque; 8 | import java.util.LinkedList; 9 | import java.util.Queue; 10 | 11 | /** 12 | * Basic data structure including queue, stack, graph... 13 | * 14 | * @author billryan 15 | * @date 2019-06-22 16 | */ 17 | @Data 18 | @NoArgsConstructor 19 | public class DataStructure { 20 | private Queue queue = new LinkedList<>(); 21 | private Deque stack = new ArrayDeque<>(); 22 | } 23 | -------------------------------------------------------------------------------- /codes/algorithm-java/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | # By default, everything goes to console and file 3 | log4j.rootLogger=INFO, stdout 4 | 5 | # Direct log messages to stdout 6 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 7 | log4j.appender.stdout.Target=System.out 8 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 9 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 10 | -------------------------------------------------------------------------------- /codes/algorithm-java/src/test/java/basic/DataStructureTest.java: -------------------------------------------------------------------------------- 1 | package basic; 2 | 3 | import org.junit.Test; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | /** 8 | * @author billryan 9 | * @date 10/8/2019 10:59 10 | */ 11 | public class DataStructureTest { 12 | 13 | private static final Logger log = LoggerFactory.getLogger(DataStructureTest.class); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /codes/algorithm-java/src/test/java/basic/QueueTest.java: -------------------------------------------------------------------------------- 1 | package basic; 2 | 3 | import org.junit.Test; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.LinkedList; 8 | import java.util.Queue; 9 | 10 | /** 11 | * @author billryan 12 | * @date 10/8/2019 12:05 13 | */ 14 | public class QueueTest { 15 | 16 | private static final Logger log = LoggerFactory.getLogger(QueueTest.class); 17 | 18 | @Test 19 | public void testQueue() { 20 | Queue queue = new LinkedList<>(); 21 | queue.offer(1); 22 | queue.offer(2); 23 | queue.offer(3); 24 | 25 | int peek = 1; 26 | while (!queue.isEmpty()) { 27 | int queuePeek = queue.poll(); 28 | log.info("queue peek: {}", queuePeek); 29 | assert peek == queuePeek; 30 | peek++; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /codes/algorithm-java/src/test/java/basic/StackTest.java: -------------------------------------------------------------------------------- 1 | package basic; 2 | 3 | import org.junit.Test; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.ArrayDeque; 8 | import java.util.Deque; 9 | 10 | /** 11 | * @author billryan 12 | * @date 10/8/2019 12:04 13 | */ 14 | public class StackTest { 15 | 16 | private static final Logger log = LoggerFactory.getLogger(StackTest.class); 17 | 18 | @Test 19 | public void testStack() { 20 | Deque stack = new ArrayDeque<>(); 21 | stack.push(1); 22 | stack.push(2); 23 | stack.push(3); 24 | 25 | int peek = 3; 26 | while (!stack.isEmpty()) { 27 | int stackPeek = stack.pop(); 28 | log.info("stack peek: {}", stackPeek); 29 | assert peek == stackPeek; 30 | peek--; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /conf/10-latin.conf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | serif 5 | 6 | 7 | Noto Serif 8 | Noto Sans 9 | 10 | 11 | 12 | 13 | 14 | sans-serif 15 | 16 | 17 | Noto Sans 18 | 19 | 20 | 21 | 22 | 23 | monospace 24 | 25 | 26 | Source Code Pro 27 | 28 | 29 | -------------------------------------------------------------------------------- /conf/15-noto-cjksc.conf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | serif 5 | 6 | 7 | Noto Sans CJK SC 8 | 9 | 10 | 11 | 12 | 13 | sans-serif 14 | 15 | 16 | Noto Sans CJK SC 17 | 18 | 19 | 20 | 21 | 22 | monospace 23 | 24 | 25 | Source Code Pro 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /conf/20-noto-cjk.conf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | serif 5 | 6 | 7 | Noto Sans T Chinese 8 | Noto Sans S Chinese 9 | Noto Sans Japanese 10 | Noto Sans Korean 11 | 12 | 13 | 14 | 15 | sans-serif 16 | 17 | 18 | Noto Sans T Chinese 19 | Noto Sans S Chinese 20 | Noto Sans Japanese 21 | Noto Sans Korean 22 | 23 | 24 | 25 | 26 | monospace 27 | 28 | 29 | Noto Sans T Chinese 30 | Noto Sans S Chinese 31 | Noto Sans Japanese 32 | Noto Sans Korean 33 | 34 | 35 | -------------------------------------------------------------------------------- /conf/qiniu_sync.json: -------------------------------------------------------------------------------- 1 | { 2 | "src": "/home/travis/upload", 3 | "dest": "qiniu:access_key=AccessKey&secret_key=SecretKey&bucket=pub4bill&key_prefix=docs/algorithm-exercise/", 4 | "deletable": 0, 5 | "debug_level": 1 6 | } 7 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Guidelines for Contributing 2 | 3 | - Access English via [Guidelines for Contributing](http://algorithm.yuanbin.me/en/faq/guidelines_for_contributing.html) 4 | - 繁體中文請移步 [貢獻指南](http://algorithm.yuanbin.me/zh-tw/faq/guidelines_for_contributing.html) 5 | - 简体中文请移步 [贡献指南](http://algorithm.yuanbin.me/zh-hans/faq/guidelines_for_contributing.html) 6 | -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/cover.jpg -------------------------------------------------------------------------------- /cover_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/cover_small.jpg -------------------------------------------------------------------------------- /en/basics_data_structure/README.md: -------------------------------------------------------------------------------- 1 | # Data Structure 2 | 3 | This chapter describes the fundamental data structures and their implementations. 4 | -------------------------------------------------------------------------------- /en/basics_data_structure/string.md: -------------------------------------------------------------------------------- 1 | # String 2 | 3 | String-related problems often appear in interview questions. In actual 4 | development, strings are also frequently used. Summarized here are common uses 5 | of strings in C++, Java, and Python. 6 | 7 | ## Python 8 | 9 | ```python 10 | s1 = str() 11 | # in python, `''` and `""` are the same 12 | s2 = "shaunwei" # 'shaunwei' 13 | s2len = len(s2) 14 | # last 3 chars 15 | s2[-3:] # wei 16 | s2[5:8] # wei 17 | s3 = s2[:5] # shaun 18 | s3 += 'wei' # return 'shaunwei' 19 | # list in python is same as ArrayList in java 20 | s2list = list(s3) 21 | # string at index 4 22 | s2[4] # 'n' 23 | # find index at first 24 | s2.index('w') # return 5, if not found, throw ValueError 25 | s2.find('w') # return 5, if not found, return -1 26 | ``` 27 | 28 | In Python, there's no StringBuffer or StringBuilder. However, string manipulations 29 | are fairly efficient already. 30 | 31 | ## Java 32 | 33 | ```java 34 | String s1 = new String(); 35 | String s2 = "billryan"; 36 | int s2Len = s2.length(); 37 | s2.substring(4, 8); // return "ryan" 38 | StringBuilder s3 = new StringBuilder(s2.substring(4, 8)); 39 | s3.append("bill"); 40 | String s2New = s3.toString(); // return "ryanbill" 41 | // convert String to char array 42 | char[] s2Char = s2.toCharArray(); 43 | // char at index 4 44 | char ch = s2.charAt(4); // return 'r' 45 | // find index at first 46 | int index = s2.indexOf('r'); // return 4. if not found, return -1 47 | ``` 48 | 49 | The difference between StringBuffer and StringBuilder is that the former guarantees 50 | thread safety. In a single-threaded environment, StringBuilder is more efficient. 51 | -------------------------------------------------------------------------------- /en/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/en/cover.jpg -------------------------------------------------------------------------------- /en/cover_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/en/cover_small.jpg -------------------------------------------------------------------------------- /en/faq/README.md: -------------------------------------------------------------------------------- 1 | # FAQ - Frequently Asked Question 2 | 3 | Some guidelines for contributing and other questions are listed here. 4 | 5 | ## How to Contribute? 6 | 7 | - Access [Guidelines for Contributing](http://algorithm.yuanbin.me/en/faq/guidelines_for_contributing.html) for details. 8 | -------------------------------------------------------------------------------- /en/faq/guidelines_for_contributing.md: -------------------------------------------------------------------------------- 1 | # Guidelines for Contributing 2 | 3 | - Access English via [Guidelines for Contributing](http://algorithm.yuanbin.me/en/faq/guidelines_for_contributing.html) 4 | - 繁體中文請移步 [貢獻指南](http://algorithm.yuanbin.me/zh-tw/faq/guidelines_for_contributing.html) 5 | - 简体中文请移步 [贡献指南](http://algorithm.yuanbin.zh-hans/faq/guidelines_for_contributing.html) 6 | -------------------------------------------------------------------------------- /en/integer_array/partition_array_by_odd_and_even.md: -------------------------------------------------------------------------------- 1 | # Partition Array by Odd and Even 2 | 3 | ## Question 4 | 5 | - lintcode: [(373) Partition Array by Odd and Even](http://www.lintcode.com/en/problem/partition-array-by-odd-and-even/) 6 | - [Segregate Even and Odd numbers - GeeksforGeeks](http://www.geeksforgeeks.org/segregate-even-and-odd-numbers/) 7 | 8 | ``` 9 | Partition an integers array into odd number first and even number second. 10 | 11 | Example 12 | Given [1, 2, 3, 4], return [1, 3, 2, 4] 13 | 14 | Challenge 15 | Do it in-place. 16 | ``` 17 | 18 | ## Solution 19 | 20 | Use **two pointers** to keep the odd before the even, and swap when necessary. 21 | 22 | ### Java 23 | 24 | ```java 25 | public class Solution { 26 | /** 27 | * @param nums: an array of integers 28 | * @return: nothing 29 | */ 30 | public void partitionArray(int[] nums) { 31 | if (nums == null) return; 32 | 33 | int left = 0, right = nums.length - 1; 34 | while (left < right) { 35 | // odd number 36 | while (left < right && nums[left] % 2 != 0) { 37 | left++; 38 | } 39 | // even number 40 | while (left < right && nums[right] % 2 == 0) { 41 | right--; 42 | } 43 | // swap 44 | if (left < right) { 45 | int temp = nums[left]; 46 | nums[left] = nums[right]; 47 | nums[right] = temp; 48 | } 49 | } 50 | } 51 | } 52 | ``` 53 | 54 | ### C++ 55 | 56 | ```c++ 57 | void partitionArray(vector &nums) { 58 | if (nums.empty()) return; 59 | 60 | int i=0, j=nums.size()-1; 61 | while (i **Note** 6 | In order to re-use most of the memory of an existing data structure, internal implementation of string is immutable in most programming languages(Java, Python). Take care if you want to modify character in place. 7 | -------------------------------------------------------------------------------- /en/styles/website.css: -------------------------------------------------------------------------------- 1 | .book .book-summary, .book .book-body { 2 | font-family: "Helvetica Neue", Helvetica, Arial, "Microsoft YaHei UI", "Microsoft Yahei", "PingFang SC", "Lantinghei SC", "Hiragino Sans GB", "WenQuanYi Micro Hei", "WenQuanYi Zen Hei", "Noto Sans CJK SC", "Microsoft JhengHei UI", "Microsoft JhengHei", "PingFang TC", "Lantinghei TC", "Noto Sans CJK TC", sans-serif; 3 | } 4 | -------------------------------------------------------------------------------- /en/tags.md: -------------------------------------------------------------------------------- 1 | # Tags 2 | -------------------------------------------------------------------------------- /scripts/gitls.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git ls-tree -r --name-only HEAD | while read filename; do 4 | echo "$(git log -1 --format="%ad" --date=short -- $filename) $filename" 5 | done 6 | -------------------------------------------------------------------------------- /scripts/parse_md.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import re 6 | 7 | class parseMD: 8 | def __init__(self, fname, isSummary=False): 9 | self.fname = fname 10 | self.isSummary = isSummary 11 | 12 | def get_title(self): 13 | lines = open(self.fname) 14 | for line in lines: 15 | if re.match('^# ', line): 16 | title = re.split(' - ', line)[2:] 17 | break 18 | 19 | return title 20 | -------------------------------------------------------------------------------- /scripts/rename_ebook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for old_file in book* 4 | do 5 | new_file="$(echo ${old_file} | sed s/^book/algorithm-ebook/)" 6 | mv "${old_file}" "${new_file}" 7 | done 8 | -------------------------------------------------------------------------------- /scripts/sitemap/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/scripts/sitemap/__init__.py -------------------------------------------------------------------------------- /scripts/sitemap/templates/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% for page in pages %} 4 | 5 | {{root_url}}/{{page['url']}} 6 | {{page['lastmod']}} 7 | {{freq}} 8 | 9 | {% endfor %} 10 | 11 | -------------------------------------------------------------------------------- /scripts/sitemap_gen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | from shutil import copyfile 6 | from pathlib import Path 7 | from jinja2 import Environment, FileSystemLoader 8 | from subprocess import check_output 9 | 10 | BASE_DIR = os.path.abspath(os.path.dirname(__file__)) 11 | ROOT_DIR = os.path.abspath(os.path.join(BASE_DIR, os.pardir)) 12 | 13 | 14 | def sitemap(suffix='.md'): 15 | # ensure we are in the ROOT_DIR 16 | os.chdir(ROOT_DIR) 17 | multilang = ['en/', 'zh-hans/', 'zh-tw/'] 18 | pages = [] 19 | raw_bytes = check_output('scripts/gitls.sh') 20 | # ignore last blank string 21 | raw_strs = raw_bytes.decode("utf-8").split('\n')[:-1] 22 | for raw_str in raw_strs: 23 | date, raw_f = raw_str.split(' ') 24 | for lang in multilang: 25 | if raw_f.startswith(lang) and raw_f.endswith(suffix): 26 | if raw_f == lang + 'SUMMARY.md': 27 | continue 28 | p = Path(raw_f) 29 | # rename README with index 30 | if p.name == 'README.md': 31 | p = p.with_name('index.md') 32 | p = p.with_suffix('.html') 33 | fn = p.as_posix().lower() 34 | page = {} 35 | page['lastmod'] = date 36 | page['url'] = fn 37 | pages.append(page) 38 | root_url = 'http://algorithm.yuanbin.me' 39 | templates = os.path.join(BASE_DIR, 'sitemap' + os.sep + 'templates') 40 | env = Environment(loader=FileSystemLoader(templates)) 41 | template = env.get_template('sitemap.xml') 42 | sitemap_xml = template.render(root_url=root_url, pages=pages, freq='daily') 43 | sitemap_fn = os.path.join(ROOT_DIR, 'sitemap.xml') 44 | with open(sitemap_fn, 'w') as sf: 45 | sf.write(sitemap_xml) 46 | sitemap_txt_fn = os.path.join(ROOT_DIR, 'sitemap.txt') 47 | with open(sitemap_txt_fn, 'w') as sf: 48 | urls = [root_url + '/' + page['url'] + '\n' for page in pages] 49 | sf.writelines(urls) 50 | # gitbook do not serve static files under root dir 51 | sitemap_en_fn = os.path.join(ROOT_DIR, 'en' + os.sep + 'sitemap.xml') 52 | copyfile(sitemap_fn, sitemap_en_fn) 53 | 54 | 55 | if __name__ == "__main__": 56 | sitemap() 57 | -------------------------------------------------------------------------------- /scripts/util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import errno 6 | 7 | def mkdir_p(path): 8 | try: 9 | os.makedirs(path) 10 | except OSError as exc: # Python >2.5 11 | if exc.errno == errno.EEXIST and os.path.isdir(path): 12 | pass 13 | else: 14 | raise 15 | 16 | 17 | def par_dir(path): 18 | return os.path.abspath(os.path.join(path, os.pardir)) -------------------------------------------------------------------------------- /shared-files/README.md: -------------------------------------------------------------------------------- 1 | # Shared Files 2 | 3 | This folder exists for files sharing of Multilingual site. 4 | -------------------------------------------------------------------------------- /shared-files/SUMMARY.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/SUMMARY.md -------------------------------------------------------------------------------- /shared-files/docs/oj_templates/cpp_templates.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | // t: total cases 10 | int t; 11 | cin >> t; 12 | for (int i = 0; i < t; ++i) { 13 | // m: test case lines in total 14 | int m; 15 | cin >> m; 16 | } 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /shared-files/images/Binary-reflected_Gray_code_construction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/Binary-reflected_Gray_code_construction.png -------------------------------------------------------------------------------- /shared-files/images/Heapsort-example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/Heapsort-example.gif -------------------------------------------------------------------------------- /shared-files/images/alipay_billryan_qr15x15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/alipay_billryan_qr15x15.jpg -------------------------------------------------------------------------------- /shared-files/images/binary_tree_summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/binary_tree_summary.png -------------------------------------------------------------------------------- /shared-files/images/binary_tree_traversal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/binary_tree_traversal.png -------------------------------------------------------------------------------- /shared-files/images/bipatial_graph_part_i_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/bipatial_graph_part_i_1.png -------------------------------------------------------------------------------- /shared-files/images/bipatial_graph_part_i_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/bipatial_graph_part_i_2.png -------------------------------------------------------------------------------- /shared-files/images/bubble_sort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/bubble_sort.gif -------------------------------------------------------------------------------- /shared-files/images/copy_list_with_random_pointer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/copy_list_with_random_pointer.jpg -------------------------------------------------------------------------------- /shared-files/images/gitbook_editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/gitbook_editor.png -------------------------------------------------------------------------------- /shared-files/images/huffman_algorithm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/huffman_algorithm.gif -------------------------------------------------------------------------------- /shared-files/images/insertion_sort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/insertion_sort.gif -------------------------------------------------------------------------------- /shared-files/images/insertion_sort_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/insertion_sort_list.png -------------------------------------------------------------------------------- /shared-files/images/linked_list_cycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/linked_list_cycle.png -------------------------------------------------------------------------------- /shared-files/images/linked_list_cycle_ii.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/linked_list_cycle_ii.png -------------------------------------------------------------------------------- /shared-files/images/linked_list_summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/linked_list_summary.png -------------------------------------------------------------------------------- /shared-files/images/linked_list_summary_en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/linked_list_summary_en.png -------------------------------------------------------------------------------- /shared-files/images/merge_sort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/merge_sort.gif -------------------------------------------------------------------------------- /shared-files/images/problem_b_professor_qs_software.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/problem_b_professor_qs_software.png -------------------------------------------------------------------------------- /shared-files/images/qsort1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/qsort1.png -------------------------------------------------------------------------------- /shared-files/images/qsort2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/qsort2.png -------------------------------------------------------------------------------- /shared-files/images/qsort3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/qsort3.gif -------------------------------------------------------------------------------- /shared-files/images/remove_duplicates_from_sorted_list.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/remove_duplicates_from_sorted_list.jpg -------------------------------------------------------------------------------- /shared-files/images/resume-zh_CN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/resume-zh_CN.png -------------------------------------------------------------------------------- /shared-files/images/reverse_linked_list_i.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/reverse_linked_list_i.jpg -------------------------------------------------------------------------------- /shared-files/images/rotated_array.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/rotated_array.png -------------------------------------------------------------------------------- /shared-files/images/selection_sort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/selection_sort.gif -------------------------------------------------------------------------------- /shared-files/images/subsets.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/subsets.jpg -------------------------------------------------------------------------------- /shared-files/images/topological-sorting.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/topological-sorting.jpeg -------------------------------------------------------------------------------- /shared-files/images/topological_sorting.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/topological_sorting.jpeg -------------------------------------------------------------------------------- /shared-files/images/tree_diameter.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/tree_diameter.gif -------------------------------------------------------------------------------- /shared-files/images/valid-sudoku.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/valid-sudoku.png -------------------------------------------------------------------------------- /shared-files/images/wechat_billryan_qr15x15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/shared-files/images/wechat_billryan_qr15x15.jpg -------------------------------------------------------------------------------- /zh-hans/GLOSSARY.md: -------------------------------------------------------------------------------- 1 | ## TLE 2 | 3 | Time Limit Exceeded 的简称。你的程序在 OJ 上的运行时间太长了,超过了对应题目的时间限制。 4 | 5 | ## DFS 6 | 7 | Depth-First Search, 深度优先搜索 8 | 9 | ## BFS 10 | 11 | Breadth-First Search, 广度优先搜索 12 | 13 | ## DP_Sequence 14 | 15 | 单序列动态规划,通常使用 f[i] 表示前i个位置/数字/字母... 使用 f[n-1] 表示最后返回结果。 16 | 17 | ## DP_Two_Sequence 18 | 19 | 一般有两个数组或者两个字符串,计算其匹配关系. 通常可用 `f[i][j]`表示第一个数组的前 i 位和第二个数组的前 j 位的关系。 20 | 21 | ## DP_Matrix 22 | 23 | 根据动态规划解题的四要素,矩阵类动态规划问题通常可用 f[x][y] 表示从起点走到坐标(x,y)的值 24 | -------------------------------------------------------------------------------- /zh-hans/appendix_i_interview_and_resume/README.md: -------------------------------------------------------------------------------- 1 | # Appendix I Interview and Resume 2 | 3 | 本章主要总结一些技术面试和撰写简历方面的注意事项。 4 | 5 | -------------------------------------------------------------------------------- /zh-hans/appendix_i_interview_and_resume/resume.md: -------------------------------------------------------------------------------- 1 | # Resume 2 | 3 | 本小节主要总结一些**技术简历**相关的优质资源。具体的还可以参考前一节中 Facebook 提供的简历撰写指南,除了这些简短的资源外还强烈推荐下 Gayle 写的 *The Google Resume*,极其详细!干货超多! 4 | 5 | ## Resume Template 6 | 7 | 推荐使用 Markdown 或者 Latex 撰写简历,可以使用 sharelatex 在线写简历,从 [CV or Resume](https://www.sharelatex.com/templates/cv-or-resume) 模板中挑,modernCV 的那些模板要写在一页里比较困难,这个 [Professional CV](https://www.sharelatex.com/templates/cv-or-resume/professional-cv) 相对紧凑一些,[LaTeX Templates » Curricula Vitae/Résumés](http://www.latextemplates.com/cat/curricula-vitae) 上还有更多更好的选择。另外推荐下自己写的一个还算简洁优雅的简历模板——[billryan/resume](https://github.com/billryan/resume), 同时支持中英文和 FontAwesome 字体,欢迎试用~ 中文的样式大概长成下面这个样子。 8 | 9 | ![Resume Template - English](https://cloud.githubusercontent.com/assets/1292567/12375657/d6c6e58a-bd07-11e5-8401-ee7b97f61864.png) 10 | ![Resume Template - 简体中文](https://cloud.githubusercontent.com/assets/1292567/12375656/d6c6e6f2-bd07-11e5-89a4-73bcf89ff19d.png) 11 | 12 | ## Reference 13 | 14 | - *The Google Resume* - 书名虽为简历,但本书可不只是教你写简历那么简单,除了教你如何写优秀简历外还总结了技术面试以及找工作过程中的方方面面。甚至连职业规划都有涉及!**力荐!** 15 | - [如何写好技术简历 —— 实例、模板及工具 | @Get社区](http://get.jobdeer.com/744.get) - 挺不错的技术简历实战。 16 | - [精益技术简历之道——改善技术简历的47条原则 - Lucida](http://zh.lucida.me/blog/lean-technical-resume/) - 『Effective 简历』系列。 17 | - [如何把简历写进一页 - V2EX](https://www.v2ex.com/t/175250) - 众人支招助萌妹纸优化简历。 18 | - *Cracking the coding interview* 『写好简历』一节。 19 | -------------------------------------------------------------------------------- /zh-hans/basics_algorithm/README.md: -------------------------------------------------------------------------------- 1 | # Basics Algorithm 2 | 3 | 本章主要介绍一些常用的基本算法,后序章节介绍一些高级算法。 4 | -------------------------------------------------------------------------------- /zh-hans/basics_algorithm/bitmap.md: -------------------------------------------------------------------------------- 1 | # Bitmap 2 | 3 | 最开始接触 bitmap 是在《编程珠玑》这本书上,书中所述的方法有点简单粗暴,不过思想倒是挺好——从信息论的角度来解释就是信息压缩了。即将原来32位表示一个 int 变为一位表示一个 int. 从空间的角度来说就是巨大的节省了(1/32)。可能的应用有**大数据排序/查找(非负整数)**。核心思想为根据最大非负整数确定位数,对应的位依次排序。 4 | 5 | C++ 中有`bitset`容器,其他语言可用类似方法实现。 6 | 7 | ## Implementation 8 | 9 | ### C 10 | 11 | ```c 12 | #include 13 | #include 14 | 15 | /* 16 | * @param bits: uint array, i: num i of original array 17 | */ 18 | void setbit(unsigned int *bits, unsigned int i, int BIT_LEN) 19 | { 20 | bits[i / BIT_LEN] |= 1 << (i % BIT_LEN); 21 | } 22 | 23 | /* 24 | * @param bits: uint array, i: num i of original array 25 | */ 26 | int testbit(unsigned int *bits, unsigned int i, int BIT_LEN) 27 | { 28 | return bits[i / BIT_LEN] & (1 << (i % BIT_LEN)); 29 | } 30 | 31 | int main(int argc, char *argv[]) 32 | { 33 | const int BIT_LEN = sizeof(int) * 8; 34 | const unsigned int N = 1 << (BIT_LEN - 1); 35 | unsigned int *bits = (unsigned int *)calloc(N / BIT_LEN, sizeof(int)); 36 | for (unsigned int i = 0; i < N; i++) { 37 | if (i % 10000001 == 0) setbit(bits, i, BIT_LEN); 38 | } 39 | 40 | for (unsigned int i = 0; i < N; i++) { 41 | if (testbit(bits, i, BIT_LEN) != 0) printf("i = %u exists.\n", i); 42 | } 43 | free(bits); 44 | bits = NULL; 45 | 46 | return 0; 47 | } 48 | ``` 49 | 50 | ### 源码分析 51 | 52 | 核心为两个函数方法的使用,`setbit`用于将非负整数`i`置于指定的位。可用分区分位的方式来理解位图排序的思想,即将非负整数`i`放到它应该在的位置。比如16,其可以位于第一个 int 型的第17位,具体实现即将第17位置一,细节见上面代码。测试某个数是否存在于位图中也可以采用类似方法。 53 | -------------------------------------------------------------------------------- /zh-hans/basics_algorithm/divide_and_conquer.md: -------------------------------------------------------------------------------- 1 | # Divide and Conquer - 分治法 2 | 3 | 在计算机科学中,分治法是一种很重要的算法。分治法即『分而治之』,把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。这个思想是很多高效算法的基础,如排序算法(快速排序,归并排序)等。 4 | 5 | ## 分治法思想 6 | 7 | 分治法所能解决的问题一般具有以下几个特征: 8 | 9 | 1. 问题的规模缩小到一定的程度就可以容易地解决。 10 | 2. 问题可以分解为若干个规模较小的相同问题,即该问题具有**最优子结构**性质。 11 | 3. 利用该问题分解出的子问题的解可以合并为该问题的解。 12 | 4. 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。 13 | 14 | 分治法的三个步骤是: 15 | 16 | 1. 分解(Divide):将原问题分解为若干子问题,这些子问题都是原问题规模较小的实例。 17 | 2. 解决(Conquer):递归地求解各子问题。如果子问题规模足够小,则直接求解。 18 | 3. 合并(Combine):将所有子问题的解合并为原问题的解。 19 | 20 | 分治法的经典题目: 21 | 22 | 1. 二分搜索 23 | 2. 大整数乘法 24 | 3. Strassen矩阵乘法 25 | 4. 棋盘覆盖 26 | 5. 归并排序 27 | 6. 快速排序 28 | 7. 循环赛日程表 29 | 8. 汉诺塔 30 | -------------------------------------------------------------------------------- /zh-hans/basics_algorithm/math/README.md: -------------------------------------------------------------------------------- 1 | # Math 2 | 3 | 本小节总结一些与数学(尤其是数论部分)有关的基础,主要总结了《挑战程序设计竞赛》第二章。主要包含以下内容: 4 | 5 | 1. Greatest Common Divisor(最大公约数) 6 | 2. Prime(素数基础理论) 7 | 3. Modulus(求模运算) 8 | 4. Fast Power(快速幂运算) 9 | 10 | ## Modulus - 求模运算 11 | 12 | 有时计算结果可能会溢出,此时往往需要对结果取余。如果有`a % m = c % m` 和 `b % m = d % m`, 那么有以下模运算成立。 13 | 14 | - `(a + b) % m = (c + d) % m` 15 | - `(a - b) % m = (c - d) % m` 16 | - `(a × b) % m = (c × d) % m` 17 | 18 | 需要注意的是没有除法运算,另外由于最终结果可能溢出,故需要使用更大范围的类型来保存求模之前的结果。另外若`a`是负数时往往需要改写为 `a % m + m`, 这样就保证结果在`[0, m - 1]`范围内了。 19 | 20 | ## Fast Power - 快速幂运算 21 | 22 | 快速幂运算的核心思想为反复平方法,将幂指数表示为2的幂次的和,等价于二进制进行移位计算(不断取幂的最低位),比如 $$x^{22} = x^{16} x^4 x^2$$. 23 | 24 | ### Java 25 | 26 | ```java 27 | import java.util.*; 28 | 29 | public class FastPow { 30 | public static long fastModPow(long x, long n, long mod) { 31 | long res = 1 % mod; 32 | while (n > 0) { 33 | // if lowest bit is 1 34 | if ((n & 1) != 0) res = res * x % mod; 35 | x = x * x % mod; 36 | n >>= 1; 37 | } 38 | return res; 39 | } 40 | 41 | public static void main(String[] args) { 42 | if (args.length != 2 && args.length != 3) return; 43 | 44 | long x = Long.parseLong(args[0]); 45 | long n = Long.parseLong(args[1]); 46 | long mod = Long.MAX_VALUE; 47 | if (args.length == 3) { 48 | mod = Long.parseLong(args[2]); 49 | } 50 | System.out.println(fastModPow(x, n, mod)); 51 | } 52 | } 53 | ``` 54 | -------------------------------------------------------------------------------- /zh-hans/basics_algorithm/probability/README.md: -------------------------------------------------------------------------------- 1 | # Probability 2 | -------------------------------------------------------------------------------- /zh-hans/basics_data_structure/README.md: -------------------------------------------------------------------------------- 1 | # Data Structure - 数据结构 2 | 3 | 本章主要介绍一些基本的数据结构和算法。 4 | -------------------------------------------------------------------------------- /zh-hans/basics_data_structure/graph.md: -------------------------------------------------------------------------------- 1 | # Graph - 图 2 | 3 | 图的表示通常使用**邻接矩阵和邻接表**,前者易实现但是对于稀疏矩阵会浪费较多空间,后者使用链表的方式存储信息但是对于图搜索时间复杂度较高。 4 | 5 | ## 编程实现 6 | 7 | ### 邻接矩阵 8 | 9 | 设顶点个数为 V, 那么邻接矩阵可以使用 V × V 的二维数组来表示。 10 | `g[i][j]`表示顶点`i`和顶点`j`的关系,对于无向图可以使用0/1表示是否有连接,对于带权图则需要使用`INF`来区分。有重边时保存边数或者权值最大/小的边即可。 11 | 12 | #### Python 13 | ```python 14 | g = [[0 for _ in range(V)] for _ in range(V)] 15 | ``` 16 | 17 | #### Java 18 | ```java 19 | /* Java Definition */ 20 | int[][] g = new int[V][V]; 21 | ``` 22 | 23 | 24 | ### 邻接表 25 | 26 | 邻接表通过表示从顶点`i`出发到其他所有可能能到的边。 27 | 28 | ### 有向图 29 | 30 | #### Python 31 | 32 | ```python 33 | class DirectedGraphNode: 34 | def __init__(self, x): 35 | self.label = x 36 | self.neighbors = [] 37 | ``` 38 | 39 | #### Java 40 | 41 | ```java 42 | /* Java Definition */ 43 | class DirectedGraphNode { 44 | int label; 45 | ArrayList neighbors; 46 | DirectedGraphNode(int x) { 47 | label = x; 48 | neighbors = new ArrayList(); 49 | } 50 | } 51 | ``` 52 | 53 | ### 无向图同上,只不过在建图时双向同时加。 54 | 55 | #### Python 56 | 57 | ```python 58 | class UndirectedGraphNode: 59 | def __init__(self, x): 60 | self.label = x 61 | self.neighbors = [] 62 | ``` 63 | 64 | 65 | #### Java 66 | 67 | ```java 68 | class UndirectedGraphNode { 69 | int label; 70 | ArrayList neighbors; 71 | UndirectedGraphNode(int x) { 72 | this.label = x; 73 | this.neighbors = new ArrayList(); 74 | } 75 | } 76 | ``` 77 | -------------------------------------------------------------------------------- /zh-hans/basics_data_structure/map.md: -------------------------------------------------------------------------------- 1 | # Map - 哈希表 2 | 3 | Map 是一种关联数组的数据结构,也常被称为字典或键值对。 4 | 5 | ## 编程实现 6 | 7 | ### Python 8 | 9 | 在 Python 中 `dict`(Map) 是一种基本的数据结构。 10 | 11 | ```python 12 | # map 在 python 中是一个keyword 13 | hash_map = {} # or dict() 14 | hash_map['shaun'] = 98 15 | hash_map['wei'] = 99 16 | exist = 'wei' in hash_map # check existence 17 | point = hash_map['shaun'] # get value by key 18 | point = hash_map.pop('shaun') # remove by key, return value 19 | keys = hash_map.keys() # return key list 20 | # iterate dictionary(map) 21 | for key, value in hash_map.items(): 22 | # do something with k, v 23 | pass 24 | ``` 25 | 26 | ### Java 27 | 28 | Java 的实现中 Map 是一种将对象与对象相关联的设计。常用的实现有`HashMap`和`TreeMap`, `HashMap`被用来快速访问,而`TreeMap`则保证『键』始终有序。Map 可以返回键的 Set, 值的 Collection, 键值对的 Set. 29 | 30 | ```java 31 | Map map = new HashMap(); 32 | map.put("bill", 98); 33 | map.put("ryan", 99); 34 | boolean exist = map.containsKey("ryan"); // check key exists in map 35 | int point = map.get("bill"); // get value by key 36 | int point = map.remove("bill") // remove by key, return value 37 | Set set = map.keySet(); 38 | // iterate Map 39 | for (Map.Entry entry : map.entrySet()) { 40 | String key = entry.getKey(); 41 | int value = entry.getValue(); 42 | // do some thing 43 | } 44 | ``` 45 | -------------------------------------------------------------------------------- /zh-hans/basics_data_structure/set.md: -------------------------------------------------------------------------------- 1 | # Set 2 | 3 | Set 是一种用于保存不重复元素的数据结构。常被用作测试归属性,故其查找的性能十分重要。 4 | 5 | ## 编程实现 6 | 7 | ### Python 8 | 9 | `Set` 是`python`自带的基本数据结构, 有多种初始化方式。 `Python`的`set`跟`dict`的Implementation方式类似, 可以认为`set`是只有`key`的`dict`. 10 | 11 | ```python 12 | s = set() 13 | s1 = {1, 2, 3} 14 | s.add('shaunwei') 15 | 'shaun' in s # return true 16 | s.remove('shaunwei') 17 | ``` 18 | 19 | 20 | ### Java 21 | 22 | Set 与 Collection 具有安全一样的接口,通常有`HashSet`, `TreeSet` 或 `LinkedHashSet`三种实现。`HashSet`基于散列函数实现,无序,查询速度最快;`TreeSet`基于红-黑树实现,有序。 23 | 24 | ```java 25 | Set hash = new HashSet(); 26 | hash.add("billryan"); 27 | hash.contains("billryan"); 28 | ``` 29 | 30 | 在不允许重复元素时可当做哈希表来用。 31 | -------------------------------------------------------------------------------- /zh-hans/basics_data_structure/stack.md: -------------------------------------------------------------------------------- 1 | # Stack - 栈 2 | 3 | 栈是一种 LIFO(Last In First Out) 的数据结构,常用方法有添加元素,取栈顶元素,弹出栈顶元素,判断栈是否为空。 4 | 5 | ## 编程实现 6 | 7 | ### Python 8 | ```python 9 | stack = [] 10 | len(stack) # size of stack 11 | 12 | # more efficient stack 13 | import collections 14 | stack = collections.deque() 15 | ``` 16 | 17 | `list`作为最基本的`python`数据结构之一, 可以很轻松的实现`stack`。 如果需要更高效的`stack`, 建议使用`deque`。 18 | 19 | #### Methods 20 | 21 | - `len(stack) != 0` - 判断`stack`是否为空 22 | - `stack[-1]` - 取栈顶元素,不移除 23 | - `pop()` - 移除栈顶元素并返回该元素 24 | - `append(item)` - 向栈顶添加元素 25 | 26 | 27 | ### Java 28 | 29 | ```java 30 | Deque stack = new ArrayDeque(); 31 | s.size(); // size of stack 32 | ``` 33 | 34 | JDK doc 中建议使用`Deque`代替`Stack`实现栈,因为`Stack`继承自`Vector`,需要`synchronized`,性能略低。 35 | 36 | #### Methods 37 | 38 | - `boolean isEmpty()` - 判断栈是否为空,若使用 Stack 类构造则为 empty() 39 | - `E peek()` - 取栈顶元素,不移除 40 | - `E pop()` - 移除栈顶元素并返回该元素 41 | - `E push(E item)` - 向栈顶添加元素 42 | -------------------------------------------------------------------------------- /zh-hans/basics_data_structure/string.md: -------------------------------------------------------------------------------- 1 | # String 2 | 3 | String 相关的题常出现在面试题中,实际开发也经常用到,这里总结下 C++, Java, Python 中字符串常用的方法。 4 | 5 | ## Python 6 | 7 | ```python 8 | s1 = str() 9 | # in python `''` or `""` is the same 10 | s2 = "shaunwei" # 'shaunwei' 11 | s2len = len(s2) 12 | # last 3 chars 13 | s2[-3:] # wei 14 | s2[5:8] # wei 15 | s3 = s2[:5] # shaun 16 | s3 += 'wei' # return 'shaunwei' 17 | # list in python is same as ArrayList in java 18 | s2list = list(s3) 19 | # string at index 4 20 | s2[4] # 'n' 21 | # find index at first 22 | s2.index('w') # return 5, if not found, throw ValueError 23 | s2.find('w') # return 5, if not found, return -1 24 | ``` 25 | 26 | 在Python里面,没有StringBuffer 或者 StringBuilder。 但是在Python 里面处理String本身就比较 cheap。 27 | 28 | ## Java 29 | 30 | ```java 31 | String s1 = new String(); 32 | String s2 = "billryan"; 33 | int s2Len = s2.length(); 34 | s2.substring(4, 8); // return "ryan" 35 | StringBuilder s3 = new StringBuilder(s2.substring(4, 8)); 36 | s3.append("bill"); 37 | String s2New = s3.toString(); // return "ryanbill" 38 | // convert String to char array 39 | char[] s2Char = s2.toCharArray(); 40 | // char at index 4 41 | char ch = s2.charAt(4); // return 'r' 42 | // find index at first 43 | int index = s2.indexOf('r'); // return 4. if not found, return -1 44 | ``` 45 | 46 | StringBuffer 与 StringBuilder, 前者保证线程安全,后者不是,但单线程下效率高一些,一般使用 StringBuilder. 47 | -------------------------------------------------------------------------------- /zh-hans/basics_misc/README.md: -------------------------------------------------------------------------------- 1 | # Basics Miscellaneous 2 | 3 | 杂项部分,涉及「位操作」等。 4 | -------------------------------------------------------------------------------- /zh-hans/basics_misc/bit_manipulation.md: -------------------------------------------------------------------------------- 1 | # Bit Manipulation 2 | 3 | 位操作有按位与、或、非、左移n位和右移n位等操作。 4 | 5 | ### XOR - 异或 6 | 7 | > 异或:相同为0,不同为1。也可用「不进位加法」来理解。 8 | 9 | 异或操作的一些特点: 10 | ``` 11 | x ^ 0 = x 12 | x ^ 1s = ~x // 1s = ~0 13 | x ^ (~x) = 1s 14 | x ^ x = 0 // interesting and important! 15 | a ^ b = c => a ^ c = b, b ^ c = a // swap 16 | a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c // associative 17 | ``` 18 | 19 | ### 移位操作 20 | 21 | 移位操作可近似为乘以/除以2的幂。`0b0010 * 0b0110`等价于`0b0110 << 2`. 下面是一些常见的移位组合操作。从低位向高位看过去,个位为1,那么有: 22 | 23 | 1. 将`x`最右边的`n`位清零 - `x & (~0 << n)` 24 | 2. 获取`x`的第`n`位值(0或者1) - `(x >> n) & 1` 25 | 2. 获取`x`的第`n`位的幂值 - `x & (1 << (n - 1))` 26 | 3. 仅将第`n`位置为`1` - `x | (1 << n)` 27 | 4. 仅将第`n`位置为`0` - `x & (~(1 << n))` 28 | 5. 将`x`最高位至第`n`位(含)清零 - `x & ((1 << n) - 1)` 29 | 6. 将第`n`位至第0位(含)清零 - `x & (~((1 << (n + 1)) - 1))` 30 | 7. 仅更新第`n`位,写入值为`v`; `v`为1则更新为1,否则为0 - `mask = ~(1 << n); x = (x & mask) | (v << i)` 31 | 32 | 33 | ## Reference 34 | 35 | - [位运算应用技巧(1) » NoAlGo博客](http://noalgo.info/344.html) 36 | - [位运算应用技巧(2) » NoAlGo博客](http://noalgo.info/353.html) 37 | - [位运算简介及实用技巧(一):基础篇 | Matrix67: The Aha Moments](http://www.matrix67.com/blog/archives/263) 38 | - *cc150* chapter 8.5 and chapter 9.5 39 | - 《编程珠玑2》 40 | - 《Elementary Algorithms》 Larry LIU Xinyu 41 | -------------------------------------------------------------------------------- /zh-hans/basics_sorting/README.md: -------------------------------------------------------------------------------- 1 | # Basics Sorting - 基础排序算法 2 | 3 | # 算法复习——排序 4 | 5 | 时间限制为1s时,大O为10000000时勉强可行,100,000,000时很悬。 6 | 7 | ## 算法分析 8 | 9 | 1. 时间复杂度-执行时间(比较和交换次数) 10 | 2. 空间复杂度-所消耗的额外内存空间 11 | - 使用小堆栈或表 12 | - 使用链表或指针、数组索引来代表数据 13 | - 排序数据的副本 14 | 15 | 对具有重键的数据(同一组数按不同键多次排序)进行排序时,需要考虑排序方法的稳定性,在非稳定性排序算法中需要稳定性时可考虑加入小索引。 16 | 17 | 稳定性:如果排序后文件中拥有相同键的项的相对位置不变,这种排序方式是稳定的。 18 | 19 | 常见的排序算法根据是否需要比较可以分为如下几类: 20 | 21 | - Comparison Sorting 22 | 1. Bubble Sort 23 | 2. Selection Sort 24 | 3. Insertion Sort 25 | 4. Shell Sort 26 | 5. Merge Sort 27 | 6. Quck Sort 28 | 7. Heap Sort 29 | - Bucket Sort 30 | - Counting Sort 31 | - Radix Sort 32 | 33 | 从稳定性角度考虑可分为如下两类: 34 | - 稳定 35 | - 非稳定 36 | 37 | ## Reference 38 | 39 | - [常用排序算法总结(性能+代码) - SegmentFault](http://segmentfault.com/a/1190000002595152#articleHeader15) 40 | - [Sorting algorithm - Wikipedia, the free encyclopedia](http://en.wikipedia.org/wiki/Sorting_algorithm) - 各类排序算法的「平均、最好、最坏时间复杂度」总结。 41 | - [经典排序算法总结与实现 | Jark's Blog](http://wuchong.me/blog/2014/02/09/algorithm-sort-summary/) - 基于 Python 的较为清晰的总结。 42 | - [【面经】硅谷前沿Startup面试经验-排序算法总结及快速排序算法代码_九章算法](http://blog.sina.com.cn/s/blog_eb52001d0102v1k8.html) - 总结了一些常用常问的排序算法。 43 | -------------------------------------------------------------------------------- /zh-hans/basics_sorting/bubble_sort.md: -------------------------------------------------------------------------------- 1 | # Bubble Sort - 冒泡排序 2 | 3 | 核心:**冒泡**,持续比较相邻元素,大的挪到后面,因此大的会逐步往后挪,故称之为冒泡。 4 | 5 | ![Bubble Sort](../../shared-files/images/bubble_sort.gif) 6 | 7 | ## Implementation 8 | 9 | ### Python 10 | 11 | ```python 12 | #!/usr/bin/env python 13 | 14 | 15 | def bubbleSort(alist): 16 | for i in xrange(len(alist)): 17 | print(alist) 18 | for j in xrange(1, len(alist) - i): 19 | if alist[j - 1] > alist[j]: 20 | alist[j - 1], alist[j] = alist[j], alist[j - 1] 21 | 22 | return alist 23 | 24 | unsorted_list = [6, 5, 3, 1, 8, 7, 2, 4] 25 | print(bubbleSort(unsorted_list)) 26 | ``` 27 | 28 | ### Java 29 | 30 | ```java 31 | public class Sort { 32 | public static void main(String[] args) { 33 | int[] unsortedArray = new int[]{6, 5, 3, 1, 8, 7, 2, 4}; 34 | bubbleSort(unsortedArray); 35 | System.out.println("After sort: "); 36 | for (int item : unsortedArray) { 37 | System.out.print(item + " "); 38 | } 39 | } 40 | 41 | public static void bubbleSort(int[] nums) { 42 | int len = nums.length; 43 | for (int i = 0; i < len; i++) { 44 | for (int num : nums) { 45 | System.out.print(num + " "); 46 | } 47 | System.out.println(); 48 | for (int j = 1; j < len - i; j++) { 49 | if (nums[j - 1] > nums[j]) { 50 | int temp = nums[j - 1]; 51 | nums[j - 1] = nums[j]; 52 | nums[j] = temp; 53 | } 54 | } 55 | } 56 | } 57 | } 58 | ``` 59 | 60 | ### 复杂度分析 61 | 62 | 平均情况与最坏情况均为 $$O(n^2)$$, 使用了 temp 作为临时交换变量,空间复杂度为 $$O(1)$$. 63 | 64 | ## Reference 65 | 66 | - [冒泡排序 - 维基百科,自由的百科全书](http://zh.wikipedia.org/wiki/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F) 67 | -------------------------------------------------------------------------------- /zh-hans/basics_sorting/bucket_sort.md: -------------------------------------------------------------------------------- 1 | # Bucket Sort 2 | 3 | 桶排序和归并排序有那么点点类似,也使用了归并的思想。大致步骤如下: 4 | 5 | 1. 设置一个定量的数组当作空桶。 6 | 2. Divide - 从待排序数组中取出元素,将元素按照一定的规则塞进对应的桶子去。 7 | 3. 对每个非空桶进行排序,通常可在塞元素入桶时进行插入排序。 8 | 4. Conquer - 从非空桶把元素再放回原来的数组中。 9 | 10 | ## Reference 11 | 12 | - [Bucket Sort Visualization](http://www.cs.usfca.edu/~galles/visualization/BucketSort.html) - 动态演示。 13 | - [桶排序 - 维基百科,自由的百科全书](http://zh.wikipedia.org/wiki/%E6%A1%B6%E6%8E%92%E5%BA%8F) 14 | -------------------------------------------------------------------------------- /zh-hans/basics_sorting/counting_sort.md: -------------------------------------------------------------------------------- 1 | # Counting Sort 2 | 3 | 计数排序,顾名思义,就是对待排序数组按元素进行计数。使用前提是需要先知道待排序数组的元素范围,将这些一定范围的元素置于新数组中,新数组的大小为待排序数组中最大元素与最小元素的差值。 4 | 5 | 维基上总结的四个步骤如下: 6 | 7 | 1. 定新数组大小——找出待排序的数组中最大和最小的元素 8 | 2. 统计次数——统计数组中每个值为i的元素出现的次数,存入新数组C的第i项 9 | 3. 对统计次数逐个累加——对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加) 10 | 4. 反向填充目标数组——将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1 11 | 12 | 其中反向填充主要是为了避免重复元素落入新数组的同一索引处。 13 | 14 | ## Reference 15 | 16 | - [计数排序 - 维基百科,自由的百科全书](http://zh.wikipedia.org/wiki/%E8%AE%A1%E6%95%B0%E6%8E%92%E5%BA%8F) - 中文版的维基感觉比英文版的好理解些。 17 | - [Counting Sort Visualization](https://www.cs.usfca.edu/~galles/visualization/CountingSort.html) - 动画真心不错~ 结合着看一遍就理解了。 18 | -------------------------------------------------------------------------------- /zh-hans/basics_sorting/radix_sort.md: -------------------------------------------------------------------------------- 1 | # Radix Sort 2 | 3 | 经典排序算法 - 基数排序Radix sort 4 | 5 | 原理类似桶排序,这里总是需要10个桶,多次使用 6 | 7 | 首先以个位数的值进行装桶,即个位数为1则放入1号桶,为9则放入9号桶,暂时忽视十位数 8 | 9 | 例如 10 | 11 | 待排序数组[62,14,59,88,16]简单点五个数字 12 | 13 | 分配10个桶,桶编号为0-9,以个位数数字为桶编号依次入桶,变成下边这样 14 | 15 | | 0 | 0 | 62 | 0 | 14 | 0 | 16 | 0 | 88 | 59 | 16 | 17 | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |桶编号 18 | 19 | 将桶里的数字顺序取出来, 20 | 21 | 输出结果:[62,14,16,88,59] 22 | 23 | 再次入桶,不过这次以十位数的数字为准,进入相应的桶,变成下边这样: 24 | 25 | 由于前边做了个位数的排序,所以当十位数相等时,个位数字是由小到大的顺序入桶的,就是说,入完桶还是有序 26 | 27 | | 0 | 14,16 | 0 | 0 | 0 | 59 | 62 | 0 | 88 | 0 | 28 | 29 | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |桶编号 30 | 31 | 32 | 33 | 34 | 因为没有大过100的数字,没有百位数,所以到这排序完毕,顺序取出即可 35 | 36 | 最后输出结果:[14,16,59,62,88] 37 | 38 | 39 | 文章引用自 40 | http://www.cnblogs.com/kkun/archive/2011/11/23/2260275.html 41 | -------------------------------------------------------------------------------- /zh-hans/basics_sorting/selection_sort.md: -------------------------------------------------------------------------------- 1 | # Selection Sort - 选择排序 2 | 3 | 核心:不断地选择剩余元素中的最小者。 4 | 5 | 1. 找到数组中最小元素并将其和数组第一个元素交换位置。 6 | 2. 在剩下的元素中找到最小元素并将其与数组第二个元素交换,直至整个数组排序。 7 | 8 | 性质: 9 | 10 | - 比较次数=(N-1)+(N-2)+(N-3)+...+2+1~N^2/2 11 | - 交换次数=N 12 | - 运行时间与输入无关 13 | - 数据移动最少 14 | 15 | 下图来源为 [File:Selection-Sort-Animation.gif - IB Computer Science](http://wiki.ibcsstudent.org/index.php?title=File:Selection-Sort-Animation.gif) 16 | 17 | ![Selection Sort](../../shared-files/images/selection_sort.gif) 18 | 19 | ## Implementation 20 | 21 | ### Python 22 | 23 | ```python 24 | #!/usr/bin/env python 25 | 26 | 27 | def selectionSort(alist): 28 | for i in xrange(len(alist)): 29 | print(alist) 30 | min_index = i 31 | for j in xrange(i + 1, len(alist)): 32 | if alist[j] < alist[min_index]: 33 | min_index = j 34 | alist[min_index], alist[i] = alist[i], alist[min_index] 35 | return alist 36 | 37 | unsorted_list = [8, 5, 2, 6, 9, 3, 1, 4, 0, 7] 38 | print(selectionSort(unsorted_list)) 39 | ``` 40 | 41 | ### Java 42 | 43 | ```java 44 | public class Sort { 45 | public static void main(String[] args) { 46 | int unsortedArray[] = new int[]{8, 5, 2, 6, 9, 3, 1, 4, 0, 7}; 47 | selectionSort(unsortedArray); 48 | System.out.println("After sort: "); 49 | for (int item : unsortedArray) { 50 | System.out.print(item + " "); 51 | } 52 | } 53 | 54 | public static void selectionSort(int[] array) { 55 | int len = array.length; 56 | for (int i = 0; i < len; i++) { 57 | for (int item : array) { 58 | System.out.print(item + " "); 59 | } 60 | System.out.println(); 61 | int min_index = i; 62 | for (int j = i + 1; j < len; j++) { 63 | if (array[j] < array[min_index]) { 64 | min_index = j; 65 | } 66 | } 67 | int temp = array[min_index]; 68 | array[min_index] = array[i]; 69 | array[i] = temp; 70 | } 71 | } 72 | } 73 | ``` 74 | 75 | ## Reference 76 | 77 | - [选择排序 - 维基百科,自由的百科全书](http://zh.wikipedia.org/wiki/%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F) 78 | - [The Selection Sort — Problem Solving with Algorithms and Data Structures](http://interactivepython.org/runestone/static/pythonds/SortSearch/TheSelectionSort.html) 79 | -------------------------------------------------------------------------------- /zh-hans/bigdata/README.md: -------------------------------------------------------------------------------- 1 | 本小节主要总结 bigdata 相关的题,涉及 MapReduce, Top K 等经典问题。 -------------------------------------------------------------------------------- /zh-hans/bigdata/top_k_largest_numbers.md: -------------------------------------------------------------------------------- 1 | --- 2 | difficulty: Medium 3 | tags: 4 | - Priority Queue 5 | - Heap 6 | title: Top k Largest Numbers 7 | --- 8 | 9 | # Top k Largest Numbers 10 | 11 | ## Problem 12 | 13 | ### Metadata 14 | 15 | - tags: Priority Queue, Heap 16 | - difficulty: Medium 17 | - source(lintcode): 18 | 19 | ### Description 20 | 21 | Given an integer array, find the top *k* largest numbers in it. 22 | 23 | #### Example 24 | 25 | Given `[3,10,1000,-99,4,100]` and *k* = `3`. 26 | Return `[1000, 100, 10]`. 27 | 28 | ## 题解 29 | 30 | 简单题,使用堆即可。 31 | 32 | ### Java 33 | 34 | ```java 35 | public class Solution { 36 | /** 37 | * @param nums: an integer array 38 | * @param k: An integer 39 | * @return: the top k largest numbers in array 40 | */ 41 | public int[] topk(int[] nums, int k) { 42 | if (nums == null || nums.length <= 1) return nums; 43 | 44 | PriorityQueue pq = new PriorityQueue(nums.length, Collections.reverseOrder()); 45 | for (int num : nums) { 46 | pq.offer(num); 47 | } 48 | 49 | int[] maxK = new int[k]; 50 | for (int i = 0; i < k; i++) { 51 | maxK[i] = pq.poll(); 52 | } 53 | 54 | return maxK; 55 | } 56 | } 57 | ``` 58 | 59 | ### 源码分析 60 | 61 | 略 62 | 63 | ### 复杂度分析 64 | 65 | 略 -------------------------------------------------------------------------------- /zh-hans/bigdata/top_k_largest_numbers_ii.md: -------------------------------------------------------------------------------- 1 | --- 2 | difficulty: Medium 3 | tags: 4 | - Priority Queue 5 | - Heap 6 | - Data Stream 7 | title: Top k Largest Numbers II 8 | --- 9 | 10 | # Top k Largest Numbers II 11 | 12 | ## Problem 13 | 14 | ### Metadata 15 | 16 | - tags: Priority Queue, Heap, Data Stream 17 | - difficulty: Medium 18 | - source(lintcode): 19 | 20 | ### Description 21 | 22 | Implement a data structure, provide two interfaces: 23 | 24 | 1. `add(number)`. Add a new number in the data structure. 25 | 2. `topk()`. Return the top *k* largest numbers in this data structure. *k* is given when we create the data structure. 26 | 27 | #### Example 28 | 29 | ``` 30 | s = new Solution(3); 31 | >> create a new data structure. 32 | s.add(3) 33 | s.add(10) 34 | s.topk() 35 | >> return [10, 3] 36 | s.add(1000) 37 | s.add(-99) 38 | s.topk() 39 | >> return [1000, 10, 3] 40 | s.add(4) 41 | s.topk() 42 | >> return [1000, 10, 4] 43 | s.add(100) 44 | s.topk() 45 | >> return [1000, 100, 10] 46 | ``` 47 | 48 | ## 题解 49 | 50 | 此题只用堆的话在最后的排序输出会比较难受,最后用 List 的排序也可以。 51 | 52 | ### Java 53 | 54 | ```java 55 | public class Solution { 56 | private int k = -1; 57 | private Queue heap = null; 58 | /* 59 | * @param k: An integer 60 | */public Solution(int k) { 61 | // do intialization if necessary 62 | this.k = k; 63 | heap = new PriorityQueue(k); 64 | } 65 | 66 | /* 67 | * @param num: Number to be added 68 | * @return: nothing 69 | */ 70 | public void add(int num) { 71 | // write your code here 72 | if (heap.size() < k) { 73 | heap.offer(num); 74 | } else if (heap.peek() < num) { 75 | heap.poll(); 76 | heap.offer(num); 77 | } 78 | } 79 | 80 | /* 81 | * @return: Top k element 82 | */ 83 | public List topk() { 84 | // write your code here 85 | List result = new ArrayList<>(k); 86 | Iterator it = heap.iterator(); 87 | while(it.hasNext()) { 88 | result.add(it.next()); 89 | } 90 | result.sort(Collections.reverseOrder()); 91 | return result; 92 | } 93 | } 94 | ``` 95 | 96 | ### 源码分析 97 | 98 | 略 99 | 100 | ### 复杂度分析 101 | 102 | 略 -------------------------------------------------------------------------------- /zh-hans/binary_search/README.md: -------------------------------------------------------------------------------- 1 | # Search - 搜索 2 | 3 | 本章主要总结二分搜索相关的题。 4 | 5 | - 能使用二分搜索的前提是数组已排序。 6 | - 二分查找的使用场景:(1)可转换为find the first/last position of...(2)时间复杂度至少为O(lgn)。 7 | - 递归和迭代的使用场景:能用迭代就用迭代,特别复杂时采用递归。 8 | -------------------------------------------------------------------------------- /zh-hans/binary_search/first_position_of_target.md: -------------------------------------------------------------------------------- 1 | # First Position of Target 2 | 3 | ## Question 4 | 5 | - lintcode: [First Position of Target](http://www.lintcode.com/en/problem/first-position-of-target) 6 | 7 | ### Problem Statement 8 | 9 | For a given sorted array (ascending order) and a `target` number, find the 10 | first index of this number in `O(log n)` time complexity. 11 | 12 | If the target number does not exist in the array, return `-1`. 13 | 14 | #### Example 15 | 16 | If the array is `[1, 2, 3, 3, 4, 5, 10]`, for given target `3`, return `2`. 17 | 18 | #### Challenge 19 | 20 | If the count of numbers is bigger than $$2^{32}$$, can your code work properly? 21 | 22 | ## 题解 23 | 24 | 对于已排序升序(升序)数组,使用二分查找可满足复杂度要求,注意数组中可能有重复值,所以需要使用类似`lower_bound`中提到的方法。 25 | 26 | ### Java 27 | 28 | ```java 29 | class Solution { 30 | /** 31 | * @param nums: The integer array. 32 | * @param target: Target to find. 33 | * @return: The first position of target. Position starts from 0. 34 | */ 35 | public int binarySearch(int[] nums, int target) { 36 | if (nums == null || nums.length == 0) { 37 | return -1; 38 | } 39 | 40 | int start = -1, end = nums.length; 41 | int mid; 42 | while (start + 1 < end) { 43 | // avoid overflow when (end + start) 44 | mid = start + (end - start) / 2; 45 | if (nums[mid] < target) { 46 | start = mid; 47 | } else { 48 | end = mid; 49 | } 50 | } 51 | 52 | if (end == nums.length || nums[end] != target) { 53 | return -1; 54 | } else { 55 | return end; 56 | } 57 | } 58 | } 59 | 60 | ``` 61 | 62 | ### 源码分析 63 | 64 | 1. 首先对输入做异常处理,数组为空或者长度为0。 65 | 2. 初始化 `start, end, mid`三个变量,这里`start`初始化为`-1`主要是考虑到`end`为`1`。注意mid的求值方法,可以防止两个整型值相加时溢出。 66 | 3. **使用迭代而不是递归**进行二分查找,因为工程中递归写法存在潜在溢出的可能。 67 | 4. while终止条件应为`start + 1 < end`而不是`start <= end`,`start == end`时可能出现死循环。**即循环终止条件是相邻或相交元素时退出。**由于这里初始化时`start < end`,所以一定是`start + 1 == end`时退出循环。 68 | 5. 迭代终止时有两种情况,一种是在原数组中找到了,这种情况下一定是`end`, 因为`start`的更新只在`nums[mid] < target`. 69 | 6. 最后判断`end`和`target`的关系,先排除`end`为数组长度这种会引起越界的情况,然后再判断和目标值是否相等。 70 | 71 | ### 复杂度分析 72 | 73 | 时间复杂度 $$O(\log n)$$, 空间复杂度 $$(1)$$. 74 | 对于题中的 follow up, Java 中数组不允许使用 long 型,如果使用 long 型,那么数组大小可大 17GB 之巨!!几乎没法用。 75 | 76 | ## Reference 77 | 78 | - 《挑战程序设计竞赛》3.1节 79 | -------------------------------------------------------------------------------- /zh-hans/binary_search_tree/README.md: -------------------------------------------------------------------------------- 1 | # Binary Search Tree - 二叉搜索树 2 | 3 | 二叉搜索树的定义及简介在 [Binary Search Trees](http://algorithm.yuanbin.me/zh-hans/basics_data_structure/binary_search_tree.html) 中已经有所介绍。简单来说就是当前节点的值大于等于左子结点的值,而小于右子节点的值。 4 | -------------------------------------------------------------------------------- /zh-hans/binary_tree/README.md: -------------------------------------------------------------------------------- 1 | Maximum Depth of Binary Tree# Binary Tree - 二叉树 2 | 3 | 二叉树的基本概念在 [Binary Tree | Algorithm](http://algorithm.yuanbin.me/zh-hans/basics_data_structure/binary_tree.html) 中有简要的介绍,这里就二叉树的一些应用做一些实战演练。 4 | 5 | 二叉树的遍历大致可分为前序、中序、后序三种方法。 6 | 7 | 8 | 下图是把本章中所有出现的题目归类总结了一下,便于记忆 9 | 10 | ![二叉树](../../shared-files/images/binary_tree_summary.png) -------------------------------------------------------------------------------- /zh-hans/binary_tree/diameter_of_a_binary_tree.md: -------------------------------------------------------------------------------- 1 | # Diameter of a Binary Tree 2 | 3 | ## Question 4 | 5 | - [Diameter of a Binary Tree - GeeksforGeeks](http://www.geeksforgeeks.org/diameter-of-a-binary-tree/) 6 | 7 | ``` 8 | The diameter of a tree (sometimes called the width) is the number of nodes 9 | on the longest path between two leaves in the tree. 10 | The diagram below shows two trees each with diameter nine, 11 | the leaves that form the ends of a longest path are shaded 12 | (note that there is more than one path in each tree of length nine, 13 | but no path longer than nine nodes). 14 | ``` 15 | 16 | ![Diameter of a Binary Tree](../../shared-files/images/tree_diameter.gif) 17 | 18 | ## 题解 19 | 20 | 和题 [Lowest Common Ancestor](http://algorithm.yuanbin.me/zh-hans/binary_tree/lowest_common_ancestor.html) 分析思路特别接近。 21 | 22 | ### Java 23 | 24 | ```java 25 | class TreeNode { 26 | int val; 27 | TreeNode left, right; 28 | TreeNode(int val) { 29 | this.val = val; 30 | this.left = null; 31 | this.right = null; 32 | } 33 | } 34 | 35 | public class Solution { 36 | public int diameter(TreeNode root) { 37 | if (root == null) return 0; 38 | 39 | // left, right height 40 | int leftHight = getHeight(root.left); 41 | int rightHight = getHeight(root.right); 42 | 43 | // left, right subtree diameter 44 | int leftDia = diameter(root.left); 45 | int rightDia = diameter(root.right); 46 | 47 | int maxSubDia = Math.max(leftDia, rightDia); 48 | return Math.max(maxSubDia, leftHight + 1 + rightHight); 49 | } 50 | 51 | private int getHeight(TreeNode root) { 52 | if (root == null) return 0; 53 | 54 | return 1 + Math.max(getHeight(root.left), getHeight(root.right)); 55 | } 56 | 57 | public static void main(String[] args) { 58 | TreeNode root = new TreeNode(1); 59 | root.left = new TreeNode(2); 60 | root.right = new TreeNode(3); 61 | root.left.left = new TreeNode(4); 62 | root.left.right = new TreeNode(5); 63 | root.left.right.left = new TreeNode(6); 64 | root.left.right.left.right = new TreeNode(7); 65 | root.left.left.left = new TreeNode(8); 66 | 67 | Solution sol = new Solution(); 68 | int maxDistance = sol.diameter(root); 69 | System.out.println("Max Distance: " + maxDistance); 70 | } 71 | } 72 | ``` 73 | 74 | ## Reference 75 | 76 | - [Diameter of a Binary Tree - GeeksforGeeks](http://www.geeksforgeeks.org/diameter-of-a-binary-tree/) 77 | - [Diameter of a Binary Tree | Algorithms](http://algorithms.tutorialhorizon.com/diameter-of-a-binary-tree/) 78 | -------------------------------------------------------------------------------- /zh-hans/binary_tree/subtree.md: -------------------------------------------------------------------------------- 1 | # Subtree 2 | 3 | ## Question 4 | 5 | - lintcode: [(245) Subtree](http://www.lintcode.com/en/problem/subtree/#) 6 | 7 | ``` 8 | You have two every large binary trees: T1, 9 | with millions of nodes, and T2, with hundreds of nodes. 10 | Create an algorithm to decide if T2 is a subtree of T1. 11 | 12 | Example 13 | T2 is a subtree of T1 in the following case: 14 | 1 3 15 | / \ / 16 | T1 = 2 3 T2 = 4 17 | / 18 | 4 19 | T2 isn't a subtree of T1 in the following case: 20 | 1 3 21 | / \ \ 22 | T1 = 2 3 T2 = 4 23 | / 24 | 4 25 | Note 26 | A tree T2 is a subtree of T1 if there exists a node n in T1 such that 27 | the subtree of n is identical to T2. 28 | That is, if you cut off the tree at node n, 29 | the two trees would be identical. 30 | ``` 31 | 32 | ## 题解 33 | 34 | 判断 T2是否是 T1的子树,首先应该在 T1中找到 T2的根节点,找到根节点后两棵子树必须完全相同。所以整个思路分为两步走:找根节点,判断两棵树是否全等。咋看起来极其简单,但实际实现中还是比较精妙的,尤其是递归的先后顺序及条件与条件或的处理。 35 | 36 | ### Java 37 | 38 | ```java 39 | /** 40 | * Definition of TreeNode: 41 | * public class TreeNode { 42 | * public int val; 43 | * public TreeNode left, right; 44 | * public TreeNode(int val) { 45 | * this.val = val; 46 | * this.left = this.right = null; 47 | * } 48 | * } 49 | */ 50 | public class Solution { 51 | /** 52 | * @param T1, T2: The roots of binary tree. 53 | * @return: True if T2 is a subtree of T1, or false. 54 | */ 55 | public boolean isSubtree(TreeNode T1, TreeNode T2) { 56 | if (T2 == null) return true; 57 | if (T1 == null) return false; 58 | return identical(T1, T2) || isSubtree(T1.left, T2) || isSubtree(T1.right, T2); 59 | } 60 | 61 | private boolean identical(TreeNode T1, TreeNode T2) { 62 | if (T1 == null && T2 == null) return true; 63 | if (T1 == null || T2 == null) return false; 64 | if (T1.val != T2.val) return false; 65 | return identical(T1.left, T2.left) && identical(T1.right, T2.right); 66 | } 67 | } 68 | ``` 69 | 70 | ### 源码分析 71 | 72 | 这道题的异常处理相对 trick 一点,需要理解 null 对子树的含义。另外需要先调用`identical`再递归调用`isSubtree`判断左右子树的情况。方法`identical`中调用`.val`前需要判断是否为 null, 而后递归调用判断左右子树是否 identical。 73 | 74 | ### 复杂度分析 75 | 76 | identical 的调用,时间复杂度近似 $$O(n)$$, 查根节点的时间复杂度随机,平均为 $$O(m)$$, 故总的时间复杂度可近似为 $$O(mn)$$. 77 | 78 | ## Reference 79 | 80 | - [LintCode: Subtree](http://cherylintcode.blogspot.com/2015/06/subtree.html) 81 | -------------------------------------------------------------------------------- /zh-hans/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/zh-hans/cover.jpg -------------------------------------------------------------------------------- /zh-hans/cover_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/zh-hans/cover_small.jpg -------------------------------------------------------------------------------- /zh-hans/data_structure/README.md: -------------------------------------------------------------------------------- 1 | # Data Structure 2 | 3 | 本章主要总结数据结构如 Queue, Stack 等相关的题。 4 | -------------------------------------------------------------------------------- /zh-hans/data_structure/implement_queue_by_two_stacks.md: -------------------------------------------------------------------------------- 1 | # Implement Queue by Two Stacks 2 | 3 | ## Question 4 | 5 | - lintcode: [(40) Implement Queue by Two Stacks](http://www.lintcode.com/en/problem/implement-queue-by-two-stacks/) 6 | 7 | ``` 8 | As the title described, you should only use two stacks to implement a queue's actions. 9 | 10 | The queue should support push(element), 11 | pop() and top() where pop is pop the first(a.k.a front) element in the queue. 12 | 13 | Both pop and top methods should return the value of first element. 14 | 15 | Example 16 | For push(1), pop(), push(2), push(3), top(), pop(), you should return 1, 2 and 2 17 | 18 | Challenge 19 | implement it by two stacks, do not use any other data structure and push, 20 | pop and top should be O(1) by AVERAGE. 21 | ``` 22 | 23 | ## 题解 24 | 25 | 两个栈模拟队列,栈是 LIFO, 队列是 FIFO, 故用两个栈模拟队列时可结合栈1和栈2, LIFO + LIFO ==> FIFO, 即先将一个栈元素全部 push 到另一个栈,效果即等价于 Queue. 26 | 27 | ### Java 28 | 29 | ```java 30 | public class Solution { 31 | private Stack stack1; 32 | private Stack stack2; 33 | 34 | public Solution() { 35 | // source stack 36 | stack1 = new Stack(); 37 | // target stack 38 | stack2 = new Stack(); 39 | } 40 | 41 | public void push(int element) { 42 | stack1.push(element); 43 | } 44 | 45 | public int pop() { 46 | if (stack2.empty()) { 47 | stack1ToStack2(stack1, stack2); 48 | } 49 | return stack2.pop(); 50 | } 51 | 52 | public int top() { 53 | if (stack2.empty()) { 54 | stack1ToStack2(stack1, stack2); 55 | } 56 | return stack2.peek(); 57 | } 58 | 59 | private void stack1ToStack2(Stack stack1, Stack stack2) { 60 | while (!stack1.empty()) { 61 | stack2.push(stack1.pop()); 62 | } 63 | } 64 | } 65 | ``` 66 | 67 | ### 源码分析 68 | 69 | 将栈1作为原始栈,将栈1元素压入栈2是公共方法,故写成一个私有方法。 70 | 71 | ### 复杂度分析 72 | 73 | 视连续 push 的元素而定,时间复杂度近似为 $$O(1)$$. 74 | 75 | ## Reference 76 | 77 | - [Implement Queue by Two Stacks 参考程序 Java/C++/Python](http://www.jiuzhang.com/solutions/implement-queue-by-two-stacks/) 78 | -------------------------------------------------------------------------------- /zh-hans/data_structure/longest_words.md: -------------------------------------------------------------------------------- 1 | # Longest Words 2 | 3 | ## Question 4 | 5 | - lintcode: [(133) Longest Words](http://www.lintcode.com/en/problem/longest-words/) 6 | 7 | ``` 8 | Given a dictionary, find all of the longest words in the dictionary. 9 | 10 | Example 11 | Given 12 | 13 | { 14 | "dog", 15 | "google", 16 | "facebook", 17 | "internationalization", 18 | "blabla" 19 | } 20 | the longest words are(is) ["internationalization"]. 21 | 22 | Given 23 | 24 | { 25 | "like", 26 | "love", 27 | "hate", 28 | "yes" 29 | } 30 | the longest words are ["like", "love", "hate"]. 31 | 32 | Challenge 33 | It's easy to solve it in two passes, can you do it in one pass? 34 | ``` 35 | 36 | ## 题解 37 | 38 | 简单题,容易想到的是首先遍历以便,找到最长的字符串,第二次遍历时取最长的放到最终结果中。但是如果只能进行一次遍历呢?一次遍历意味着需要维护当前遍历的最长字符串,这必然有比较与更新删除操作,这种情况下使用双端队列最为合适,这道题稍微特殊一点,不必从尾端插入,只需在遍历时若发现比数组中最长的元素还长时删除整个列表。 39 | 40 | ### Java 41 | 42 | ```java 43 | class Solution { 44 | /** 45 | * @param dictionary: an array of strings 46 | * @return: an arraylist of strings 47 | */ 48 | ArrayList longestWords(String[] dictionary) { 49 | ArrayList result = new ArrayList(); 50 | if (dictionary == null || dictionary.length == 0) return result; 51 | 52 | for (String str : dictionary) { 53 | // combine empty and shorter length 54 | if (result.isEmpty() || str.length() > result.get(0).length()) { 55 | result.clear(); 56 | result.add(str); 57 | } else if (str.length() == result.get(0).length()) { 58 | result.add(str); 59 | } 60 | } 61 | 62 | return result; 63 | } 64 | } 65 | ``` 66 | 67 | ### 源码分析 68 | 69 | 熟悉变长数组的常用操作。 70 | 71 | ### 复杂度分析 72 | 73 | 时间复杂度 $$O(n)$$, 最坏情况下需要保存 n - 1个字符串,空间复杂度 $$O(n)$$. 74 | 75 | ## Reference 76 | 77 | - [Lintcode: Longest Words | codesolutiony](https://codesolutiony.wordpress.com/2015/06/07/lintcode-longest-words/) 78 | -------------------------------------------------------------------------------- /zh-hans/data_structure/min_stack.md: -------------------------------------------------------------------------------- 1 | # Min Stack 2 | 3 | ## Question 4 | 5 | - lintcode: [(12) Min Stack](http://www.lintcode.com/en/problem/min-stack/) 6 | 7 | ``` 8 | Implement a stack with min() function, 9 | which will return the smallest number in the stack. 10 | 11 | It should support push, pop and min operation all in O(1) cost. 12 | 13 | Example 14 | Operations: push(1), pop(), push(2), push(3), min(), push(1), min() Return: 1, 2, 1 15 | 16 | Note 17 | min operation will never be called if there is no number in the stack 18 | ``` 19 | 20 | ## 题解 21 | 22 | 『最小』栈,要求在栈的基础上实现可以在 $$O(1)$$ 的时间内找出最小值,一般这种 $$O(1)$$的实现往往就是哈希表或者哈希表的变体,这里简单起见可以另外克隆一个栈用以跟踪当前栈的最小值。 23 | 24 | ### Java 25 | 26 | ```java 27 | public class Solution { 28 | public Solution() { 29 | stack1 = new Stack(); 30 | stack2 = new Stack(); 31 | } 32 | 33 | public void push(int number) { 34 | stack1.push(number); 35 | if (stack2.empty()) { 36 | stack2.push(number); 37 | } else { 38 | stack2.push(Math.min(number, stack2.peek())); 39 | } 40 | } 41 | 42 | public int pop() { 43 | stack2.pop(); 44 | return stack1.pop(); 45 | } 46 | 47 | public int min() { 48 | return stack2.peek(); 49 | } 50 | 51 | private Stack stack1; // original stack 52 | private Stack stack2; // min stack 53 | } 54 | ``` 55 | 56 | ### 源码分析 57 | 58 | 取最小栈的栈顶值时需要先判断是否为空栈(而不仅是 null)。 59 | 60 | ### 复杂度分析 61 | 62 | 均为 $$O(1)$$. 63 | -------------------------------------------------------------------------------- /zh-hans/dynamic_programming/climbing_stairs.md: -------------------------------------------------------------------------------- 1 | # Climbing Stairs 2 | 3 | ## Question 4 | 5 | - lintcode: [(111) Climbing Stairs](http://www.lintcode.com/en/problem/climbing-stairs/) 6 | 7 | ``` 8 | You are climbing a stair case. It takes n steps to reach to the top. 9 | 10 | Each time you can either climb 1 or 2 steps. 11 | In how many distinct ways can you climb to the top? 12 | 13 | Example 14 | Given an example n=3 , 1+1+1=2+1=1+2=3 15 | 16 | return 3 17 | ``` 18 | 19 | ## 题解 20 | 21 | 题目问的是到达顶端的方法数,我们采用序列类问题的通用分析方法,可以得到如下四要素: 22 | 23 | 1. State: f[i] 爬到第i级的方法数 24 | 2. Function: f[i]=f[i-1]+f[i-2] 25 | 3. Initialization: f[0]=1,f[1]=1 26 | 4. Answer: f[n] 27 | 28 | 尤其注意状态转移方程的写法,f[i]只可能由两个中间状态转化而来,一个是f[i-1],由f[i-1]到f[i]其方法总数并未增加;另一个是f[i-2],由f[i-2]到f[i]隔了两个台阶,因此有1+1和2两个方法,因此容易写成 f[i]=f[i-1]+f[i-2]+1,但仔细分析后能发现,由f[i-2]到f[i]的中间状态f[i-1]已经被利用过一次,故f[i]=f[i-1]+f[i-2]. 使用动规思想解题时需要分清『重叠子状态』, 如果有重复的需要去重。 29 | 30 | ### C++ 31 | 32 | ```c++ 33 | class Solution { 34 | public: 35 | /** 36 | * @param n: An integer 37 | * @return: An integer 38 | */ 39 | int climbStairs(int n) { 40 | if (n < 1) { 41 | return 0; 42 | } 43 | 44 | vector ret(n + 1, 1); 45 | 46 | for (int i = 2; i != n + 1; ++i) { 47 | ret[i] = ret[i - 1] + ret[i - 2]; 48 | } 49 | 50 | return ret[n]; 51 | } 52 | }; 53 | ``` 54 | 55 | 1. 异常处理 56 | 2. 初始化n+1个元素,初始值均为1。之所以用n+1个元素是下标分析起来更方便 57 | 3. 状态转移方程 58 | 4. 返回ret[n] 59 | 60 | 初始化ret[0]也为1,可以认为到第0级也是一种方法。 61 | 62 | 以上答案的空间复杂度为 $$O(n)$$,仔细观察后可以发现在状态转移方程中,我们可以使用三个变量来替代长度为n+1的数组。具体代码可参考 [climbing-stairs | 九章算法 ](http://www.jiuzhang.com/solutions/climbing-stairs/) 63 | 64 | ### Python 65 | ```python 66 | class Solution: 67 | def climbStairs(n): 68 | if n < 1: 69 | return 0 70 | 71 | l = r = 1 72 | for _ in xrange(n - 1): 73 | l, r = r, r + l 74 | return r 75 | ``` 76 | 77 | ### C++ 78 | 79 | ```c++ 80 | class Solution { 81 | public: 82 | /** 83 | * @param n: An integer 84 | * @return: An integer 85 | */ 86 | int climbStairs(int n) { 87 | if (n < 1) { 88 | return 0; 89 | } 90 | 91 | int ret0 = 1, ret1 = 1, ret2 = 1; 92 | 93 | for (int i = 2; i != n + 1; ++i) { 94 | ret0 = ret1 + ret2; 95 | ret2 = ret1; 96 | ret1 = ret0; 97 | } 98 | 99 | return ret0; 100 | } 101 | }; 102 | ``` 103 | -------------------------------------------------------------------------------- /zh-hans/dynamic_programming/matrix.md: -------------------------------------------------------------------------------- 1 | # Matrix 2 | 3 | 本节主要总结矩阵类动态规划问题, 4 | -------------------------------------------------------------------------------- /zh-hans/dynamic_programming/unique_paths.md: -------------------------------------------------------------------------------- 1 | # Unique Paths 2 | 3 | - tags: [DP_Matrix] 4 | 5 | ## Question 6 | 7 | - lintcode: [(114) Unique Paths](http://www.lintcode.com/en/problem/unique-paths/) 8 | 9 | ``` 10 | A robot is located at the top-left corner of a m x n grid 11 | (marked 'Start' in the diagram below). 12 | 13 | The robot can only move either down or right at any point in time. 14 | The robot is trying to reach the bottom-right corner of the grid 15 | (marked 'Finish' in the diagram below). 16 | 17 | How many possible unique paths are there? 18 | 19 | Note 20 | m and n will be at most 100. 21 | ``` 22 | 23 | ## 题解 24 | 25 | 题目要求:给定*m x n*矩阵,求左上角到右下角的路径总数,每次只能向左或者向右前进。按照动态规划中矩阵类问题的通用方法: 26 | 27 | 1. State: f[m][n] 从起点到坐标(m,n)的路径数目 28 | 2. Function: f[m][n] = f[m-1][n] + f[m][n-1] 分析终点与左边及右边节点的路径数,发现从左边或者右边到达终点的路径一定不会重合,相加即为唯一的路径总数 29 | 3. Initialization: f[i][j] = 1, 到矩阵中任一节点均至少有一条路径,其实关键之处在于给第0行和第0列初始化,免去了单独遍历第0行和第0列进行初始化 30 | 4. Answer: f[m - 1][n - 1] 31 | 32 | ### C++ 33 | 34 | ```c++ 35 | class Solution { 36 | public: 37 | /** 38 | * @param n, m: positive integer (1 <= n ,m <= 100) 39 | * @return an integer 40 | */ 41 | int uniquePaths(int m, int n) { 42 | if (m < 1 || n < 1) { 43 | return 0; 44 | } 45 | 46 | vector > ret(m, vector(n, 1)); 47 | 48 | for (int i = 1; i != m; ++i) { 49 | for (int j = 1; j != n; ++j) { 50 | ret[i][j] = ret[i - 1][j] + ret[i][j - 1]; 51 | } 52 | } 53 | 54 | return ret[m - 1][n - 1]; 55 | } 56 | }; 57 | ``` 58 | 59 | ### 源码分析 60 | 61 | 1. 异常处理,虽然题目有保证为正整数,但还是判断一下以防万一 62 | 2. 初始化二维矩阵,值均为1 63 | 3. 按照转移矩阵函数进行累加 64 | 4. 任何`ret[m - 1][n - 1]` 65 | -------------------------------------------------------------------------------- /zh-hans/exhaustive_search/README.md: -------------------------------------------------------------------------------- 1 | # Exhaustive Search - 穷竭搜索 2 | 3 | 穷竭搜索又称暴力搜索,指代将所有可能性列出来,然后再在其中寻找满足题目条件的解。常用求解方法和工具有: 4 | 5 | 1. 递归函数 6 | 2. 栈 7 | 3. 队列 8 | 4. 深度优先搜索(DFS, Depth-First Search),又常称为回溯法 9 | 5. 广度优先搜索(BFS, Breadth-First Search) 10 | 11 | 1, 2, 3 往往在深搜或者广搜中体现。 12 | 13 | ## DFS 14 | 15 | DFS 通常从某个状态开始,根据特定的规则转移状态,直至无法转移(节点为空),然后回退到之前一步状态,继续按照指定规则转移状态,直至遍历完所有状态。 16 | 17 | 回溯法包含了多类问题,模板类似。 18 | 19 | 排列组合模板->搜索问题(是否要排序,哪些情况要跳过) 20 | 21 | 使用回溯法的一般步骤: 22 | 23 | 1. 确定所给问题的解空间:首先应明确定义问题的解空间,解空间中至少包含问题的一个解。 24 | 2. 确定结点的扩展搜索规则 25 | 3. 以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。 26 | 27 | ### BFS 28 | 29 | BFS 从某个状态开始,搜索**所有可以到达的状态**,转移顺序为『初始状态->只需一次转移就可到达的所有状态->只需两次转移就可到达的所有状态->...』,所以对于同一个状态,BFS 只搜索一次,故时间复杂度为 $$O(states \times transfer\_methods)$$. BFS 通常配合队列一起使用,搜索时先将状态加入到队列中,然后从队列顶端不断取出状态,再把从该状态可转移到的状态中尚未访问过的部分加入队列,知道队列为空或已找到解。因此 BFS 适合用于『由近及远』的搜索,比较适合用于求解最短路径、最少操作之类的问题。 30 | 31 | ## Reference 32 | 33 | - 《挑战程序设计竞赛》Chaper 2.1 p26 最基础的“穷竭搜索” 34 | - [Steven Skiena: Lecture15 - Backtracking](http://7xojrx.com1.z0.glb.clouddn.com/docs/algorithm-exercise/docs/lecture15-backtracking.pdf) 35 | - [全面解析回溯法:算法框架与问题求解 - 五岳 - 博客园](http://www.cnblogs.com/wuyuegb2312/p/3273337.html) 36 | - [五大常用算法之四:回溯法 - 红脸书生 - 博客园](http://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741376.html) 37 | - [演算法筆記 - Backtracking](http://www.csie.ntnu.edu.tw/~u91029/Backtracking.html) 38 | -------------------------------------------------------------------------------- /zh-hans/exhaustive_search/combinations.md: -------------------------------------------------------------------------------- 1 | # Combinations 2 | 3 | ## Question 4 | 5 | - leetcode: [Combinations | LeetCode OJ](https://leetcode.com/problems/combinations/) 6 | - lintcode: [(152) Combinations](http://www.lintcode.com/en/problem/combinations/) 7 | 8 | ### Problem Statement 9 | 10 | Given two integers n and k, 11 | return all possible combinations of k numbers out of 1 ... n. 12 | 13 | #### Example 14 | 15 | For example, 16 | If n = 4 and k = 2, a solution is: 17 | `[[2,4],[3,4],[2,3],[1,2],[1,3],[1,4]]` 18 | 19 | ## 题解 20 | 21 | 套用 [Permutations](http://algorithm.yuanbin.me/zh-hans/exhaustive_search/permutations.html) 模板。 22 | 23 | ### Java 24 | 25 | ```java 26 | public class Solution { 27 | public List> combine(int n, int k) { 28 | assert(n >= 1 && n >= k && k >= 1); 29 | 30 | List> result = new ArrayList>(); 31 | List list = new ArrayList(); 32 | dfs(n, k, 1, list, result); 33 | 34 | return result; 35 | } 36 | 37 | private void dfs(int n, int k, int pos, List list, 38 | List> result) { 39 | 40 | if (list.size() == k) { 41 | result.add(new ArrayList(list)); 42 | return; 43 | } 44 | for (int i = pos; i <= n; i++) { 45 | list.add(i); 46 | dfs(n, k, i + 1, list, result); 47 | list.remove(list.size() - 1); 48 | } 49 | } 50 | } 51 | ``` 52 | 53 | ### 源码分析 54 | 55 | 注意递归`helper(n, k, i + 1, list, result);`中的`i + 1`,不是`pos + 1`。 56 | 57 | ### 复杂度分析 58 | 59 | 状态数 $$C_n^2$$, 每组解有两个元素,故时间复杂度应为 $$O(n^2)$$. list 只保留最多两个元素,空间复杂度 $$O(1)$$. 60 | -------------------------------------------------------------------------------- /zh-hans/exhaustive_search/minimum_depth_of_binary_tree.md: -------------------------------------------------------------------------------- 1 | # Minimum Depth of Binary Tree 2 | 3 | ## Question 4 | 5 | - leetcode: [Minimum Depth of Binary Tree | LeetCode OJ](https://leetcode.com/problems/minimum-depth-of-binary-tree/) 6 | - lintcode: [(155) Minimum Depth of Binary Tree](http://www.lintcode.com/en/problem/minimum-depth-of-binary-tree/) 7 | 8 | ``` 9 | Given a binary tree, find its minimum depth. 10 | 11 | The minimum depth is the number of nodes along the shortest path 12 | from the root node down to the nearest leaf node. 13 | 14 | Example 15 | Given a binary tree as follow: 16 | 17 | 1 18 | 19 | / \ 20 | 21 | 2 3 22 | 23 | / \ 24 | 25 | 4 5 26 | The minimum depth is 2 27 | ``` 28 | 29 | ## 题解 30 | 31 | 注意审题,题中的最小深度指的是从根节点到**最近的叶子节点(因为题中的最小深度是the number of nodes,故该叶子节点不能是空节点)**,所以需要单独处理叶子节点为空的情况。此题使用 DFS 递归实现比较简单。 32 | 33 | ### Java 34 | 35 | ```java 36 | /** 37 | * Definition of TreeNode: 38 | * public class TreeNode { 39 | * public int val; 40 | * public TreeNode left, right; 41 | * public TreeNode(int val) { 42 | * this.val = val; 43 | * this.left = this.right = null; 44 | * } 45 | * } 46 | */ 47 | public class Solution { 48 | /** 49 | * @param root: The root of binary tree. 50 | * @return: An integer. 51 | */ 52 | public int minDepth(TreeNode root) { 53 | if (root == null) return 0; 54 | 55 | int leftDepth = minDepth(root.left); 56 | int rightDepth = minDepth(root.right); 57 | 58 | // current node is not leaf node 59 | if (root.left == null) { 60 | return 1 + rightDepth; 61 | } else if (root.right == null) { 62 | return 1 + leftDepth; 63 | } 64 | 65 | return 1 + Math.min(leftDepth, rightDepth); 66 | } 67 | } 68 | ``` 69 | 70 | ### 源码分析 71 | 72 | 建立好递归模型即可,左右子节点为空时需要单独处理下。 73 | 74 | ### 复杂度分析 75 | 76 | 每个节点遍历一次,时间复杂度 $$O(n)$$. 不计栈空间的话空间复杂度 $$O(1)$$. 77 | -------------------------------------------------------------------------------- /zh-hans/faq/README.md: -------------------------------------------------------------------------------- 1 | # FAQ - 常见问题答疑 2 | 3 | 本节主要整理一些常见问题,如『如何贡献』、『有疑问如何讨论』和授权协议等。 4 | 5 | ## 能说一下项目的背景吗? 6 | 7 | 最开始的维护者为 [@billryan](https://github.com/billryan), 由于他在学习算法的过程中需要使用 markdown 记录自己的学习心得,正好发现 Gitbook 很好地满足了他对使用 markdown 写技术笔记的所有幻想。 8 | 9 | ## 在网页上发现有错误的地方怎么办? 10 | 11 | 有两种相对轻量级一点的方式:disqus 评论和 GitHub 的 Web 界面更改。markdown 标记语言简明清晰,不会成为贡献内容的障碍。 12 | 13 | ### GitHub Edit Link 14 | 15 | 最简单的方式是通过网页最上方的『改进此页』在 GitHub 的 Web 界面上更改并提交 Pull Request. 也许你之前并没有 git 相关经验,没关系,下面的截图视频教你怎么玩儿。 16 | 17 | ![Pull Request in the GitHub Web](https://cloud.githubusercontent.com/assets/1292567/12375593/51494cd4-bd04-11e5-9e99-90f765dbe2e3.gif) 18 | 19 | 总结下来就是: 20 | 21 | 1. 点击『改进此页』 22 | 2. 跳转至 GitHub 登陆界面认证后在 Web 上更改你觉得有问题的地方 23 | 3. 改好后在下方的 comment 处简要说一下更改的理由 24 | 4. Pull Request 25 | 26 | 不要告诉我你没有 GitHub 账号... 27 | 28 | ### Disqus 29 | 30 | 如果你实在是不想在 GitHub 的 Contributor 处青史留名,那就通过这种方式吧!Maintainer 稍微辛苦点就是... 31 | 另外你也可以通过 Disqus 在相应网页下提出你的疑问。 32 | disqus 的评论处直接粘贴代码十分难看,参考 [syntax highlighting](https://help.disqus.com/customer/portal/articles/665057-syntax-highlighting) 改进。 33 | 34 | ## 我想成为重量级贡献者! 35 | 36 | 不要犹豫!快到碗里来!猛戳 [贡献指南](http://algorithm.yuanbin.me/zh-hans/faq/guidelines_for_contributing.html) 37 | 38 | ## 有暂时没出现在网页上的问题怎么办? 39 | 40 | 有两种方式:GitHub issues 和 Slack. 41 | 你可以加入 Slack 群 - 和我们一起讨论。 42 | 43 | ## 如何订阅更新的内容? 44 | 45 | 本项目托管在 由 [Gitbook](https://www.gitbook.com/book/yuanbin/algorithm/details) 渲染生成 HTML 页面。 46 | 你可以在 GitHub 中 star 该项目手动查看更新,也可以订阅 中的 `#github_commit` channel 在邮件中查看更新细节,~~RSS 种子功能正在开发中~~。 47 | 48 | Slack 的自助邀请注册功能已启用,访问 即刻开启~ 49 | Gitbook 虽然也有 star 和 subscribe 功能,但目前来看还是非常鸡肋,通过 Slack 的 `#github_commit` channel 你可以看到对单文件`diff`级别的改动。 50 | 51 | **号外:Slack 的 [shua-shua-shua](https://ds-algo.slack.com/messages/shua-shua-shua/details/) channel 用于刷题小组讨论,大家可以在这个 channel 里一起讨论学习算法。** 52 | 53 | ## 我觉得这个文档整理的真好,接受捐助吗? 54 | 55 | 当然!除了 GitHub 上 star 或者帮助改进内容外,你还可以以现金或者其他实物激励我们创造出更好的内容! 56 | 57 | ### 邮寄明信片 58 | 59 | @billryan 喜欢收集各种明信片,来者不拒~ 邮寄的话可以邮寄至 `上海市闵行区上海交通大学闵行校区电院群楼5号楼307`,收件人:`袁斌`。 60 | 61 | ### 送书 62 | 63 | 除了邮寄明信片,你还可以买本书送给各位贡献者,@billryan 的地址见上节。 64 | 65 | ### 支付宝 66 | 67 | ![支付宝打赏](../../shared-files/images/alipay_billryan_qr15x15.jpg) 68 | 69 | 账户名:yuanbin2014(at)gmail.com 金额随意 70 | 71 | ### Wechat 72 | 73 | ![Red Packet](../../shared-files/images/wechat_billryan_qr15x15.jpg) 74 | 75 | 金额随意 76 | 77 | ### PayPal 78 | 79 | 账户名:yuanbin2014(at)gmail.com 金额随意,付款时选择 friends and family 80 | -------------------------------------------------------------------------------- /zh-hans/google_apac/README.md: -------------------------------------------------------------------------------- 1 | # Google APAC 2 | 3 | 本章总结 Google APAC 的一些题。 4 | -------------------------------------------------------------------------------- /zh-hans/google_apac/google_apac_2015_round_b/A-large-practice.in: -------------------------------------------------------------------------------- 1 | 100 2 | 1 1 3 | 3 4 4 | 5 5 5 | 15 15 6 | 100 100 7 | 66 100 8 | 77 97 9 | 7 11 10 | 36 47 11 | 10 41 12 | 31 35 13 | 4 42 14 | 81 85 15 | 41 84 16 | 20 85 17 | 46 95 18 | 17 30 19 | 6 25 20 | 2 4 21 | 2 2 22 | 71 99 23 | 12 12 24 | 27 65 25 | 6 39 26 | 9 15 27 | 3 22 28 | 2 51 29 | 47 63 30 | 5 17 31 | 6 28 32 | 40 53 33 | 42 64 34 | 40 100 35 | 5 37 36 | 47 53 37 | 42 65 38 | 65 88 39 | 90 99 40 | 37 50 41 | 1 15 42 | 3 67 43 | 32 65 44 | 7 55 45 | 20 56 46 | 23 24 47 | 1 25 48 | 6 9 49 | 14 58 50 | 24 79 51 | 6 15 52 | 12 36 53 | 31 34 54 | 8 8 55 | 3 27 56 | 9 68 57 | 11 25 58 | 40 81 59 | 46 55 60 | 50 67 61 | 5 7 62 | 33 45 63 | 7 18 64 | 41 74 65 | 4 12 66 | 39 72 67 | 10 34 68 | 24 58 69 | 9 82 70 | 29 51 71 | 21 25 72 | 30 53 73 | 25 56 74 | 83 89 75 | 3 68 76 | 26 72 77 | 37 49 78 | 2 8 79 | 13 20 80 | 39 92 81 | 15 84 82 | 25 61 83 | 36 74 84 | 27 89 85 | 9 86 86 | 1 19 87 | 5 13 88 | 6 11 89 | 4 4 90 | 15 82 91 | 1 6 92 | 28 97 93 | 16 20 94 | 33 71 95 | 47 89 96 | 4 26 97 | 20 29 98 | 19 45 99 | 5 8 100 | 7 13 101 | 12 76 102 | -------------------------------------------------------------------------------- /zh-hans/google_apac/google_apac_2015_round_b/A-small-practice.in: -------------------------------------------------------------------------------- 1 | 15 2 | 1 1 3 | 3 4 4 | 5 5 5 | 7 7 6 | 4 7 7 | 4 4 8 | 6 6 9 | 1 7 10 | 1 2 11 | 1 6 12 | 2 4 13 | 1 5 14 | 6 7 15 | 5 5 16 | 3 4 17 | -------------------------------------------------------------------------------- /zh-hans/google_apac/google_apac_2015_round_b/README.md: -------------------------------------------------------------------------------- 1 | # APAC 2015 Round B 2 | 3 | - [Dashboard - Round B APAC Test - Google Code Jam](https://code.google.com/codejam/contest/4214486/dashboard) 4 | -------------------------------------------------------------------------------- /zh-hans/google_apac/google_apac_2015_round_b/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class Solution { 4 | public static void main(String[] args) { 5 | Scanner in = new Scanner(System.in); 6 | int T = in.nextInt(); 7 | // System.out.println("T = " + T); 8 | for (int t = 1; t <= T; t++) { 9 | int M = in.nextInt(), N = in.nextInt(); 10 | long ans = solve(M, N); 11 | // System.out.printf("M = %d, N = %d\n", M, N); 12 | System.out.printf("Case #%d: %d\n", t, ans); 13 | } 14 | } 15 | 16 | public static long solve(int M, int N) { 17 | long[][] dp = new long[1 + M][1 + N]; 18 | long mod = 1000000007; 19 | for (int j = 1; j <= N; j++) { 20 | dp[1][j] = 1; 21 | } 22 | for (int i = 2; i <= M; i++) { 23 | for (int j = i; j <= N; j++) { 24 | dp[i][j] = i * (dp[i][j - 1] + dp[i - 1][j - 1]); 25 | dp[i][j] %= mod; 26 | } 27 | } 28 | 29 | return dp[M][N]; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /zh-hans/google_apac/google_apac_2016_round_d/README.md: -------------------------------------------------------------------------------- 1 | # APAC 2016 Round D 2 | 3 | - [Dashboard - Round D APAC Test 2016 - Google Code Jam](https://code.google.com/codejam/contest/11214486/dashboard) 4 | -------------------------------------------------------------------------------- /zh-hans/google_apac/google_apac_2016_round_d/Solution.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class Solution { 4 | public static void main(String[] args) { 5 | Scanner in = new Scanner(System.in); 6 | int T = in.nextInt(); 7 | // System.out.println("T = " + T); 8 | for (int t = 1; t <= T; t++) { 9 | int R = in.nextInt(), C = in.nextInt(); 10 | int[][] grid = new int[R][C]; 11 | // System.out.println("R = " + R + ", C = " + C); 12 | in.nextLine(); 13 | for (int r = 0; r < R; r++) { 14 | String row = in.nextLine(); 15 | // System.out.println(row); 16 | for (int c = 0; c < C; c++) { 17 | int z = Character.getNumericValue(row.charAt(c)); 18 | grid[r][c] = z; 19 | } 20 | } 21 | int N = in.nextInt(); 22 | in.nextLine(); 23 | System.out.printf("Case #%d:\n", t); 24 | int[][] gridNew = new int[R][C]; 25 | for (int i = 0; i < N; i++) { 26 | String[] tokens = in.nextLine().split(" "); 27 | if (tokens[0].equals("Q")) { 28 | for (int r = 0; r < R; r++) { 29 | for (int c = 0; c < C; c++) { 30 | gridNew[r][c] = grid[r][c]; 31 | } 32 | } 33 | int ans = solve(gridNew); 34 | // System.out.printf("M = %d, N = %d\n", M, N); 35 | System.out.println(ans); 36 | } else { 37 | int tx = Integer.parseInt(tokens[1]); 38 | int ty = Integer.parseInt(tokens[2]); 39 | int tz = Integer.parseInt(tokens[3]); 40 | grid[tx][ty] = tz; 41 | } 42 | } 43 | } 44 | } 45 | 46 | public static int solve(int[][] grid) { 47 | if (grid == null || grid.length == 0) { 48 | return -1; 49 | } 50 | 51 | int R = grid.length, C = grid[0].length; 52 | int res = 0; 53 | for (int r = 0; r < R; r++) { 54 | for (int c = 0; c < C; c++) { 55 | if (grid[r][c] == 1) { 56 | dfs(grid, r, c); 57 | res++; 58 | } 59 | } 60 | } 61 | return res; 62 | } 63 | 64 | private static void dfs(int[][] grid, int x, int y) { 65 | int R = grid.length, C = grid[0].length; 66 | grid[x][y] = 0; 67 | for (int dx = -1; dx <= 1; dx++) { 68 | for (int dy = -1; dy <= 1; dy++) { 69 | int nx = x + dx, ny = y + dy; 70 | // up, down, left, right 71 | if (Math.abs(nx + ny - x - y) != 1) continue; 72 | if (0 <= nx && nx < R && 0 <= ny && ny < C) { 73 | if (grid[nx][ny] == 1) dfs(grid, nx, ny); 74 | } 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /zh-hans/graph/README.md: -------------------------------------------------------------------------------- 1 | # Graph 2 | 3 | 本章主要总结图与搜索相关题目。 4 | -------------------------------------------------------------------------------- /zh-hans/integer_array/README.md: -------------------------------------------------------------------------------- 1 | # Integer Array - 整型数组 2 | 3 | 本章主要总结与整型数组相关的题。 4 | -------------------------------------------------------------------------------- /zh-hans/integer_array/partition_array_by_odd_and_even.md: -------------------------------------------------------------------------------- 1 | # Partition Array by Odd and Even 2 | 3 | ## Question 4 | 5 | - lintcode: [(373) Partition Array by Odd and Even](http://www.lintcode.com/en/problem/partition-array-by-odd-and-even/) 6 | - [Segregate Even and Odd numbers - GeeksforGeeks](http://www.geeksforgeeks.org/segregate-even-and-odd-numbers/) 7 | 8 | ``` 9 | Partition an integers array into odd number first and even number second. 10 | 11 | Example 12 | Given [1, 2, 3, 4], return [1, 3, 2, 4] 13 | 14 | Challenge 15 | Do it in-place. 16 | ``` 17 | 18 | ## 题解 19 | 20 | 将数组中的奇数和偶数分开,使用『两根指针』的方法最为自然,奇数在前,偶数在后,若不然则交换之。 21 | 22 | ### Java 23 | 24 | ```java 25 | public class Solution { 26 | /** 27 | * @param nums: an array of integers 28 | * @return: nothing 29 | */ 30 | public void partitionArray(int[] nums) { 31 | if (nums == null) return; 32 | 33 | int left = 0, right = nums.length - 1; 34 | while (left < right) { 35 | // odd number 36 | while (left < right && nums[left] % 2 != 0) { 37 | left++; 38 | } 39 | // even number 40 | while (left < right && nums[right] % 2 == 0) { 41 | right--; 42 | } 43 | // swap 44 | if (left < right) { 45 | int temp = nums[left]; 46 | nums[left] = nums[right]; 47 | nums[right] = temp; 48 | } 49 | } 50 | } 51 | } 52 | ``` 53 | 54 | ### C++ 55 | ``` c++ 56 | void partitionArray(vector &nums) { 57 | if (nums.empty()) return; 58 | 59 | int i=0, j=nums.size()-1; 60 | while (i &nums) { 37 | if (nums.size() <= 1) return nums.size(); 38 | 39 | int len = nums.size(); 40 | int newIndex = 0; 41 | for (int i = 1; i< len; ++i) { 42 | if (nums[i] != nums[newIndex]) { 43 | newIndex++; 44 | nums[newIndex] = nums[i]; 45 | } 46 | } 47 | 48 | return newIndex + 1; 49 | } 50 | }; 51 | ``` 52 | 53 | ### Java 54 | 55 | ```java 56 | public class Solution { 57 | /** 58 | * @param A: a array of integers 59 | * @return : return an integer 60 | */ 61 | public int removeDuplicates(int[] nums) { 62 | if (nums == null) return -1; 63 | if (nums.length <= 1) return nums.length; 64 | 65 | int newIndex = 0; 66 | for (int i = 1; i < nums.length; i++) { 67 | if (nums[i] != nums[newIndex]) { 68 | newIndex++; 69 | nums[newIndex] = nums[i]; 70 | } 71 | } 72 | 73 | return newIndex + 1; 74 | } 75 | } 76 | ``` 77 | 78 | ### 源码分析 79 | 80 | 注意最后需要返回的是索引值加1。 81 | 82 | ### 复杂度分析 83 | 84 | 遍历一次数组,时间复杂度 $$O(n)$$, 空间复杂度 $$O(1)$$. 85 | -------------------------------------------------------------------------------- /zh-hans/integer_array/remove_duplicates_from_sorted_array_ii.md: -------------------------------------------------------------------------------- 1 | # Remove Duplicates from Sorted Array II 2 | 3 | ## Question 4 | 5 | - leetcode: [Remove Duplicates from Sorted Array II | LeetCode OJ](https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/) 6 | - lintcode: [(101) Remove Duplicates from Sorted Array II](http://www.lintcode.com/en/problem/remove-duplicates-from-sorted-array-ii/) 7 | 8 | ``` 9 | Follow up for "Remove Duplicates": 10 | What if duplicates are allowed at most twice? 11 | 12 | For example, 13 | Given sorted array A = [1,1,1,2,2,3], 14 | 15 | Your function should return length = 5, and A is now [1,1,2,2,3]. 16 | Example 17 | ``` 18 | 19 | ## 题解 20 | 21 | 在上题基础上加了限制条件元素最多可重复出现两次。~~因此可以在原题的基础上添加一变量跟踪元素重复出现的次数,小于指定值时执行赋值操作。但是需要注意的是重复出现次数`occurence`的初始值(从1开始,而不是0)和reset的时机。~~这种方法比较复杂,谢谢 @meishenme 提供的简洁方法,核心思想仍然是两根指针,只不过此时新索引自增的条件是当前遍历的数组值和『新索引』或者『新索引-1』两者之一不同。 22 | 23 | ### C++ 24 | 25 | ```c++ 26 | class Solution { 27 | public: 28 | /** 29 | * @param A: a list of integers 30 | * @return : return an integer 31 | */ 32 | int removeDuplicates(vector &nums) { 33 | if (nums.size() <= 2) return nums.size(); 34 | 35 | int len = nums.size(); 36 | int newIndex = 1; 37 | for (int i = 2; i < len; ++i) { 38 | if (nums[i] != nums[newIndex] || nums[i] != nums[newIndex - 1]) { 39 | ++newIndex; 40 | nums[newIndex] = nums[i]; 41 | } 42 | } 43 | 44 | return newIndex + 1; 45 | } 46 | }; 47 | ``` 48 | 49 | ### Java 50 | 51 | ```java 52 | public class Solution { 53 | /** 54 | * @param A: a array of integers 55 | * @return : return an integer 56 | */ 57 | public int removeDuplicates(int[] nums) { 58 | if (nums == null) return -1; 59 | if (nums.length <= 2) return nums.length; 60 | 61 | int newIndex = 1; 62 | for (int i = 2; i < nums.length; i++) { 63 | if (nums[i] != nums[newIndex] || nums[i] != nums[newIndex - 1]) { 64 | newIndex++; 65 | nums[newIndex] = nums[i]; 66 | } 67 | } 68 | 69 | return newIndex + 1; 70 | } 71 | } 72 | ``` 73 | 74 | ### 源码分析 75 | 76 | 遍历数组时 i 从2开始,newIndex 初始化为1便于分析。 77 | 78 | ### 复杂度分析 79 | 80 | 时间复杂度 $$O(n)$$, 空间复杂度 $$O(1)$$. 81 | -------------------------------------------------------------------------------- /zh-hans/interview/facebook_interview.md: -------------------------------------------------------------------------------- 1 | # Facebook Technical Coding Interview 2 | 3 | Frank Qixing Du shared his experience of coding interview and writing resume. 4 | 5 | - Detailed notes: [Facebook学长交流分享 - biaobiaoqi](http://www.cnblogs.com/biaobiaoqi/p/3753750.html) 6 | - [Frank DU | LinkedIn](https://www.linkedin.com/pub/frank-du/4/790/3b8) 7 | -------------------------------------------------------------------------------- /zh-hans/interview/google_interview.md: -------------------------------------------------------------------------------- 1 | # Google interview experience 2 | 3 | ## Brief self-introduction 4 | 5 | 1. Name, school, major 6 | 2. Previous projects and internships 7 | 3. Major accomplishments, etc. 8 | 9 | ## Technical assessment 10 | 11 | 1. Building and developing algorithms 12 | 2. Coding 13 | 3. Basic CS knowledge 14 | 4. Data Structure 15 | 5. Read-world problem solving 16 | 17 | ## Other Reference 18 | 19 | - [面试体验:Google 篇 - Cat Chen - 博客园](http://www.cnblogs.com/cathsfz/archive/2012/08/08/google-interview-experience.html) 20 | -------------------------------------------------------------------------------- /zh-hans/linked_list/README.md: -------------------------------------------------------------------------------- 1 | # Linked List - 链表 2 | 3 | 本节包含链表的一些常用操作,如删除、插入和合并等。 4 | 5 | 常见错误有 遍历链表不向前递推节点,遍历链表前未保存头节点,返回链表节点指针错误。 6 | 7 | 8 | 下图是把本章中所有出现的题目归类总结了一下,便于记忆 9 | 10 | ![链表](../../shared-files/images/linked_list_summary.png) -------------------------------------------------------------------------------- /zh-hans/linked_list/lru_cache.md: -------------------------------------------------------------------------------- 1 | # LRU Cache 2 | 3 | ## Question 4 | 5 | - leetcode: [LRU Cache | LeetCode OJ](https://leetcode.com/problems/lru-cache/) 6 | - lintcode: [(134) LRU Cache](http://www.lintcode.com/en/problem/lru-cache/) 7 | 8 | ### Problem Statement 9 | 10 | 11 | Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: `get` and `set`. 12 | 13 | `get(key)` - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. 14 | 15 | `set(key, value)` - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item. 16 | 17 | ## 题解 18 | 19 | ### Java 20 | 21 | ```java 22 | public class Solution { 23 | private int capacity; 24 | private HashMap map = new HashMap<>(); 25 | private Node head = new Node(-1, -1), tail = new Node(-1, -1); 26 | 27 | private class Node { 28 | Node prev, next; 29 | int val, key; 30 | 31 | public Node(int key, int val) { 32 | this.val = val; 33 | this.key = key; 34 | prev = null; 35 | next = null; 36 | } 37 | 38 | // @Override 39 | // public String toString() { 40 | // return "(" + key + ", " + val + ") " + "last:" 41 | // + (prev == null ? "null" : "node"); 42 | // } 43 | } 44 | 45 | public Solution(int capacity) { 46 | this.capacity = capacity; 47 | tail.prev = head; 48 | head.next = tail; 49 | } 50 | 51 | public int get(int key) { 52 | if (!map.containsKey(key)) { 53 | return -1; 54 | } 55 | // remove current 56 | Node currentNode = map.get(key); 57 | currentNode.prev.next = currentNode.next; 58 | currentNode.next.prev = currentNode.prev; 59 | 60 | // move current to tail; 61 | moveToTail(currentNode); 62 | 63 | return map.get(key).val; 64 | } 65 | 66 | public void set(int key, int value) { 67 | if (get(key) != -1) { 68 | map.get(key).val = value; 69 | return; 70 | } 71 | if (map.size() == capacity) { 72 | map.remove(head.next.key); 73 | head.next = head.next.next; 74 | head.next.prev = head; 75 | } 76 | Node insert = new Node(key, value); 77 | map.put(key, insert); 78 | moveToTail(insert); 79 | } 80 | 81 | private void moveToTail(Node current) { 82 | current.prev = tail.prev; 83 | tail.prev = current; 84 | current.prev.next = current; 85 | current.next = tail; 86 | } 87 | } 88 | 89 | ``` 90 | -------------------------------------------------------------------------------- /zh-hans/linked_list/remove_linked_list_elements.md: -------------------------------------------------------------------------------- 1 | # Remove Linked List Elements 2 | 3 | ## Question 4 | 5 | - leetcode: [Remove Linked List Elements | LeetCode OJ](https://leetcode.com/problems/remove-linked-list-elements/) 6 | - lintcode: [(452) Remove Linked List Elements](http://www.lintcode.com/en/problem/remove-linked-list-elements/) 7 | 8 | ### Problem Statement 9 | 10 | Remove all elements from a linked list of integers that have value `val`. 11 | 12 | #### Example 13 | 14 | Given `1->2->3->3->4->5->3`, val = 3, you should return the list as 15 | `1->2->4->5` 16 | 17 | ## 题解 18 | 19 | 删除链表中指定值,找到其前一个节点即可,将 next 指向下一个节点即可。 20 | 21 | ### Python 22 | 23 | ```python 24 | # Definition for singly-linked list. 25 | # class ListNode(object): 26 | # def __init__(self, x): 27 | # self.val = x 28 | # self.next = None 29 | 30 | class Solution(object): 31 | def removeElements(self, head, val): 32 | """ 33 | :type head: ListNode 34 | :type val: int 35 | :rtype: ListNode 36 | """ 37 | dummy = ListNode(0) 38 | dummy.next = head 39 | curr = dummy 40 | while curr.next is not None: 41 | if curr.next.val == val: 42 | curr.next = curr.next.next 43 | else: 44 | curr = curr.next 45 | 46 | return dummy.next 47 | ``` 48 | 49 | ### Java 50 | 51 | ```java 52 | /** 53 | * Definition for singly-linked list. 54 | * public class ListNode { 55 | * int val; 56 | * ListNode next; 57 | * ListNode(int x) { val = x; } 58 | * } 59 | */ 60 | public class Solution { 61 | /** 62 | * @param head a ListNode 63 | * @param val an integer 64 | * @return a ListNode 65 | */ 66 | public ListNode removeElements(ListNode head, int val) { 67 | ListNode dummy = new ListNode(0); 68 | dummy.next = head; 69 | ListNode curr = dummy; 70 | while (curr.next != null) { 71 | if (curr.next.val == val) { 72 | curr.next = curr.next.next; 73 | } else { 74 | curr = curr.next; 75 | } 76 | } 77 | 78 | return dummy.next; 79 | } 80 | } 81 | ``` 82 | 83 | ### 源码分析 84 | 85 | while 循环中使用`curr.next`较为方便,if 语句中比较时也使用`curr.next.val`也比较简洁,如果使用`curr`会比较难处理。 86 | 87 | ### 复杂度分析 88 | 89 | 略 90 | -------------------------------------------------------------------------------- /zh-hans/linked_list/rotate_list.md: -------------------------------------------------------------------------------- 1 | # Rotate List 2 | 3 | ## Question 4 | 5 | - leetcode: [Rotate List | LeetCode OJ](https://leetcode.com/problems/rotate-list/) 6 | - lintcode: [(170) Rotate List](http://www.lintcode.com/en/problem/rotate-list/) 7 | 8 | ### Problem Statement 9 | 10 | Given a list, rotate the list to the right by _k_ places, where _k_ is non- 11 | negative. 12 | 13 | #### Example 14 | 15 | Given `1->2->3->4->5` and k = `2`, return `4->5->1->2->3`. 16 | 17 | ## 题解 18 | 19 | 旋转链表,链表类问题通常需要找到需要处理节点处的前一个节点。因此我们只需要找到旋转节点和最后一个节点即可。需要注意的细节是 k 有可能比链表长度还要大,此时需要取模,另一个 corner case 则是链表长度和 k 等长。 20 | 21 | ### Java 22 | 23 | ```java 24 | /** 25 | * Definition for singly-linked list. 26 | * public class ListNode { 27 | * int val; 28 | * ListNode next; 29 | * ListNode(int x) { 30 | * val = x; 31 | * next = null; 32 | * } 33 | * } 34 | */ 35 | public class Solution { 36 | /** 37 | * @param head: the List 38 | * @param k: rotate to the right k places 39 | * @return: the list after rotation 40 | */ 41 | public ListNode rotateRight(ListNode head, int k) { 42 | if (head == null) return head; 43 | ListNode fast = head, slow = head; 44 | int len = 1; 45 | for (len = 1; fast.next != null && len <= k; len++) { 46 | fast = fast.next; 47 | } 48 | // k mod len if k > len 49 | if (len <= k) { 50 | k = k % len; 51 | fast = head; 52 | for (int i = 0; i < k; i++) { 53 | fast = fast.next; 54 | } 55 | } 56 | // forward slow and fast 57 | while (fast.next != null) { 58 | fast = fast.next; 59 | slow = slow.next; 60 | } 61 | // return new head 62 | fast.next = head; 63 | head = slow.next; 64 | slow.next = null; 65 | 66 | return head; 67 | } 68 | } 69 | ``` 70 | 71 | ### 源码分析 72 | 73 | 由于需要处理的是节点的前一个节点,故最终的`while` 循环使用`fast.next != null`. k 与链表等长时包含在`len <= k`中。 74 | 75 | ### 复杂度分析 76 | 77 | 时间复杂度 $$O(n)$$, 空间复杂度 $$O(1)$$. 78 | -------------------------------------------------------------------------------- /zh-hans/linked_list/two_lists_sum_advanced.md: -------------------------------------------------------------------------------- 1 | # Two Lists Sum Advanced 2 | 3 | ## Question 4 | 5 | - CC150 - [Add two numbers represented by linked lists | Set 2 - GeeksforGeeks](http://www.geeksforgeeks.org/sum-of-two-linked-lists/) 6 | 7 | ``` 8 | Given two numbers represented by two linked lists, write a function that returns sum list. 9 | The sum list is linked list representation of addition of two input numbers. 10 | 11 | Example 12 | 13 | Input: 14 | First List: 5->6->3 // represents number 563 15 | Second List: 8->4->2 // represents number 842 16 | Output 17 | Resultant list: 1->4->0->5 // represents number 1405 18 | 19 | Challenge 20 | 21 | Not allowed to modify the lists. 22 | Not allowed to use explicit extra space. 23 | ``` 24 | 25 | ## 题解1 - 反转链表 26 | 27 | 在题 [Two Lists Sum | Data Structure and Algorithm](http://algorithm.yuanbin.me/zh-hans/linked_list/two_lists_sum.html) 的基础上改了下数位的表示方式,前者低位在前,高位在后,这个题的高位在前,低位在后。很自然地可以联想到先将链表反转,而后再使用 Two Lists Sum 的解法。 28 | 29 | ## Reference 30 | 31 | - [Add two numbers represented by linked lists | Set 2 - GeeksforGeeks](http://www.geeksforgeeks.org/sum-of-two-linked-lists/) 32 | -------------------------------------------------------------------------------- /zh-hans/math_and_bit_manipulation/README.md: -------------------------------------------------------------------------------- 1 | # Bit Manipulation 2 | 3 | 位运算的题大多较为灵活,涉及较多的按位与/或/异或等特性。 4 | 5 | ## Reference 6 | 7 | - [位运算简介及实用技巧(一):基础篇 | Matrix67: The Aha Moments](http://www.matrix67.com/blog/archives/263) 8 | - *cc150* chapter 8.5 and chapter 9.5 9 | -------------------------------------------------------------------------------- /zh-hans/math_and_bit_manipulation/a_plus_b_problem.md: -------------------------------------------------------------------------------- 1 | # A plus B Problem 2 | 3 | ## Question 4 | 5 | - lintcode: [(1) A + B Problem](http://www.lintcode.com/en/problem/a-b-problem/) 6 | 7 | ``` 8 | Write a function that add two numbers A and B. 9 | You should not use + or any arithmetic operators. 10 | 11 | 12 | Example 13 | Given a=1 and b=2 return 3 14 | 15 | Note 16 | There is no need to read data from standard input stream. 17 | Both parameters are given in function aplusb, 18 | you job is to calculate the sum and return it. 19 | Challenge 20 | Of course you can just return a + b to get accepted. 21 | But Can you challenge not do it like that? 22 | Clarification 23 | Are a and b both 32-bit integers? 24 | Yes. 25 | Can I use bit operation? 26 | 27 | Sure you can. 28 | ``` 29 | 30 | ## 题解 31 | 32 | 不用加减法实现加法,类似数字电路中的全加器,异或求得部分和,相与求得进位,最后将进位作为加法器的输入,典型的递归实现思路。 33 | 34 | ### Java 35 | 36 | ```java 37 | class Solution { 38 | /* 39 | * param a: The first integer 40 | * param b: The second integer 41 | * return: The sum of a and b 42 | */ 43 | public int aplusb(int a, int b) { 44 | int result = a ^ b; 45 | int carry = a & b; 46 | carry <<= 1; 47 | if (carry != 0) { 48 | result = aplusb(result, carry); 49 | } 50 | 51 | return result; 52 | } 53 | } 54 | ``` 55 | 56 | ### 源码分析 57 | 58 | 递归步为进位是否为0,为0时返回。 59 | 60 | ### 复杂度分析 61 | 62 | 取决于进位,近似为 $$O(1)$$. 使用了部分额外变量,空间复杂度为 $$O(1)$$. 63 | -------------------------------------------------------------------------------- /zh-hans/math_and_bit_manipulation/count_1_in_binary.md: -------------------------------------------------------------------------------- 1 | # Count 1 in Binary 2 | 3 | ## Question 4 | 5 | - lintcode: [(365) Count 1 in Binary](http://www.lintcode.com/en/problem/count-1-in-binary/) 6 | 7 | ``` 8 | Count how many 1 in binary representation of a 32-bit integer. 9 | 10 | Example 11 | Given 32, return 1 12 | 13 | Given 5, return 2 14 | 15 | Given 1023, return 9 16 | 17 | Challenge 18 | If the integer is n bits with m 1 bits. Can you do it in O(m) time? 19 | ``` 20 | 21 | ## 题解 22 | 23 | 题 [O1 Check Power of 2](http://algorithm.yuanbin.me/zh-hans/math_and_bit_manipulation/o1_check_power_of_2.html) 的进阶版,`x & (x - 1)` 的含义为去掉二进制数中1的最后一位,无论 x 是正数还是负数都成立。 24 | 25 | ### C++ 26 | ``` c++ 27 | class Solution { 28 | public: 29 | /** 30 | * @param num: an integer 31 | * @return: an integer, the number of ones in num 32 | */ 33 | int countOnes(int num) { 34 | int count=0; 35 | while (num) { 36 | num &= num-1; 37 | count++; 38 | } 39 | return count; 40 | } 41 | }; 42 | ``` 43 | 44 | ### Java 45 | 46 | ```java 47 | public class Solution { 48 | /** 49 | * @param num: an integer 50 | * @return: an integer, the number of ones in num 51 | */ 52 | public int countOnes(int num) { 53 | int count = 0; 54 | while (num != 0) { 55 | num = num & (num - 1); 56 | count++; 57 | } 58 | 59 | return count; 60 | } 61 | } 62 | ``` 63 | 64 | ### 源码分析 65 | 66 | 累加计数器即可。 67 | 68 | ### 复杂度分析 69 | 70 | 这种算法依赖于数中1的个数,时间复杂度为 $$O(m)$$. 空间复杂度 $$O(1)$$. 71 | 72 | ## Reference 73 | 74 | - [Number of 1 bits | LeetCode](http://articles.leetcode.com/2010/09/number-of-1-bits.html) - 评论中有关于不同算法性能的讨论 75 | -------------------------------------------------------------------------------- /zh-hans/math_and_bit_manipulation/digit_counts.md: -------------------------------------------------------------------------------- 1 | # Digit Counts 2 | 3 | ## Question 4 | 5 | - leetcode: [Number of Digit One | LeetCode OJ](https://leetcode.com/problems/number-of-digit-one/) 6 | - lintcode: [(3) Digit Counts](http://www.lintcode.com/en/problem/digit-counts/) 7 | 8 | ``` 9 | Count the number of k's between 0 and n. k can be 0 - 9. 10 | 11 | Example 12 | if n=12, k=1 in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 13 | we have FIVE 1's (1, 10, 11, 12) 14 | ``` 15 | 16 | ## 题解 17 | 18 | leetcode 上的有点简单,这里以 Lintcode 上的为例进行说明。找出从0至整数 n 中出现数位k的个数,与整数有关的题大家可能比较容易想到求模求余等方法,但其实很多与整数有关的题使用字符串的解法更为便利。将整数 i 分解为字符串,然后遍历之,自增 k 出现的次数即可。 19 | 20 | ### C++ 21 | ```c++ 22 | class Solution { 23 | public: 24 | /* 25 | * param k : As description. 26 | * param n : As description. 27 | * return: How many k's between 0 and n. 28 | */ 29 | int digitCounts(int k, int n) { 30 | char c = k + '0'; 31 | int count = 0; 32 | for (int i = k; i <= n; i++) { 33 | for (auto s : to_string(i)) { 34 | if (s == c) count++; 35 | } 36 | } 37 | return count; 38 | } 39 | }; 40 | ``` 41 | 42 | ### Java 43 | 44 | ```java 45 | class Solution { 46 | /* 47 | * param k : As description. 48 | * param n : As description. 49 | * return: An integer denote the count of digit k in 1..n 50 | */ 51 | public int digitCounts(int k, int n) { 52 | int count = 0; 53 | char kChar = (char)(k + '0'); 54 | for (int i = k; i <= n; i++) { 55 | char[] iChars = Integer.toString(i).toCharArray(); 56 | for (char iChar : iChars) { 57 | if (kChar == iChar) count++; 58 | } 59 | } 60 | 61 | return count; 62 | } 63 | } 64 | ``` 65 | 66 | ### 源码分析 67 | 68 | 太简单了,略 69 | 70 | ### 复杂度分析 71 | 72 | 时间复杂度 $$O(n \times L)$$, L 为n 的最大长度,拆成字符数组,空间复杂度 $$O(L)$$. 73 | -------------------------------------------------------------------------------- /zh-hans/math_and_bit_manipulation/fibonacci.md: -------------------------------------------------------------------------------- 1 | # Fibonacci 2 | 3 | ## Question 4 | 5 | - lintcode: [(366) Fibonacci](http://www.lintcode.com/en/problem/fibonacci/) 6 | 7 | ### Problem Statement 8 | 9 | Find the _N_th number in Fibonacci sequence. 10 | 11 | A Fibonacci sequence is defined as follow: 12 | 13 | * The first two numbers are 0 and 1. 14 | * The _i_ th number is the sum of _i_-1 th number and _i_-2 th number. 15 | 16 | The first ten numbers in Fibonacci sequence is: 17 | 18 | `0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ...` 19 | 20 | #### Example 21 | 22 | Given `1`, return `0` 23 | 24 | Given `2`, return `1` 25 | 26 | Given `10`, return `34` 27 | 28 | #### Note 29 | 30 | The _N_th fibonacci number won't exceed the max value of signed 32-bit integer 31 | in the test cases. 32 | 33 | ## 题解 34 | 35 | 斐波那契数列使用递归极其容易实现,其实使用非递归的方法也很容易,不断向前滚动即可。 36 | 37 | ### C++ 38 | ```c++ 39 | class Solution{ 40 | public: 41 | /** 42 | * @param n: an integer 43 | * @return an integer f(n) 44 | */ 45 | int fibonacci(int n) { 46 | if (n <= 0) return -1; 47 | if (n == 1) return 0; 48 | if (n == 2) return 1; 49 | 50 | int fn = 0, fn1 = 0, fn2 = 1; 51 | for (int i = 3; i <= n; i++) { 52 | fn = fn1 + fn2; 53 | fn1 = fn2; 54 | fn2 = fn; 55 | } 56 | return fn; 57 | } 58 | }; 59 | ``` 60 | 61 | ### Java 62 | 63 | ```java 64 | class Solution { 65 | /** 66 | * @param n: an integer 67 | * @return an integer f(n) 68 | */ 69 | public int fibonacci(int n) { 70 | if (n <= 0) return -1; 71 | if (n == 1) return 0; 72 | if (n == 2) return 1; 73 | 74 | int fn = 0, fn1 = 1, fn2 = 0; 75 | for (int i = 3; i <= n; i++) { 76 | fn = fn1 + fn2; 77 | fn2 = fn1; 78 | fn1 = fn; 79 | } 80 | 81 | return fn; 82 | } 83 | } 84 | ``` 85 | 86 | ### 源码分析 87 | 88 | 1. corner cases 89 | 2. 初始化 fn, fn1, fn2, 建立地推关系。 90 | 3. 注意 fn, fn2, fn1的递推顺序。 91 | 92 | ### 复杂度分析 93 | 94 | 遍历一次,时间复杂度为 $$O(n)$$, 使用了两个额外变量,空间复杂度为 $$O(1)$$. 95 | -------------------------------------------------------------------------------- /zh-hans/math_and_bit_manipulation/happy_number.md: -------------------------------------------------------------------------------- 1 | # Happy Number 2 | 3 | Tags: Hash Table, Math, Easy 4 | 5 | ## Question 6 | 7 | - leetcode: [Happy Number](https://leetcode.com/problems/happy-number/) 8 | - lintcode: [Happy Number](http://www.lintcode.com/en/problem/happy-number/) 9 | 10 | ### Problem Statement 11 | 12 | Write an algorithm to determine if a number is "happy". 13 | 14 | A happy number is a number defined by the following process: Starting with any 15 | positive integer, replace the number by the sum of the squares of its digits, 16 | and repeat the process until the number equals 1 (where it will stay), or it 17 | loops endlessly in a cycle which does not include 1. Those numbers for which 18 | this process ends in 1 are happy numbers. 19 | 20 | **Example: ** 19 is a happy number 21 | 22 | * $$1^2 + 9^2 = 82$$ 23 | * $$8^2 + 2^2 = 68$$ 24 | * $$6^2 + 8^2 = 100$$ 25 | * $$1^2 + 0^2 + 0^2 = 1$$ 26 | 27 | **Credits:** 28 | Special thanks to [@mithmatt](https://leetcode.com/discuss/user/mithmatt) and 29 | [@ts](https://leetcode.com/discuss/user/ts) for adding this problem and 30 | creating all test cases. 31 | 32 | ## 题解 33 | 34 | 根据指定运算规则判断输入整数是否为『happy number』,容易推断得知最终要么能求得1,要么为环形队列不断循环。 35 | 第一种情况容易判断,第二种情况即判断得到的数是否为环形队列,也就是说是否重复出现,这种场景使用哈希表轻易解决。 36 | 37 | ### Java 38 | 39 | ```java 40 | public class Solution { 41 | public boolean isHappy(int n) { 42 | if (n < 0) return false; 43 | 44 | Set set = new HashSet(); 45 | set.add(n); 46 | while (n != 1) { 47 | n = digitsSquareSum(n); 48 | if (n == 1) { 49 | return true; 50 | } else if (set.contains(n)) { 51 | return false; 52 | } else { 53 | set.add(n); 54 | } 55 | } 56 | 57 | return true; 58 | } 59 | 60 | private int digitsSquareSum(int n) { 61 | int sum = 0; 62 | for (; n > 0; n /= 10) { 63 | sum += (n % 10) * (n % 10); 64 | } 65 | return sum; 66 | } 67 | } 68 | ``` 69 | 70 | ### 源码分析 71 | 72 | 辅助方法计算数字平方和。 73 | 74 | ### 复杂度分析 75 | 76 | 有限迭代次数一定终止,时间和空间复杂度均为 $$O(1)$$. -------------------------------------------------------------------------------- /zh-hans/math_and_bit_manipulation/majority_number.md: -------------------------------------------------------------------------------- 1 | # Majority Number 2 | 3 | ## Question 4 | 5 | - leetcode: [Majority Element | LeetCode OJ](https://leetcode.com/problems/majority-element/) 6 | - lintcode: [(46) Majority Number](http://www.lintcode.com/en/problem/majority-number/) 7 | 8 | ``` 9 | Given an array of integers, the majority number is 10 | the number that occurs more than half of the size of the array. Find it. 11 | 12 | Example 13 | Given [1, 1, 1, 1, 2, 2, 2], return 1 14 | 15 | Challenge 16 | O(n) time and O(1) extra space 17 | ``` 18 | 19 | ## 题解 20 | 21 | 找出现次数超过一半的数,使用哈希表统计不同数字出现的次数,超过二分之一即返回当前数字。这种方法非常简单且容易实现,但会占据过多空间,注意到题中明确表明要找的数会超过二分之一,这里的隐含条件不是那么容易应用。既然某个数超过二分之一,那么用这个数和其他数进行 PK,不同的计数器都减一**(核心在于两两抵消)**,相同的则加1,最后返回计数器大于0的即可。综上,我们需要一辅助数据结构如`pair`. 22 | 23 | ### C++ 24 | ```c++ 25 | int majorityNumber(vector nums) { 26 | if (nums.empty()) return -1; 27 | 28 | int k = -1, count = 0; 29 | for (auto n : nums) { 30 | if (!count) k = n; 31 | if (k == n) count++; 32 | else count--; 33 | } 34 | return k; 35 | } 36 | ``` 37 | 38 | ### Java 39 | 40 | ```java 41 | public class Solution { 42 | /** 43 | * @param nums: a list of integers 44 | * @return: find a majority number 45 | */ 46 | public int majorityNumber(ArrayList nums) { 47 | if (nums == null || nums.isEmpty()) return -1; 48 | 49 | // pair 50 | int key = -1, count = 0; 51 | for (int num : nums) { 52 | // re-initialize 53 | if (count == 0) { 54 | key = num; 55 | count = 1; 56 | continue; 57 | } 58 | // increment/decrement count 59 | if (key == num) { 60 | count++; 61 | } else { 62 | count--; 63 | } 64 | } 65 | 66 | return key; 67 | } 68 | } 69 | ``` 70 | 71 | ### 源码分析 72 | 73 | 初始化`count = 0`, 遍历数组时需要先判断`count == 0`以重新初始化。 74 | 75 | ### 复杂度分析 76 | 77 | 时间复杂度 $$O(n)$$, 空间复杂度 $$O(1)$$. 78 | -------------------------------------------------------------------------------- /zh-hans/math_and_bit_manipulation/o1_check_power_of_2.md: -------------------------------------------------------------------------------- 1 | # O(1) Check Power of 2 2 | 3 | ## Question 4 | 5 | - lintcode: [(142) O(1) Check Power of 2](http://www.lintcode.com/en/problem/o1-check-power-of-2/) 6 | 7 | ``` 8 | Using O(1) time to check whether an integer n is a power of 2. 9 | 10 | Example 11 | For n=4, return true; 12 | 13 | For n=5, return false; 14 | 15 | Challenge 16 | O(1) time 17 | ``` 18 | 19 | ## 题解 20 | 21 | 咋看起来挺简单的一道题目,可之前若是没有接触过神奇的位运算技巧遇到这种题就有点不知从哪入手了,咳咳,我第一次接触到这个题就是在七牛的笔试题中看到的,泪奔 :-( 22 | 23 | 简单点来考虑可以连除2求余,看最后的余数是否为1,但是这种方法无法在 $$O(1)$$ 的时间内解出,所以我们必须要想点别的办法了。2的整数幂若用二进制来表示,则其中必只有一个1,其余全是0,那么怎么才能用一个式子把这种特殊的关系表示出来了?传统的位运算如按位与、按位或和按位异或等均无法直接求解,我就不卖关子了,比较下`x - 1`和`x`的关系试试?以`x=4`为例。 24 | 25 | ``` 26 | 0100 ==> 4 27 | 0011 ==> 3 28 | ``` 29 | 30 | 两个数进行按位与就为0了!如果不是2的整数幂则无上述关系,反证法可证之。 31 | 32 | ### Python 33 | 34 | ```python 35 | class Solution: 36 | """ 37 | @param n: An integer 38 | @return: True or false 39 | """ 40 | def checkPowerOf2(self, n): 41 | if n < 1: 42 | return False 43 | else: 44 | return (n & (n - 1)) == 0 45 | ``` 46 | 47 | ### C++ 48 | 49 | ```c++ 50 | class Solution { 51 | public: 52 | /* 53 | * @param n: An integer 54 | * @return: True or false 55 | */ 56 | bool checkPowerOf2(int n) { 57 | if (1 > n) { 58 | return false; 59 | } else { 60 | return 0 == (n & (n - 1)); 61 | } 62 | } 63 | }; 64 | ``` 65 | 66 | ### Java 67 | 68 | ```java 69 | class Solution { 70 | /* 71 | * @param n: An integer 72 | * @return: True or false 73 | */ 74 | public boolean checkPowerOf2(int n) { 75 | if (n < 1) { 76 | return false; 77 | } else { 78 | return (n & (n - 1)) == 0; 79 | } 80 | } 81 | }; 82 | ``` 83 | 84 | ### 源码分析 85 | 86 | 除了考虑正整数之外,其他边界条件如小于等于0的整数也应考虑在内。在比较0和`(n & (n - 1))`的值时,需要用括号括起来避免优先级结合的问题。 87 | 88 | ### 复杂度分析 89 | 90 | $$O(1)$$. 91 | 92 | ## 扩展 93 | 94 | 关于2的整数幂还有一道有意思的题,比如 [Next Power of 2 - GeeksforGeeks](http://www.geeksforgeeks.org/next-power-of-2/),有兴趣的可以去围观下。 95 | -------------------------------------------------------------------------------- /zh-hans/math_and_bit_manipulation/print_numbers_by_recursion.md: -------------------------------------------------------------------------------- 1 | # Print Numbers by Recursion 2 | 3 | ## Question 4 | 5 | - lintcode: [(371) Print Numbers by Recursion](http://www.lintcode.com/en/problem/print-numbers-by-recursion/) 6 | 7 | ``` 8 | Print numbers from 1 to the largest number with N digits by recursion. 9 | 10 | Example 11 | Given N = 1, return [1,2,3,4,5,6,7,8,9]. 12 | 13 | Given N = 2, return [1,2,3,4,5,6,7,8,9,10,11,12,...,99]. 14 | 15 | Note 16 | It's pretty easy to do recursion like: 17 | 18 | recursion(i) { 19 | if i > largest number: 20 | return 21 | results.add(i) 22 | recursion(i + 1) 23 | } 24 | however this cost a lot of recursion memory as the recursion depth maybe very large. 25 | Can you do it in another way to recursive with at most N depth? 26 | 27 | Challenge 28 | Do it in recursion, not for-loop. 29 | ``` 30 | 31 | ## 题解 32 | 33 | 从小至大打印 N 位的数列,正如题目中所提供的 `recursion(i)`, 解法简单粗暴,但问题在于 N 稍微大一点时栈就溢出了,因为递归深度太深了。能联想到的方法大概有两种,一种是用排列组合的思想去解释,把0~9当成十个不同的数(字符串表示),塞到 N 个坑位中,这个用 DFS 来解应该是可行的;另一个则是使用数学方法,依次递归递推,比如 N=2 可由 N=1递归而来,具体方法则是乘10进位加法。题中明确要求递归深度最大不超过 N, 故 DFS 方法比较危险。 34 | 35 | ### Java 36 | 37 | ```java 38 | public class Solution { 39 | /** 40 | * @param n: An integer. 41 | * return : An array storing 1 to the largest number with n digits. 42 | */ 43 | public List numbersByRecursion(int n) { 44 | List result = new ArrayList(); 45 | if (n <= 0) { 46 | return result; 47 | } 48 | helper(n, result); 49 | return result; 50 | } 51 | 52 | private void helper(int n, List ret) { 53 | if (n == 0) return; 54 | helper(n - 1, ret); 55 | // current base such as 10, 20, 30... 56 | int base = (int)Math.pow(10, n - 1); 57 | // get List size before for loop 58 | int size = ret.size(); 59 | for (int i = 1; i < 10; i++) { 60 | // add 10, 100, 1000... 61 | ret.add(i * base); 62 | for (int j = 0; j < size; j++) { 63 | // add 11, 12, 13... 64 | ret.add(ret.get(j) + base * i); 65 | } 66 | } 67 | } 68 | } 69 | ``` 70 | 71 | ### 源码分析 72 | 73 | 递归步的截止条件`n == 0`, 由于需要根据之前 N-1 位的数字递推,`base` 每次递归一层都需要乘10,`size`需要在`for`循环之前就确定。 74 | 75 | ### 复杂度分析 76 | 77 | 添加 $$10^n$$ 个元素,时间复杂度 $$O(10^n)$$, 空间复杂度 $$O(1)$$. 78 | 79 | ## Reference 80 | 81 | - [Lintcode: Print Numbers by Recursion | codesolutiony](https://codesolutiony.wordpress.com/2015/05/21/lintcode-print-numbers-by-recursion/) 82 | -------------------------------------------------------------------------------- /zh-hans/math_and_bit_manipulation/single_number.md: -------------------------------------------------------------------------------- 1 | # Single Number 2 | 3 | Tags: Hash Table, Bit Manipulation, Easy 4 | 5 | ## Question 6 | 7 | - leetcode: [Single Number](https://leetcode.com/problems/single-number/) 8 | - lintcode: [Single Number](http://www.lintcode.com/en/problem/single-number/) 9 | 10 | ### Problem Statement 11 | 12 | Given an array of integers, every element appears _twice_ except for one. Find 13 | that single one. 14 | 15 | **Note:** 16 | Your algorithm should have a linear runtime complexity. Could you implement it 17 | without using extra memory? 18 | 19 | ## 题解 20 | 21 | 「找单数」系列题,技巧性较强,需要灵活运用位运算的特性。根据题意,共有`2*n + 1`个数,且有且仅有一个数落单,要找出相应的「单数」。鉴于有空间复杂度的要求,不可能使用另外一个数组来保存每个数出现的次数,考虑到异或运算的特性,根据`x ^ x = 0`和`x ^ 0 = x`可将给定数组的所有数依次异或,最后保留的即为结果。 22 | 23 | ### C++ 24 | 25 | ```c++ 26 | class Solution { 27 | public: 28 | /** 29 | * @param A: Array of integers. 30 | * return: The single number. 31 | */ 32 | int singleNumber(vector &A) { 33 | if (A.empty()) { 34 | return -1; 35 | } 36 | int result = 0; 37 | 38 | for (vector::iterator iter = A.begin(); iter != A.end(); ++iter) { 39 | result = result ^ *iter; 40 | } 41 | 42 | return result; 43 | } 44 | }; 45 | ``` 46 | 47 | ### Java 48 | 49 | ```java 50 | public class Solution { 51 | public int singleNumber(int[] nums) { 52 | if (nums == null || nums.length == 0) return -1; 53 | 54 | int result = 0; 55 | for (int num : nums) { 56 | result ^= num; 57 | } 58 | 59 | return result; 60 | } 61 | } 62 | ``` 63 | 64 | ### 源码分析 65 | 66 | 1. 异常处理(OJ上对于空vector的期望结果为0,但个人认为-1更为合理) 67 | 2. 初始化返回结果`result`为0,因为`x ^ 0 = x` 68 | -------------------------------------------------------------------------------- /zh-hans/math_and_bit_manipulation/single_number_iii.md: -------------------------------------------------------------------------------- 1 | # Single Number III 2 | 3 | ## Question 4 | 5 | - lintcode: [(84) Single Number III](http://www.lintcode.com/en/problem/single-number-iii/) 6 | 7 | ``` 8 | Given 2*n + 2 numbers, every numbers occurs twice except two, find them. 9 | 10 | Example 11 | Given [1,2,2,3,4,4,5,3] return 1 and 5 12 | 13 | Challenge 14 | O(n) time, O(1) extra space. 15 | ``` 16 | 17 | ## 题解 18 | 19 | 题 [Single Number](http://algorithm.yuanbin.me/zh-hans/math_and_bit_manipulation/single_number.html) 的 follow up, 不妨设最后两个只出现一次的数分别为 `x1, x2`. 那么遍历数组时根据两两异或的方法可得最后的结果为 `x1 ^ x2`, 如果我们要分别求得 `x1` 和 `x2`, 我们可以根据 `x1 ^ x2 ^ x1 = x2` 求得 `x2`, 同理可得 `x_1`. 那么问题来了,如何得到`x1`和`x2`呢?看起来似乎是个死循环。大多数人一般也就能想到这一步(比如我...)。 20 | 21 | 这道题的巧妙之处在于利用`x1 ^ x2`的结果对原数组进行了分组,进而将`x1`和`x2`分开了。具体方法则是利用了`x1 ^ x2`不为0的特性,如果`x1 ^ x2`不为0,那么`x1 ^ x2`的结果必然存在某一二进制位不为0(即为1),我们不妨将最低位的1提取出来,由于在这一二进制位上`x1`和`x2`必然相异,即`x1`, `x2`中相应位一个为0,另一个为1,所以我们可以利用这个最低位的1将`x1`和`x2`分开。又由于除了`x1`和`x2`之外其他数都是成对出现,故与最低位的1异或时一定会抵消,十分之精妙! 22 | 23 | ### Java 24 | 25 | ```java 26 | public class Solution { 27 | /** 28 | * @param A : An integer array 29 | * @return : Two integers 30 | */ 31 | public List singleNumberIII(int[] A) { 32 | ArrayList nums = new ArrayList(); 33 | if (A == null || A.length == 0) return nums; 34 | 35 | int x1xorx2 = 0; 36 | for (int i : A) { 37 | x1xorx2 ^= i; 38 | } 39 | 40 | // get the last 1 bit of x1xorx2, e.g. 1010 ==> 0010 41 | int last1Bit = x1xorx2 - (x1xorx2 & (x1xorx2 - 1)); 42 | int single1 = 0, single2 = 0; 43 | for (int i : A) { 44 | if ((last1Bit & i) == 0) { 45 | single1 ^= i; 46 | } else { 47 | single2 ^= i; 48 | } 49 | } 50 | 51 | nums.add(single1); 52 | nums.add(single2); 53 | return nums; 54 | } 55 | } 56 | ``` 57 | 58 | ### 源码分析 59 | 60 | 求一个数二进制位1的最低位方法为 `x1xorx2 - (x1xorx2 & (x1xorx2 - 1))`, 其他位运算的总结可参考 [Bit Manipulation](http://algorithm.yuanbin.me/zh-hans/basics_misc/bit_manipulation.html)。利用`last1Bit`可将数组的数分为两组,一组是相应位为0,另一组是相应位为1. 61 | 62 | ### 复杂度分析 63 | 64 | 两次遍历数组,时间复杂度 $$O(n)$$, 使用了部分额外空间,空间复杂度 $$O(1)$$. 65 | 66 | ## Reference 67 | 68 | - [Single Number III 参考程序 Java/C++/Python](http://www.jiuzhang.com/solutions/single-number-iii/) 69 | -------------------------------------------------------------------------------- /zh-hans/microsoft/README.md: -------------------------------------------------------------------------------- 1 | # Microsoft 2 | 3 | 本章总结 Microsoft 校招的一些题。 4 | -------------------------------------------------------------------------------- /zh-hans/microsoft/mstest2015april/README.md: -------------------------------------------------------------------------------- 1 | # Microsoft 2015 April 2 | 3 | 本小节总结 Microsoft 2015年四月第一次招实习生的题,题目列表见 [hihoCoder](http://hihocoder.com/contest/mstest2015april/problems). 4 | -------------------------------------------------------------------------------- /zh-hans/microsoft/mstest2015april/problem_a_magic_box.md: -------------------------------------------------------------------------------- 1 | # Problem A. Magic Box 2 | 3 | ## Source 4 | 5 | - [hihoCoder](http://hihocoder.com/contest/mstest2015april/problem/1) 6 | 7 | ### Problem 8 | 9 | 时间限制:10000ms 10 | 11 | 单点时限:1000ms 12 | 13 | 内存限制:256MB 14 | 15 | ### 描述 16 | 17 | The circus clown Sunny has a magic box. When the circus is performing, Sunny 18 | puts some balls into the box one by one. The balls are in three colors: 19 | red(R), yellow(Y) and blue(B). Let Cr, Cy, Cb denote the numbers of red, 20 | yellow, blue balls in the box. Whenever the differences among Cr, Cy, Cb 21 | happen to be x, y, z, all balls in the box vanish. Given x, y, z and the 22 | sequence in which Sunny put the balls, you are to find what is the maximum 23 | number of balls in the box **ever**. 24 | 25 | For example, let's assume x=1, y=2, z=3 and the sequence is RRYBRBRYBRY. After 26 | Sunny puts the first 7 balls, RRYBRBR, into the box, Cr, Cy, Cb are 4, 1, 2 27 | respectively. The differences are exactly 1, 2, 3. (|Cr-Cy|=3, |Cy-Cb|=1, |Cb- 28 | Cr|=2) Then all the 7 balls vanish. Finally there are 4 balls in the box, 29 | after Sunny puts the remaining balls. So the box contains 7 balls at most, 30 | after Sunny puts the first 7 balls and before they vanish. 31 | 32 | #### 输入 33 | 34 | Line 1: x y z 35 | 36 | Line 2: the sequence consisting of only three characters 'R', 'Y' and 'B'. 37 | 38 | For 30% data, the length of the sequence is no more than 200. 39 | 40 | For 100% data, the length of the sequence is no more than 20,000, 0 <= x, 41 | y, z <= 20. 42 | 43 | ### 输出 44 | 45 | The maximum number of balls in the box **ever**. 46 | 47 | ### 提示 48 | 49 | Another Sample 50 | 51 | Sample Input| Sample Output 52 | ---|--- 53 | (0 0 0)RBYRRBY | 4 54 | 55 | 样例输入 56 | 57 | 1 2 3 58 | RRYBRBRYBRY 59 | 60 | 样例输出 61 | 62 | 7 63 | -------------------------------------------------------------------------------- /zh-hans/microsoft/mstest2015april/problem_c_islands_travel.md: -------------------------------------------------------------------------------- 1 | # Problem C. Islands Travel 2 | 3 | ## Source 4 | 5 | - [hihoCoder](http://hihocoder.com/contest/mstest2015april/problem/3) 6 | 7 | ### Problem 8 | 9 | 时间限制:10000ms 10 | 11 | 单点时限:1000ms 12 | 13 | 内存限制:256MB 14 | 15 | ### 描述 16 | 17 | There are N islands on a planet whose coordinates are (X1, Y1), (X2, Y2), (X3, 18 | Y3) ..., (XN, YN). You starts at the 1st island (X1, Y1) and your destination 19 | is the n-th island (XN, YN). Travelling between i-th and j-th islands will 20 | cost you min{|Xi-Xj|, |Yi-Yj|} (|a| denotes the absolute value of a. min{a, b} 21 | denotes the smaller value between a and b) gold coins. You want to know what 22 | is the minimum cost to travel from the 1st island to the n-th island. 23 | 24 | ### 输入 25 | 26 | Line 1: an integer N. 27 | 28 | Line 2~N+1: each line contains two integers Xi and Yi. 29 | 30 | 31 | 32 | For 40% data, N<=1000,0<=Xi,Yi<=100000. 33 | 34 | For 100% data, N<=100000,0<=Xi,Yi<=1000000000. 35 | 36 | ### 输出 37 | 38 | Output the minimum cost. 39 | 40 | 样例输入 41 | 42 | 43 | 44 | 45 | 3 46 | 2 2 47 | 1 7 48 | 7 6 49 | 50 | 样例输出 51 | 52 | 53 | 54 | 55 | 2 56 | 57 | 58 | -------------------------------------------------------------------------------- /zh-hans/microsoft/mstest2015april2/README.md: -------------------------------------------------------------------------------- 1 | # Microsoft 2015 April 2 2 | 3 | 本小节总结 Microsoft 2015年四月第二次招实习生的题,题目列表见 [hihoCoder](http://hihocoder.com/contest/mstest2015april2/problems). 4 | -------------------------------------------------------------------------------- /zh-hans/microsoft/mstest2015april2/problem_b_numeric_keypad.md: -------------------------------------------------------------------------------- 1 | # Problem B. Numeric Keypad 2 | 3 | ## Source 4 | 5 | - [hihoCoder](http://hihocoder.com/contest/mstest2015april2/problem/2) 6 | 7 | ### Problem 8 | 9 | 时间限制:10000ms 10 | 11 | 单点时限:1000ms 12 | 13 | 内存限制:256MB 14 | 15 | ### 描述 16 | 17 | The numberic keypad on your mobile phone looks like below: 18 | 19 | 20 | 21 | 1 2 3 22 | 4 5 6 23 | 7 8 9 24 | 0 25 | 26 | 27 | Suppose you are holding your mobile phone with single hand. Your thumb points 28 | at digit 1. Each time you can 1) press the digit your thumb pointing at, 2) 29 | move your thumb right, 3) move your thumb down. Moving your thumb left or up 30 | is not allowed. 31 | 32 | By using the numeric keypad under above constrains, you can produce some 33 | numbers like 177 or 480 while producing other numbers like 590 or 52 is 34 | impossible. 35 | 36 | Given a number K, find out the maximum number less than or equal to K that can 37 | be produced. 38 | 39 | ### 输入 40 | 41 | The first line contains an integer T, the number of testcases. 42 | 43 | Each testcase occupies a single line with an integer K. 44 | 45 | 46 | 47 | For 50% of the data, 1 <= K <= 999. 48 | 49 | For 100% of the data, 1 <= K <= 10500, t <= 20. 50 | 51 | ### 输出 52 | 53 | For each testcase output one line, the maximum number less than or equal to 54 | the corresponding K that can be produced. 55 | 56 | 样例输入 57 | 58 | 59 | 60 | 61 | 3 62 | 25 63 | 83 64 | 131 65 | 66 | 样例输出 67 | 68 | 69 | 70 | 71 | 25 72 | 80 73 | 129 74 | 75 | 76 | -------------------------------------------------------------------------------- /zh-hans/microsoft/mstest2015sept2/README.md: -------------------------------------------------------------------------------- 1 | # Microsoft 2015 September 2 2 | 3 | 本小节总结 Microsoft 2015年九月第一次大规模校招的题,题目列表见 [hihoCoder](http://hihocoder.com/contest/mstest2015sept2/problems). 这一场的题目感觉偏难。 4 | -------------------------------------------------------------------------------- /zh-hans/part_i_basics/README.md: -------------------------------------------------------------------------------- 1 | # Part I - Basics 2 | 3 | 第一部分主要总结一些算法和数据结构方面的基础知识,如基本的数据结构和常见基础算法。 4 | 5 | 本节主要由以下章节构成。 6 | - Basic Data Structure 7 | - Basic Sorting 8 | - Basic Algorithm 9 | - Basic Misc 10 | 11 | ## Reference 12 | 13 | - [VisuAlgo - visualising data structures and algorithms through animation](http://www.comp.nus.edu.sg/~stevenha/visualization/index.html) - 相当碉堡的数据结构和算法可视化。 14 | - [Data Structure Visualization](http://www.cs.usfca.edu/~galles/visualization/Algorithms.html) - 相当碉堡的动画演示!!涵盖了常用的各种数据结构/排序/算法。 15 | -------------------------------------------------------------------------------- /zh-hans/part_ii_coding/README.md: -------------------------------------------------------------------------------- 1 | # Part II - Coding 2 | 3 | 本节主要总结一些leetcode等题目的实战经验。 4 | 5 | 主要有以下章节构成。 6 | -------------------------------------------------------------------------------- /zh-hans/part_iii_contest/README.md: -------------------------------------------------------------------------------- 1 | # Part III - Contest 2 | 3 | 本节主要总结一些如 Google APAC, Microsoft 校招等在线测试的题。 4 | -------------------------------------------------------------------------------- /zh-hans/problem_misc/README.md: -------------------------------------------------------------------------------- 1 | # Problem Misc 2 | 3 | 本章主要总结暂时不方便归到其他章节的题目。 4 | -------------------------------------------------------------------------------- /zh-hans/problem_misc/add_binary.md: -------------------------------------------------------------------------------- 1 | # Add Binary 2 | 3 | ## Question 4 | 5 | - leetcode: [Add Binary | LeetCode OJ](https://leetcode.com/problems/add-binary/) 6 | - lintcode: [(408) Add Binary](http://www.lintcode.com/en/problem/add-binary/) 7 | 8 | ``` 9 | Given two binary strings, return their sum (also a binary string). 10 | 11 | For example, 12 | a = "11" 13 | b = "1" 14 | Return "100". 15 | ``` 16 | 17 | ## 题解 18 | 19 | 用字符串模拟二进制的加法,加法操作一般使用自后往前遍历的方法,不同位大小需要补零。 20 | 21 | ### Java 22 | 23 | ```java 24 | public class Solution { 25 | /** 26 | * @param a a number 27 | * @param b a number 28 | * @return the result 29 | */ 30 | public String addBinary(String a, String b) { 31 | if (a == null || a.length() == 0) return b; 32 | if (b == null || b.length() == 0) return a; 33 | 34 | StringBuilder sb = new StringBuilder(); 35 | int aLen = a.length(), bLen = b.length(); 36 | 37 | int carry = 0; 38 | for (int ia = aLen - 1, ib = bLen - 1; ia >= 0 || ib >= 0; ia--, ib--) { 39 | // replace with 0 if processed 40 | int aNum = (ia < 0) ? 0 : a.charAt(ia) - '0'; 41 | int bNum = (ib < 0) ? 0 : b.charAt(ib) - '0'; 42 | 43 | int num = (aNum + bNum + carry) % 2; 44 | carry = (aNum + bNum + carry) / 2; 45 | sb.append(num); 46 | } 47 | if (carry == 1) sb.append(1); 48 | 49 | // important! 50 | sb.reverse(); 51 | String result = sb.toString(); 52 | return result; 53 | } 54 | } 55 | ``` 56 | 57 | ### 源码分析 58 | 59 | 用到的技巧主要有两点,一是两个数位数大小不一时用0补上,二是最后需要判断最高位的进位是否为1。最后需要反转字符串,因为我们是从低位往高位迭代的。虽然可以使用 insert 避免最后的 reverse 操作,但如此一来时间复杂度就从 $$O(n)$$ 变为 $$O(n^2)$$ 了。 60 | 61 | ### 复杂度分析 62 | 63 | 遍历两个字符串,时间复杂度 $$O(n)$$. reverse 操作时间复杂度 $$O(n)$$, 故总的时间复杂度 $$O(n)$$. 使用了 StringBuilder 作为临时存储对象,空间复杂度 $$O(n)$$. 64 | -------------------------------------------------------------------------------- /zh-hans/problem_misc/continuous_subarray_sum.md: -------------------------------------------------------------------------------- 1 | # Continuous Subarray Sum 2 | 3 | ## Question 4 | 5 | - lintcode: [(402) Continuous Subarray Sum](http://www.lintcode.com/en/problem/continuous-subarray-sum/) 6 | 7 | ### Problem Statement 8 | 9 | Given an integer array, find a continuous subarray where the sum of numbers is 10 | the biggest. Your code should return the index of the first number and the 11 | index of the last number. (If their are duplicate answer, return anyone) 12 | 13 | #### Example 14 | 15 | Give `[-3, 1, 3, -3, 4]`, return `[1,4]`. 16 | 17 | ## 题解 18 | 19 | 和题 [Maximum Subarray](http://algorithm.yuanbin.me/zh-hans/dynamic_programming/maximum_subarray.html) 几乎一模一样,只是返回值要求不一样。由于需要返回区间索引值,那么显然需要额外变量记录区间起止处。若使用题解2中提到的`sum - minSum`的区间和更新方式,索引终止处容易得知是`sum - minSum > maxSub`时的`i`, 问题是索引起始处如何确定。容易得知索引起始处如果更新,必然在`minSum > sum`时,但问题在于满足此条件的可能不止一处,所以我们需要先记录这个索引值并在`sum - minSum > maxSub`时判定索引终止值是否大于索引起始值,不小于则更新。 20 | 21 | 此题难以一次 bug-free, 需要小心更新索引值。 22 | 23 | ### Java 24 | 25 | ```java 26 | public class Solution { 27 | /** 28 | * @param A an integer array 29 | * @return A list of integers includes the index of the first number and the index of the last number 30 | */ 31 | public ArrayList continuousSubarraySum(int[] A) { 32 | ArrayList result = new ArrayList(); 33 | if (A == null || A.length == 0) return result; 34 | 35 | int sum = 0, minSum = 0, maxSub = Integer.MIN_VALUE; 36 | int first = 0, last = 0; 37 | int first2 = 0; // candidate for first 38 | for (int i = 0; i < A.length; i++) { 39 | if (minSum > sum) { 40 | minSum = sum; 41 | first2 = i; 42 | } 43 | sum += A[i]; 44 | if (sum - minSum > maxSub) { 45 | maxSub = sum - minSum; 46 | last = i; 47 | // update first if valid 48 | if (first2 <= last) first = first2; 49 | } 50 | } 51 | 52 | result.add(first); 53 | result.add(last); 54 | return result; 55 | } 56 | } 57 | ``` 58 | 59 | ### 源码分析 60 | 61 | 除了最后要求的`first`和`last`, 我们还需要引入`first2`作为`first`可能的候选变量值。 62 | 63 | ### 复杂度分析 64 | 65 | 略 66 | -------------------------------------------------------------------------------- /zh-hans/problem_misc/gray_code.md: -------------------------------------------------------------------------------- 1 | # Gray Code 2 | 3 | ## Question 4 | 5 | - leetcode: [Gray Code | LeetCode OJ](https://leetcode.com/problems/gray-code/) 6 | - lintcode: [(411) Gray Code](http://www.lintcode.com/en/problem/gray-code/) 7 | 8 | ### Problem Statement 9 | 10 | The gray code is a binary numeral system where two successive values differ in only one bit. 11 | Given a non-negative integer n representing the total number of bits in the code, find the sequence of gray code. A gray code sequence must begin with 0 and with cover all $$2^n$$ integers. 12 | 13 | #### Example 14 | 15 | Given `n = 2`, return `[0,1,3,2]`. Its gray code sequence is: 16 | 17 | ``` 18 | 00 - 0 19 | 01 - 1 20 | 11 - 3 21 | 10 - 2 22 | ``` 23 | 24 | #### Note 25 | 26 | For a given n, a gray code sequence is not uniquely defined. 27 | 28 | `[0,2,3,1]` is also a valid gray code sequence according to the above definition. 29 | 30 | #### Challenge 31 | 32 | $$O(2^n)$$ time. 33 | 34 | ## 题解 35 | 36 | 第一次遇到这个题是在腾讯的在线笔试中,当时找到了规律,用的是递归,但是实现似乎有点问题... 直接从 n 位的格雷码分析不太好分析,比如题中`n = 2`的格雷码,我们不妨试试从小到大分析,以 `n = 1` 往后递推。 37 | 38 | ![Gray Code](../../shared-files/images/Binary-reflected_Gray_code_construction.png) 39 | 40 | 从图中我们可以看出n 位的格雷码可由 n-1位的格雷码递推,在最高位前顺序加0,逆序加1即可。实际实现时我们可以省掉在最高位加0的过程,因为其在数值上和前 n-1位格雷码相同。另外一点则是初始化的处理,图中为从1开始,但若从0开始可进一步简化程序。而且根据 [格雷码](https://zh.wikipedia.org/wiki/%E6%A0%BC%E9%9B%B7%E7%A0%81) 的定义,n=0时确实应该返回0. 41 | 42 | ### Java 43 | 44 | ```java 45 | public class Solution { 46 | /** 47 | * @param n a number 48 | * @return Gray code 49 | */ 50 | public ArrayList grayCode(int n) { 51 | if (n < 0) return null; 52 | 53 | ArrayList currGray = new ArrayList(); 54 | currGray.add(0); 55 | 56 | for (int i = 0; i < n; i++) { 57 | int msb = 1 << i; 58 | // backward - symmetry 59 | for (int j = currGray.size() - 1; j >= 0; j--) { 60 | currGray.add(msb | currGray.get(j)); 61 | } 62 | } 63 | 64 | return currGray; 65 | } 66 | } 67 | ``` 68 | 69 | ### 源码分析 70 | 71 | 加0 的那一部分已经在前一组格雷码中出现,故只需将前一组格雷码镜像后在最高位加1即可。第二重 for 循环中需要注意的是`currGray.size() - 1`并不是常量,只能用于给 j 初始化。本应该使用 $$2^n$$ 和上一组格雷码相加,这里考虑到最高位为1的特殊性,使用位运算模拟加法更好。 72 | 73 | ### 复杂度分析 74 | 75 | 生成n 位的二进制码,时间复杂度 $$O(2^n)$$, 使用了`msb`代表最高位的值便于后续相加,空间复杂度 $$O(1)$$. 76 | 77 | ## Reference 78 | 79 | - Soulmachine 的 leetcode 题解 80 | -------------------------------------------------------------------------------- /zh-hans/problem_misc/longest_consecutive_sequence.md: -------------------------------------------------------------------------------- 1 | # Longest Consecutive Sequence 2 | 3 | Tags: Array, Union Find, Hard 4 | 5 | ## Question 6 | 7 | - leetcode: [Longest Consecutive Sequence](https://leetcode.com/problems/longest-consecutive-sequence/) 8 | - lintcode: [Longest Consecutive Sequence](https://www.lintcode.com/problem/longest-consecutive-sequence/) 9 | 10 | ### Problem Statement 11 | 12 | Given an unsorted array of integers, find the length of the longest 13 | consecutive elements sequence. 14 | 15 | Your algorithm should run in O(_n_) complexity. 16 | 17 | **Example:** 18 | 19 | 20 | 21 | **Input:** [100, 4, 200, 1, 3, 2] 22 | **Output:** 4 23 | **Explanation:** The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4. 24 | 25 | ## 题解 26 | 27 | 首先看题要求,时间复杂度为 $$O(n)$$, 如果排序,基于比较的实现为 $$n \log n$$, 基数排序需要数据有特征。故排序无法达到复杂度要求。接下来可以联想空间换时间的做法,其中以哈希表为代表。这个题要求返回最长连续序列,不要求有序,非常符合哈希表的用法。**由于给定一个数其连续的数要么比它小1,要么大1,那么我们只需往左往右搜索知道在数组中找不到数为止。**结合哈希表查找为 $$O(1)$$ 的特性即可满足要求。 28 | 29 | ### Java 30 | 31 | ```java 32 | class Solution { 33 | public int longestConsecutive(int[] nums) { 34 | if (nums == null || nums.length <= 0) return 0; 35 | Set sets = new HashSet<>(nums.length); 36 | for (int num : nums) { 37 | sets.add(num); 38 | } 39 | 40 | int result = 1; 41 | for (int num : nums) { 42 | int seq = 1; 43 | int right = num, left = num; 44 | // right 45 | while (sets.contains(++right)) { 46 | seq++; 47 | sets.remove(right); 48 | } 49 | // left 50 | while (sets.contains(--left)) { 51 | seq++; 52 | sets.remove(left); 53 | } 54 | sets.remove(num); 55 | if (seq > result) result = seq; 56 | } 57 | 58 | return result; 59 | } 60 | } 61 | ``` 62 | 63 | ### 源码分析 64 | 65 | 首先使用 HashSet 建哈希表,然后遍历数组,依次往左往右搜相邻数,搜到了就从 Set 中删除。末尾更新最大值。 66 | 67 | ### 复杂度分析 68 | 69 | 时间复杂度和空间复杂度均为 $$O(n)$$. 70 | -------------------------------------------------------------------------------- /zh-hans/problem_misc/minimum_subarray.md: -------------------------------------------------------------------------------- 1 | # Minimum Subarray 2 | 3 | ## Question 4 | 5 | - lintcode: [(44) Minimum Subarray](http://www.lintcode.com/en/problem/minimum-subarray/) 6 | 7 | ``` 8 | Given an array of integers, find the subarray with smallest sum. 9 | 10 | Return the sum of the subarray. 11 | 12 | Example 13 | For [1, -1, -2, 1], return -3 14 | 15 | Note 16 | The subarray should contain at least one integer. 17 | ``` 18 | 19 | ## 题解 20 | 21 | 题 [Maximum Subarray](http://algorithm.yuanbin.me/zh-hans/dynamic_programming/maximum_subarray.html) 的变形,使用区间和容易理解和实现。 22 | 23 | ### Java 24 | 25 | ```java 26 | public class Solution { 27 | /** 28 | * @param nums: a list of integers 29 | * @return: A integer indicate the sum of minimum subarray 30 | */ 31 | public int minSubArray(ArrayList nums) { 32 | if (nums == null || nums.isEmpty()) return -1; 33 | 34 | int sum = 0, maxSum = 0, minSub = Integer.MAX_VALUE; 35 | for (int num : nums) { 36 | maxSum = Math.max(maxSum, sum); 37 | sum += num; 38 | minSub = Math.min(minSub, sum - maxSum); 39 | } 40 | 41 | return minSub; 42 | } 43 | } 44 | ``` 45 | 46 | ### 源码分析 47 | 48 | 略 49 | 50 | ### 复杂度分析 51 | 52 | 略 53 | -------------------------------------------------------------------------------- /zh-hans/problem_misc/reverse_integer.md: -------------------------------------------------------------------------------- 1 | # Reverse Integer 2 | 3 | ## Question 4 | 5 | - leetcode: [Reverse Integer | LeetCode OJ](https://leetcode.com/problems/reverse-integer/) 6 | - lintcode: [(413) Reverse Integer](http://www.lintcode.com/en/problem/reverse-integer/) 7 | 8 | ### Problem Statement 9 | 10 | Reverse digits of an integer. Returns 0 when the reversed integer overflows (signed 32-bit integer). 11 | 12 | #### Example 13 | 14 | Given x = 123, return 321 15 | 16 | Given x = -123, return -321 17 | 18 | ## 题解 19 | 20 | 初看这道题觉得先将其转换为字符串然后转置以下就好了,但是仔细一想这种方法存在两种缺陷,一是负号需要单独处理,而是转置后开头的0也需要处理。另一种方法是将原数字逐个弹出,然后再将弹出的数字组装为新数字,咋看以为需要用到栈,实际上却是队列... 所以根本不需要辅助数据结构。关于正负号的处理,我最开始是单独处理的,后来看其他答案时才发现根本就不用分正负考虑。因为`-1 / 10 = 0`. 21 | 22 | ### Java 23 | 24 | ```java 25 | public class Solution { 26 | /** 27 | * @param n the integer to be reversed 28 | * @return the reversed integer 29 | */ 30 | public int reverseInteger(int n) { 31 | long result = 0; 32 | while (n != 0) { 33 | result = n % 10 + 10 * result; 34 | n /= 10; 35 | } 36 | 37 | if (result < Integer.MIN_VALUE || result > Integer.MAX_VALUE) { 38 | return 0; 39 | } 40 | return (int)result; 41 | } 42 | } 43 | ``` 44 | 45 | ### 源码分析 46 | 47 | 注意 lintcode 和 leetcode 的方法名不一样。使用 long 型保存中间结果,最后判断是否溢出。 48 | 49 | ## Reference 50 | 51 | - [LeetCode-Sol-Res/ReverseInt.java at master · FreeTymeKiyan/LeetCode-Sol-Res](https://github.com/FreeTymeKiyan/LeetCode-Sol-Res/blob/master/Easy/ReverseInt.java) 52 | -------------------------------------------------------------------------------- /zh-hans/problem_misc/string_to_integer.md: -------------------------------------------------------------------------------- 1 | # String to Integer 2 | 3 | ## Question 4 | 5 | - leetcode: [String to Integer (atoi) | LeetCode OJ](https://leetcode.com/problems/string-to-integer-atoi/) 6 | - lintcode: [(54) String to Integer(atoi)](http://www.lintcode.com/en/problem/string-to-integer-ii/) 7 | 8 | ``` 9 | Implement function atoi to convert a string to an integer. 10 | 11 | If no valid conversion could be performed, a zero value is returned. 12 | 13 | If the correct value is out of the range of representable values, 14 | INT_MAX (2147483647) or INT_MIN (-2147483648) is returned. 15 | 16 | Example 17 | "10" => 10 18 | 19 | "-1" => -1 20 | 21 | "123123123123123" => 2147483647 22 | 23 | "1.0" => 1 24 | ``` 25 | 26 | ## 题解 27 | 28 | 经典的字符串转整数题,边界条件比较多,比如是否需要考虑小数点,空白及非法字符的处理,正负号的处理,科学计数法等。最先处理的是空白字符,然后是正负号,接下来只要出现非法字符(包含正负号,小数点等,无需对这两类单独处理)即退出,否则按照正负号的整数进位加法处理。 29 | 30 | ### Java 31 | 32 | ```java 33 | public class Solution { 34 | /** 35 | * @param str: A string 36 | * @return An integer 37 | */ 38 | public int atoi(String str) { 39 | if (str == null || str.length() == 0) return 0; 40 | 41 | // trim left and right spaces 42 | String strTrim = str.trim(); 43 | int len = strTrim.length(); 44 | // sign symbol for positive and negative 45 | int sign = 1; 46 | // index for iteration 47 | int i = 0; 48 | if (strTrim.charAt(i) == '+') { 49 | i++; 50 | } else if (strTrim.charAt(i) == '-') { 51 | sign = -1; 52 | i++; 53 | } 54 | 55 | // store the result as long to avoid overflow 56 | long result = 0; 57 | while (i < len) { 58 | if (strTrim.charAt(i) < '0' || strTrim.charAt(i) > '9') { 59 | break; 60 | } 61 | result = 10 * result + sign * (strTrim.charAt(i) - '0'); 62 | // overflow 63 | if (result > Integer.MAX_VALUE) { 64 | return Integer.MAX_VALUE; 65 | } else if (result < Integer.MIN_VALUE) { 66 | return Integer.MIN_VALUE; 67 | } 68 | i++; 69 | } 70 | 71 | return (int)result; 72 | } 73 | } 74 | ``` 75 | 76 | ### 源码分析 77 | 78 | 符号位使用整型表示,便于后期相乘相加。在 while 循环中需要注意判断是否已经溢出,如果放在 while 循环外面则有可能超过 long 型范围。 79 | 80 | ### 复杂度分析 81 | 82 | 略 83 | 84 | ## Reference 85 | 86 | - [String to Integer (atoi) 参考程序 Java/C++/Python](http://www.jiuzhang.com/solutions/string-to-integer-atoi/) 87 | -------------------------------------------------------------------------------- /zh-hans/string/README.md: -------------------------------------------------------------------------------- 1 | # String - 字符串 2 | 3 | 本章主要介绍字符串相关题目。 4 | 5 | > 处理字符串操作相关问题时,常见的做法是从字符串尾部开始编辑,从后往前逆向操作。这么做的原因是因为字符串的尾部往往有足够空间,可以直接修改而不用担心覆盖字符串前面的数据。 6 | 7 | 摘自《程序员面试金典》 8 | -------------------------------------------------------------------------------- /zh-hans/styles/website.css: -------------------------------------------------------------------------------- 1 | .book .book-summary, .book .book-body { 2 | font-family: "Microsoft YaHei UI", "Microsoft Yahei", "PingFang SC", "Lantinghei SC", "Hiragino Sans GB", "WenQuanYi Micro Hei", "WenQuanYi Zen Hei", "Noto Sans CJK SC", "Microsoft JhengHei UI", "Microsoft JhengHei", "PingFang TC", "Lantinghei TC", "Noto Sans CJK TC", "Helvetica Neue", Helvetica, Arial, sans-serif; 3 | } 4 | -------------------------------------------------------------------------------- /zh-hans/tags.md: -------------------------------------------------------------------------------- 1 | # Tags 2 | -------------------------------------------------------------------------------- /zh-tw/appendix_i_interview_and_resume/README.md: -------------------------------------------------------------------------------- 1 | # Appendix I Interview and Resume 2 | 3 | 本章主要總結一些技術面試和撰寫履歷方面的注意事項。 4 | 5 | -------------------------------------------------------------------------------- /zh-tw/basics_algorithm/README.md: -------------------------------------------------------------------------------- 1 | # Basics Algorithm 2 | 3 | 本章主要介紹一些常用的基本演算法,後序章節介紹一些高級演算法。 4 | -------------------------------------------------------------------------------- /zh-tw/basics_algorithm/bitmap.md: -------------------------------------------------------------------------------- 1 | # Bitmap 2 | 3 | 最開始接觸 bitmap 是在 Jon Bentley 所著《Programming Pearls》 (無繁體中文版,簡體中文版書名為《編程珠璣》) 這本書上,書中所述的方法有點簡單粗暴,不過思想倒是不錯——從 Information Theory 的角度來解釋就是信息壓縮了。即將原來32位表示一個 int 變爲一位表示一個 int. 從空間的角度來說就是巨大的節省了(1/32)。可能的應用有**大數據排序/查找(非負整數)**。 4 | 5 | C++ 中有`bitset`容器,其他語言可用類似方法實現。 6 | 7 | ## Implementation 8 | 9 | ### C 10 | 11 | ```c 12 | #include 13 | #include 14 | 15 | /* 16 | * @param bits: uint array, i: num i of original array 17 | */ 18 | void setbit(unsigned int *bits, unsigned int i, int BIT_LEN) 19 | { 20 | bits[i / BIT_LEN] |= 1 << (i % BIT_LEN); 21 | } 22 | 23 | /* 24 | * @param bits: uint array, i: num i of original array 25 | */ 26 | int testbit(unsigned int *bits, unsigned int i, int BIT_LEN) 27 | { 28 | return bits[i / BIT_LEN] & (1 << (i % BIT_LEN)); 29 | } 30 | 31 | int main(int argc, char *argv[]) 32 | { 33 | const int BIT_LEN = sizeof(int) * 8; 34 | const unsigned int N = 1 << (BIT_LEN - 1); 35 | unsigned int *bits = (unsigned int *)calloc(N, sizeof(int)); 36 | for (unsigned int i = 0; i < N; i++) { 37 | if (i % 10000001 == 0) setbit(bits, i, BIT_LEN); 38 | } 39 | 40 | for (unsigned int i = 0; i < N; i++) { 41 | if (testbit(bits, i, BIT_LEN) != 0) printf("i = %u exists.\n", i); 42 | } 43 | free(bits); 44 | bits = NULL; 45 | 46 | return 0; 47 | } 48 | ``` 49 | 50 | ### 源碼分析 51 | 52 | 核心爲兩個函數方法的使用,`setbit`用於將非負整數`i`置於指定的位。可用分區分位的方式來理解位圖排序的思想,即將非負整數`i`放到它應該在的位置。比如16,其可以位於第一個 int 型的第17位,具體實現即將第17位置一,細節見上面代碼。測試某個數是否存在於位圖中也可以採用類似方法。 53 | -------------------------------------------------------------------------------- /zh-tw/basics_algorithm/divide_and_conquer.md: -------------------------------------------------------------------------------- 1 | # Divide and Conquer - 分治法 2 | 3 | 在計算機科學中,分治法是一種很重要的演算法。分治法即『分而治之』,把一個複雜的問題分成兩個或更多的相同或相似的子問題,再把子問題分成更小的子問題……直到最後子問題可以簡單的直接求解,原問題的解即子問題的解的合併。這個思想是很多高效演算法的基礎,如排序演算法(快速排序,合併排序)等。 4 | 5 | ## 分治法思想 6 | 7 | 分治法所能解決的問題一般具有以下幾個特徵: 8 | 9 | 1. 問題的規模縮小到一定的程度就可以容易地解決。 10 | 2. 問題可以分解爲若干個規模較小的相同問題,即該問題具有**最優子結構**性質。 11 | 3. 利用該問題分解出的子問題的解可以合併爲該問題的解。 12 | 4. 該問題所分解出的各個子問題是相互獨立的,即子問題之間不包含公共的子問題。 13 | 14 | 分治法的三個步驟是: 15 | 16 | 1. 分解(Divide):將原問題分解爲若乾子問題,這些子問題都是原問題規模較小的實例。 17 | 2. 解決(Conquer):遞歸地求解各子問題。如果子問題規模足夠小,則直接求解。 18 | 3. 合併(Combine):將所有子問題的解合併爲原問題的解。 19 | 20 | 分治法的經典題目: 21 | 22 | 1. 二分搜索 23 | 2. 大整數乘法 24 | 3. Strassen矩陣乘法 25 | 4. 棋盤覆蓋 26 | 5. 歸並排序 27 | 6. 快速排序 28 | 7. 循環賽日程表 29 | 8. 河內塔 30 | -------------------------------------------------------------------------------- /zh-tw/basics_algorithm/math/README.md: -------------------------------------------------------------------------------- 1 | # Math 2 | 3 | 本小節總結一些與數學(尤其是數論部分)有關的基礎,主要總結了《挑戰程序設計競賽》(原文為《プログラミングコンテストチャレンジブック》)第二章。主要包含以下內容: 4 | 5 | 1. Greatest Common Divisor(最大公因數) 6 | 2. Prime(質數基礎理論) 7 | 3. Modulus(取模運算) 8 | 4. Fast Power(快速冪運算) 9 | 10 | ## Modulus - 取模運算 11 | 12 | 有時計算結果可能會溢位,此時往往需要對結果取餘。如果有`a % m = c % m` 和 `b % m = d % m`, 那麼有以下模運算成立。 13 | 14 | - `(a + b) % m = (c + d) % m` 15 | - `(a - b) % m = (c - d) % m` 16 | - `(a × b) % m = (c × d) % m` 17 | 18 | 需要注意的是沒有除法運算,另外由於最終結果可能溢位,故需要使用更大範圍的類型來保存取模之前的結果。另外若`a`是負數時往往需要改寫爲 `a % m + m`, 這樣就保證結果在`[0, m - 1]`範圍內了。 19 | 20 | ## Fast Power - 快速冪運算 21 | 22 | 快速冪運算的核心思想爲反覆平方法,將冪指數表示爲2的冪次的和,等價於二進制進行移位計算(不斷取冪的最低位),比如 $$x^{22} = x^{16} x^4 x^2$$. 23 | 24 | ### C++ 25 | 26 | ```C++ 27 | long long fastModPow(lont long x, int n, long long mod) { 28 | long long res = 1 % mod; 29 | while(n > 0) { 30 | //if lowest bit is 1, fast judge of even number 31 | if((n & 1) != 0) 32 | res = res * x % mod; 33 | x = x * x % mod; 34 | n >>= 1; 35 | } 36 | return res; 37 | } 38 | ``` 39 | 40 | ### Java 41 | 42 | ```java 43 | import java.util.*; 44 | 45 | public class FastPow { 46 | public static long fastModPow(long x, long n, long mod) { 47 | long res = 1 % mod; 48 | while (n > 0) { 49 | // if lowest bit is 1 50 | if ((n & 1) != 0) res = res * x % mod; 51 | x = x * x % mod; 52 | n >>= 1; 53 | } 54 | return res; 55 | } 56 | 57 | public static void main(String[] args) { 58 | if (args.length != 2 && args.length != 3) return; 59 | 60 | long x = Long.parseLong(args[0]); 61 | long n = Long.parseLong(args[1]); 62 | long mod = Long.MAX_VALUE; 63 | if (args.length == 3) { 64 | mod = Long.parseLong(args[2]); 65 | } 66 | System.out.println(fastModPow(x, n, mod)); 67 | } 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /zh-tw/basics_algorithm/probability/README.md: -------------------------------------------------------------------------------- 1 | # Probability 2 | -------------------------------------------------------------------------------- /zh-tw/basics_data_structure/README.md: -------------------------------------------------------------------------------- 1 | # Data Structure - 資料結構 2 | 3 | 本章主要介紹一些基本的資料結構和演算法。 4 | -------------------------------------------------------------------------------- /zh-tw/basics_data_structure/graph.md: -------------------------------------------------------------------------------- 1 | # Graph - 圖 2 | 3 | 圖的表示通常使用**鄰接矩陣和鄰接表**,前者易實現但是對於稀疏矩陣會浪費較多空間,後者使用鏈表的方式存儲資訊但是對於圖搜索時間複雜度較高。 4 | 5 | ## 程式實現 6 | 7 | ### 鄰接矩陣 (Adjacency Matrix) 8 | 9 | 設頂點個數爲 V, 那麼鄰接矩陣可以使用 V × V 的二維陣列來表示。 10 | `g[i][j]`表示頂點`i`和頂點`j`的關係,對於無向圖(undirected graph)可以使用0/1表示是否有連接,對於帶有權重的圖則需要使用`INF`來區分。有重邊時保存邊數或者權值最大/小的邊即可。 11 | 12 | #### Python 13 | ```python 14 | g = [[0 for _ in range(V)] for _ in range(V)] 15 | ``` 16 | 17 | #### Java 18 | ```java 19 | /* Java Definition */ 20 | int[][] g = new int[V][V]; 21 | ``` 22 | 23 | #### C++ 24 | ```C++ 25 | vector> g (V, vector(V, 0)); 26 | ``` 27 | 28 | 29 | ### 鄰接表 (Adjacency List) 30 | 31 | 鄰接表通過表示從頂點`i`出發到其他所有可能能到的邊。 32 | 33 | ### 有向圖 34 | 35 | #### Python 36 | 37 | ```python 38 | class DirectedGraphNode: 39 | def __init__(self, x): 40 | self.label = x 41 | self.neighbors = [] 42 | ``` 43 | 44 | #### Java 45 | 46 | ```java 47 | /* Java Definition */ 48 | class DirectedGraphNode { 49 | int label; 50 | ArrayList neighbors; 51 | DirectedGraphNode(int x) { 52 | label = x; 53 | neighbors = new ArrayList(); 54 | } 55 | } 56 | ``` 57 | 58 | #### C++ 59 | 60 | ```C++ 61 | struct DirectedGraphNode { 62 | int label; 63 | vector neighbors; 64 | 65 | DirectedGraphNode(int x): label(x) { } 66 | }; 67 | ``` 68 | 69 | ### 無向圖同上,只不過在建圖時雙向同時加。 70 | 71 | #### Python 72 | 73 | ```python 74 | class UndirectedGraphNode: 75 | def __init__(self, x): 76 | self.label = x 77 | self.neighbors = [] 78 | ``` 79 | 80 | 81 | #### Java 82 | 83 | ```java 84 | class UndirectedGraphNode { 85 | int label; 86 | ArrayList neighbors; 87 | UndirectedGraphNode(int x) { 88 | this.label = x; 89 | this.neighbors = new ArrayList(); 90 | } 91 | } 92 | ``` 93 | 94 | #### C++ 95 | 96 | ```C++ 97 | struct UndirectedGraphNode { 98 | int label; 99 | vector neighbors; 100 | 101 | UndirectedGraphNode(int x): label(x) { } 102 | }; 103 | ``` -------------------------------------------------------------------------------- /zh-tw/basics_data_structure/heap.md: -------------------------------------------------------------------------------- 1 | # Heap - 堆 2 | 3 | 一般情況下,堆通常指的是**二叉堆**,**二叉堆**是一個近似**完全二元樹**的數據結構,**即披著二元樹羊皮的陣列,**故使用陣列來實現較為便利。子結點的鍵值(key)或索引總是小於(或者大於)它的父節點,且每個節點的左右子樹又是一個**二叉堆**(大根堆(Max Heap)或者小根堆(Min Heap))。根節點最大的堆叫做最大堆或大根堆,根節點最小的堆叫做最小堆或小根堆。**常被用作實現優先隊列(Priority Queue)。** 4 | 5 | ## 特點 6 | 7 | 1. **以陣列表示,但是以完全二元樹的方式理解**。 8 | 2. 唯一能夠同時最優地利用空間和時間的方法——最壞情況下也能保證使用 $$2N \log N$$ 次比較和恒定的額外空間。 9 | 3. 在索引從0開始的陣列中: 10 | - 父節點 `i` 的左子節點在位置`(2*i+1)` 11 | - 父節點 `i` 的右子節點在位置`(2*i+2)` 12 | - 子節點 `i` 的父節點在位置`floor((i-1)/2)` 13 | 14 | ## 堆的基本操作 15 | 16 | 以大根堆為例,堆的常用操作如下。 17 | 18 | 1. 最大堆調整(Max_Heapify):將堆的末端子節點作調整,使得子節點永遠小於父節點 19 | 2. 創建最大堆(Build_Max_Heap):將堆所有數據重新排序 20 | 3. 堆排序(HeapSort):移除位在第一個數據的根節點,並做最大堆調整的遞迴運算 21 | 22 | 其中步驟1是給步驟2和3用的。 23 | 24 | ![Heapsort-example](../../shared-files/images/Heapsort-example.gif) 25 | 26 | ## Python 27 | 28 | ```python 29 | class MaxHeap: 30 | def __init__(self, array=None): 31 | if array: 32 | self.heap = self._max_heapify(array) 33 | else: 34 | self.heap = [] 35 | 36 | def _sink(self, array, i): 37 | # move node down the tree 38 | left, right = 2 * i + 1, 2 * i + 2 39 | max_index = i 40 | if left < len(array) and array[left] > array[max_index]: 41 | max_index = left 42 | if right < len(array) and array[right] > array[max_index]: 43 | max_index = right 44 | if max_index != i: 45 | array[i], array[max_index] = array[max_index], array[i] 46 | self._sink(array, max_index) 47 | 48 | def _swim(self, array, i): 49 | # move node up the tree 50 | if i == 0: 51 | return 52 | father = (i - 1) / 2 53 | if array[father] < array[i]: 54 | array[father], array[i] = array[i], array[father] 55 | self._swim(array, father) 56 | 57 | def _max_heapify(self, array): 58 | for i in xrange(len(array) / 2, -1, -1): 59 | self._sink(array, i) 60 | return array 61 | 62 | def push(self, item): 63 | self.heap.append(item) 64 | self._swim(self.heap, len(self.heap) - 1) 65 | 66 | def pop(self): 67 | self.heap[0], self.heap[-1] = self.heap[-1], self.heap[0] 68 | item = self.heap.pop() 69 | self._sink(self.heap, 0) 70 | return item 71 | ``` 72 | -------------------------------------------------------------------------------- /zh-tw/basics_data_structure/huffman_compression.md: -------------------------------------------------------------------------------- 1 | # Huffman Compression - 霍夫曼壓縮 2 | 3 | 主要思想:放棄文本文件的普通保存方式:不再使用7位或8位二進制數表示每一個字符,而是**用較少的比特表示出現頻率最高的字符,用較多的比特表示出現頻率低的字符**。 4 | 5 | 使用變動長度編碼(variable-length code)來表示字串,勢必會導致編解碼時碼字的唯一性問題,因此需要一種編解碼方式唯一的前綴碼(prefix code),而表示前綴碼的一種簡單方式就是使用單詞搜尋樹,其中最優前綴碼即為Huffman首創。 6 | 7 | 以符號F, O, R, G, E, T為例,其出現的頻次如以下表格所示。 8 | 9 | | Symbol | F | O | R | G | E | T | 10 | | -- | -- | -- | -- | -- | -- | -- | 11 | | Frequence | 2 | 3 | 4 | 4 | 5 | 7 | 12 | | Code | 000 | 001 | 100 | 101 | 01 | 11 | 13 | 14 | 則對各符號進行霍夫曼編碼的動態示例如下圖所示。基本步驟是將出現頻率由小到大排列,組成子樹後頻率相加作為整體再和其他未加入二元樹中的節點頻率比較。加權路徑長為節點的頻率乘以樹的深度。 15 | 16 | ![Huffman](../../shared-files/images/huffman_algorithm.gif) 17 | 18 | 有關霍夫曼編碼的具體步驟可參考 [Huffman 編碼壓縮算法 | 酷 殼 - CoolShell.cn](http://coolshell.cn/articles/7459.html) 和 [霍夫曼編碼 - 維基百科,自由的百科全書](http://zh.wikipedia.org/wiki/%E9%9C%8D%E5%A4%AB%E6%9B%BC%E7%BC%96%E7%A0%81),清晰易懂。 19 | -------------------------------------------------------------------------------- /zh-tw/basics_data_structure/map.md: -------------------------------------------------------------------------------- 1 | # Map - 關聯容器 2 | 3 | Map 是一種關聯數組的資料結構,也常被稱爲字典(dictionary)或鍵值對(key-value pair)。 4 | 5 | ## 程式實現 6 | 7 | ### Python 8 | 9 | 在 Python 中 `dict`(Map) 是一種基本的資料結構。 10 | 11 | ```python 12 | # map 在 python 中是一個keyword 13 | hash_map = {} # or dict() 14 | hash_map['shaun'] = 98 15 | hash_map['wei'] = 99 16 | exist = 'wei' in hash_map # check existence 17 | point = hash_map['shaun'] # get value by key 18 | point = hash_map.pop('shaun') # remove by key, return value 19 | keys = hash_map.keys() # return key list 20 | # iterate dictionary(map) 21 | for key, value in hash_map.items(): 22 | # do something with k, v 23 | pass 24 | ``` 25 | 26 | ### C++ 27 | 28 | 與 Set 類似,STL提供了 Map 與 Multimap 兩種,提供同一鍵(key)對應單個或多個值(value),自C++11以後,一樣提供兩種實現方式,基於紅-黑樹的`map`與`multimap`,包含在``標頭檔之中,鍵有序。另一個則是基於湊雜函數的`unordered_map`及`unordered_multimap`包含在標頭檔``,鍵無序。基本的 Map 使用如下所示 29 | 30 | ```C++ 31 | map mp; 32 | mp ["billryan"] = 69; 33 | mp ["crossluna"] = 159; 34 | auto it = mp.find("billryan"); 35 | if(it != mp.end()) { 36 | // "billryan" found 37 | cout << mp["billryan"]; // output: 69 38 | } 39 | ``` 40 | 另外可以藉由在建構時傳遞自訂的 Functor 、 Hash Function 以達成更彈性的使用,詳細用法及更多的介面請參考 STL 使用文檔。 41 | 42 | ### Java 43 | 44 | Java 的實現中 Map 是一種將物件與物件相關聯的設計。常用的實現有`HashMap`和`TreeMap`, `HashMap`被用來快速訪問,而`TreeMap`則保證『鍵』始終有序。Map 可以返回鍵的 Set, 值的 Collection, 鍵值對的 Set. 45 | 46 | ```java 47 | Map map = new HashMap(); 48 | map.put("bill", 98); 49 | map.put("ryan", 99); 50 | boolean exist = map.containsKey("ryan"); // check key exists in map 51 | int point = map.get("bill"); // get value by key 52 | int point = map.remove("bill") // remove by key, return value 53 | Set set = map.keySet(); 54 | // iterate Map 55 | for (Map.Entry entry : map.entrySet()) { 56 | String key = entry.getKey(); 57 | int value = entry.getValue(); 58 | // do some thing 59 | } 60 | ``` -------------------------------------------------------------------------------- /zh-tw/basics_data_structure/priority_queue.md: -------------------------------------------------------------------------------- 1 | # Priority Queue - 優先隊列 2 | 3 | 應用程序常常需要處理帶有優先級的業務,優先級最高的業務首先得到服務。因此優先隊列這種資料結構應運而生。優先隊列中的每個元素都有各自的優先級,優先級最高的元素最先得到服務;優先級相同的元素按照其在優先隊列中的順序得到服務,例如作業系統(operating system)中的任務調度。 4 | 5 | 優先隊列與其說是資料結構,不如說是一種抽象資料型別(Abstract Data Type,ADT),其介面(interface)至少需要三個基本的方法(method): 6 | - 插入一筆優先級別資料 (insert_with_priority) 7 | - 取出最優先資料 (pull_highest_priority_element) 8 | - 查看最優先資料 (peak) 9 | 若使用C++的STL提供的介面則如下所示 10 | 11 | ```c++ 12 | template class priority_queue{ 13 | void push (const T& val); 14 | void pop (); 15 | const T& top() const; 16 | }; 17 | ``` 18 | 19 | 優先隊列可以使用數組或鏈表實現,從時間和空間複雜度來說,往往用堆(heap)來實現。 20 | 21 | ## Reference 22 | 23 | - [優先佇列 - 維基百科,自由的百科全書](http://zh.wikipedia.org/zh/%E5%84%AA%E5%85%88%E4%BD%87%E5%88%97) 24 | - [STL: priority_queue](http://www.cplusplus.com/reference/queue/priority_queue/) 25 | -------------------------------------------------------------------------------- /zh-tw/basics_data_structure/set.md: -------------------------------------------------------------------------------- 1 | # Set 2 | 3 | Set 是一種用於保存不重複元素的資料結構。常被用作測試歸屬性,故其查找的性能十分重要。 4 | 5 | ## 程式實現 6 | 7 | ### Python 8 | 9 | `Set` 是`python`自帶的基本資料結構, 有多種初始化方式。 `Python`的`set`跟`dict`的Implementation方式類似, 可以認爲`set`是只有`key`的`dict`. 10 | 11 | ```python 12 | s = set() 13 | s1 = {1, 2, 3} 14 | s.add('shaunwei') 15 | 'shaun' in s # return true 16 | s.remove('shaunwei') 17 | ``` 18 | 19 | ### C++ 20 | 21 | STL提供的資料結構有 Set 以及 Multiset ,分別提供不重複與重複元素的版本,自C++11以後,STL提供兩種 Set 的實現方式,一個是基於紅-黑樹的`set`與`multiset`,包含在``標頭檔之中,有序。另一個則是基於湊雜函數的`unordered_set`及`unordered_multiset`,包含在標頭檔``,無序。基本的 Set 使用如下所示 22 | 23 | ```C++ 24 | set s; 25 | s.insert("crossluna"); 26 | s.insert("billryan"); 27 | auto it = s.find("lucifer"); 28 | if(it != s.end()) { 29 | // "lucifer" found 30 | } 31 | ``` 32 | 另外可以藉由在建構時傳遞自訂的 Functor 、 Hash Function 以達成更彈性的使用,詳細用法及更多的介面請參考 STL 使用文檔。 33 | 34 | 35 | ### Java 36 | 37 | Set 與 Collection 具有安全一樣的接口,通常有`HashSet`, `TreeSet` 或 `LinkedHashSet`三種實現。`HashSet`基於湊雜函數實現,無序,查詢速度最快;`TreeSet`基於紅-黑樹實現,有序。 38 | 39 | ```java 40 | Set hash = new HashSet(); 41 | hash.add("billryan"); 42 | hash.contains("billryan"); 43 | ``` 44 | 45 | 在不允許重複元素時可當做哈希表來用。 46 | 47 | -------------------------------------------------------------------------------- /zh-tw/basics_data_structure/stack.md: -------------------------------------------------------------------------------- 1 | # Stack - 堆疊 2 | 3 | 堆疊是一種 LIFO(Last In First Out) 的資料結構,常用方法有添加元素,讀Stack頂元素,彈出(pop) Stack頂元素,判斷堆疊是否為空。 4 | 5 | ## 程式碼實現 6 | 7 | ### Python 8 | ```python 9 | stack = [] 10 | len(stack) # size of stack 11 | 12 | # more efficient stack 13 | import collections 14 | stack = collections.deque() 15 | ``` 16 | 17 | `list`作為最基本的`python`資料結構之一, 可以很輕鬆地實現`stack`。 如果需要更高效的`stack`, 建議使用`deque`。 18 | 19 | #### Methods 20 | 21 | - `len(stack) != 0` - 判斷`stack`是否為空 22 | - `stack[-1]` - 取堆疊頂元素,不移除 23 | - `pop()` - 移除堆疊頂元素並返回該元素 24 | - `append(item)` - 向堆疊頂添加元素 25 | 26 | 27 | ### Java 28 | 29 | ```java 30 | Deque stack = new ArrayDeque(); 31 | s.size(); // size of stack 32 | ``` 33 | 34 | JDK doc 中建議使用`Deque`代替`Stack`實現堆疊,因為`Stack`繼承自`Vector`,需要`synchronized`,性能略低。 35 | 36 | #### Methods 37 | 38 | - `boolean isEmpty()` - 判斷堆疊是否為空,若使用 Stack 類構造則為 empty() 39 | - `E peek()` - 取堆疊頂元素,不移除 40 | - `E pop()` - 移除堆疊頂元素並返回該元素 41 | - `E push(E item)` - 向堆疊頂添加元素 42 | -------------------------------------------------------------------------------- /zh-tw/basics_data_structure/string.md: -------------------------------------------------------------------------------- 1 | # String 字串 2 | 3 | String 相關的題很常出現在面試題中,實際開發也經常用到,這裡總結一下 C++, Java, Python 中字串常用的方法。 4 | 5 | ## Python 6 | 7 | ```python 8 | s1 = str() 9 | # in python `''` and `""` are the same 10 | s2 = "shaunwei" # 'shaunwei' 11 | s2len = len(s2) 12 | # last 3 chars 13 | s2[-3:] # wei 14 | s2[5:8] # wei 15 | s3 = s2[:5] # shaun 16 | s3 += 'wei' # return 'shaunwei' 17 | # list in python is same as ArrayList in java 18 | s2list = list(s3) 19 | # string at index 4 20 | s2[4] # 'n' 21 | # find index at first 22 | s2.index('w') # return 5, if not found, throw ValueError 23 | s2.find('w') # return 5, if not found, return -1 24 | ``` 25 | 26 | 在Python裡面,沒有StringBuffer 或者 StringBuilder。 但是在Python 裡面處理String本身就比較 cheap。 27 | 28 | ## Java 29 | 30 | ```java 31 | String s1 = new String(); 32 | String s2 = "billryan"; 33 | int s2Len = s2.length(); 34 | s2.substring(4, 8); // return "ryan" 35 | StringBuilder s3 = new StringBuilder(s2.substring(4, 8)); 36 | s3.append("bill"); 37 | String s2New = s3.toString(); // return "ryanbill" 38 | // convert String to char array 39 | char[] s2Char = s2.toCharArray(); 40 | // char at index 4 41 | char ch = s2.charAt(4); // return 'r' 42 | // find index at first 43 | int index = s2.indexOf('r'); // return 4. if not found, return -1 44 | ``` 45 | 46 | StringBuffer 與 StringBuilder, 前者保證執行緒安全(Thread Safety),後者不是,但單執行緒下效率高一些,一般使用 StringBuilder. 47 | -------------------------------------------------------------------------------- /zh-tw/basics_misc/README.md: -------------------------------------------------------------------------------- 1 | # Basics Miscellaneous 2 | 3 | 雜項,涉及「位操作」等。 4 | -------------------------------------------------------------------------------- /zh-tw/basics_misc/bit_manipulation.md: -------------------------------------------------------------------------------- 1 | # Bit Manipulation 2 | 3 | 位操作有按位與(bitwise and)、或(bitwise or)、非(bitwise not)、左移n位和右移n位等操作。 4 | 5 | ### XOR - 異或(exclusive or) 6 | 7 | > 異或:相同為0,不同為1。也可用「不進位加法」來理解。 8 | 9 | 異或操作的一些特點: 10 | ``` 11 | x ^ 0 = x 12 | x ^ 1s = ~x // 1s = ~0 13 | x ^ (~x) = 1s 14 | x ^ x = 0 // interesting and important! 15 | a ^ b = c => a ^ c = b, b ^ c = a // swap 16 | a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c // associative 17 | ``` 18 | 19 | ### 移位操作(shift operation) 20 | 21 | 移位操作可近似為乘以/除以2的冪。`0b0010 * 0b0110`等價於`0b0110 << 2`. 下面是一些常見的移位組合操作。 22 | 23 | 1. 將`x`最右邊的`n`位清零 - `x & (~0 << n)` 24 | 2. 獲取`x`的第`n`位值(0或者1) - `x & (1 << n)` 25 | 2. 獲取`x`的第`n`位的冪值 - `(x >> n) & 1` 26 | 3. 僅將第`n`位置為`1` - `x | (1 << n)` 27 | 4. 僅將第`n`位置為`0` - `x & (~(1 << n))` 28 | 5. 將`x`最高位至第`n`位(含)清零 - `x & ((1 << n) - 1)` 29 | 6. 將第`n`位至第0位(含)清零 - `x & (~((1 << (n + 1)) - 1))` 30 | 7. 僅更新第`n`位,寫入值為`v`; `v`為1則更新為1,否則為0 - `mask = ~(1 << n); x = (x & mask) | (v << i)` 31 | 32 | ###實際應用 33 | 34 | ####位圖(Bitmap) 35 | 36 | 位圖一般用於替代flag array,節約空間。
37 | 一個int型的陣列用位圖替換後,占用的空間可以縮小到原來的$$1/32$$.(若int類型是32位元)
38 | 下面代碼定義了一個100萬大小的類圖,setbit和testbit函數 39 | ```c++ 40 | #define N 1000000 // 1 million 41 | #define WORD_LENGTH sizeof(int) * 8 //sizeof返回字節數,乘以8,為int類型總位數 42 | 43 | //bits為陣列,i控制具體哪位,即i為0~1000000 44 | void setbit(unsigned int* bits, unsigned int i){ 45 | bits[i / WORD_LENGTH] |= 1<<(i % WORD_LENGTH); 46 | } 47 | 48 | int testbit(unsigned int* bits, unsigned int i){ 49 | return bits[i/WORD_LENGTH] & (1<<(i % WORD_LENGTH)); 50 | } 51 | 52 | unsigned int bits[N/WORD_LENGTH + 1]; 53 | ``` 54 | 55 | ## Reference 56 | 57 | - [位運算應用技巧(1) » NoAlGo博客](http://noalgo.info/344.html) 58 | - [位運算應用技巧(2) » NoAlGo博客](http://noalgo.info/353.html) 59 | - [位運算簡介及實用技巧(一):基礎篇 | Matrix67: The Aha Moments](http://www.matrix67.com/blog/archives/263) 60 | - *cc150* chapter 8.5 and chapter 9.5 61 | - 《編程珠璣2》 62 | - 《Elementary Algorithms》 Larry LIU Xinyu 63 | -------------------------------------------------------------------------------- /zh-tw/basics_sorting/README.md: -------------------------------------------------------------------------------- 1 | # Basics Sorting - 基礎排序演算法 2 | 3 | # 演算法複習——排序 4 | 5 | 6 | 7 | ## 演算法分析 8 | 9 | 1. 時間複雜度-執行時間(比較和交換次數) 10 | 2. 空間複雜度-所消耗的額外記憶體空間 11 | - 使用小堆疊、隊列或表 12 | - 使用鏈表或指針、數組索引來代表數據 13 | - 排序數據的副本 14 | 15 | 在OJ上做題時,一些經驗法則(rule of thumb)以及封底估算(back-of-the-envelop calculation)可以幫助選擇適合的演算法,一個簡單的經驗法則是 16 | 17 | 10^9 operations per second 18 | 舉例來說,如果今天遇到一個題目,時間限制是1s,但僅有$$10^3$$筆輸入數據,此時即使使用$$O(n^2)$$的演算法也沒問題,但若有$$10^5$$筆輸入,則$$O(n^2)$$的演算法則非常可能超時,在實作前就要先思考是不是有$$O(n\log n)$$或更快的演算法。 19 | 20 | 對具有重鍵的數據(同一組數按不同鍵多次排序)進行排序時,需要考慮排序方法的穩定性,在非穩定性排序演算法中需要穩定性時可考慮加入小索引。 21 | 22 | 穩定性:如果排序後文件中擁有相同鍵的項的相對位置不變,這種排序方式是穩定的。 23 | 24 | 常見的排序演算法根據是否需要比較可以分為如下幾類: 25 | 26 | - Comparison Sorting 27 | 1. Bubble Sort 28 | 2. Selection Sort 29 | 3. Insertion Sort 30 | 4. Shell Sort 31 | 5. Merge Sort 32 | 6. Quck Sort 33 | 7. Heap Sort 34 | - Bucket Sort 35 | - Counting Sort 36 | - Radix Sort 37 | 38 | 從穩定性角度考慮可分為如下兩類: 39 | - 穩定 40 | - 非穩定 41 | 42 | ## Reference 43 | 44 | - [Sorting algorithm - Wikipedia, the free encyclopedia](http://en.wikipedia.org/wiki/Sorting_algorithm) - 各類排序演算法的「平均、最好、最壞時間複雜度」總結。 45 | - [Big-O cheatsheet](http://bigocheatsheet.com/) - 更清晰的總結 46 | - [經典排序演算法總結與實現 | Jark's Blog](http://wuchong.me/blog/2014/02/09/algorithm-sort-summary/) - 基於 Python 的較為清晰的總結。 47 | - [【面經】矽谷前沿Startup面試經驗-排序演算法總結及快速排序演算法代碼_九章演算法](http://blog.sina.com.cn/s/blog_eb52001d0102v1k8.html) - 總結了一些常用常問的排序演算法。 48 | - [雷克雅維克大學的程式競賽課程](http://algo.is/) 49 | 第一講的slide中提供了演算法分析的經驗法則 50 | -------------------------------------------------------------------------------- /zh-tw/basics_sorting/bubble_sort.md: -------------------------------------------------------------------------------- 1 | # Bubble Sort - 氣泡排序 2 | 3 | 核心:**氣泡**,持續比較相鄰元素,大的挪到後面,因此大的會逐步往後挪,故稱之為氣泡。 4 | 5 | ![Bubble Sort](../../shared-files/images/bubble_sort.gif) 6 | 7 | ## Implementation 8 | 9 | ### Python 10 | 11 | ```python 12 | #!/usr/bin/env python 13 | 14 | 15 | def bubbleSort(alist): 16 | for i in xrange(len(alist)): 17 | print(alist) 18 | for j in xrange(1, len(alist) - i): 19 | if alist[j - 1] > alist[j]: 20 | alist[j - 1], alist[j] = alist[j], alist[j - 1] 21 | 22 | return alist 23 | 24 | unsorted_list = [6, 5, 3, 1, 8, 7, 2, 4] 25 | print(bubbleSort(unsorted_list)) 26 | ``` 27 | 28 | ### Java 29 | 30 | ```java 31 | public class Sort { 32 | public static void main(String[] args) { 33 | int unsortedArray[] = new int[]{6, 5, 3, 1, 8, 7, 2, 4}; 34 | bubbleSort(unsortedArray); 35 | System.out.println("After sort: "); 36 | for (int item : unsortedArray) { 37 | System.out.print(item + " "); 38 | } 39 | } 40 | 41 | public static void bubbleSort(int[] array) { 42 | int len = array.length; 43 | for (int i = 0; i < len; i++) { 44 | for (int item : array) { 45 | System.out.print(item + " "); 46 | } 47 | System.out.println(); 48 | for (int j = 1; j < len - i; j++) { 49 | if (array[j - 1] > array[j]) { 50 | int temp = array[j - 1]; 51 | array[j - 1] = array[j]; 52 | array[j] = temp; 53 | } 54 | } 55 | } 56 | } 57 | } 58 | ``` 59 | 60 | ###C++ 61 | ```C++ 62 | void bubbleSort(vector & arr){ 63 | for(int i = 0; i < arr.size(); i++){ 64 | for(int j = 1; j < arr.size() - i; j++){ 65 | if(arr[j - 1] > arr[j])){ 66 | std::swap(arr[j-1], arr[j]); 67 | } 68 | } 69 | } 70 | return arr; 71 | } 72 | ``` 73 | 74 | ### 複雜度分析 75 | 76 | 平均情況與最壞情況均為 $$O(n^2)$$, 使用了 temp 作為臨時交換變量,空間複雜度為 $$O(1)$$. 77 | 可以做適當程度的優化,當某一次外迴圈中發現陣列已經有序,就跳出迴圈不再執行,但這僅對於部分的輸入有效,平均及最壞時間複雜度仍為$$O(n^2)$$ 78 | 79 | ```C++ 80 | void bubbleSort(vector & arr){ 81 | bool unsorted = true; 82 | for(int i = 0; i < arr.size() && unsorted; i++){ 83 | unsorted = false; 84 | for(int j = 1; j < arr.size() - i; j++){ 85 | if(arr[j - 1] > arr[j])){ 86 | std::swap(arr[j-1], arr[j]); 87 | unsorted = true; 88 | } 89 | } 90 | } 91 | return arr; 92 | } 93 | ``` 94 | 95 | ## Reference 96 | 97 | - [氣泡排序 - 維基百科,自由的百科全書](http://zh.wikipedia.org/wiki/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F) 98 | -------------------------------------------------------------------------------- /zh-tw/basics_sorting/bucket_sort.md: -------------------------------------------------------------------------------- 1 | # Bucket Sort 2 | 3 | 桶排序和合併排序有那麼點點類似,也使用了合併的思想。大致步驟如下: 4 | 5 | 1. 設置一個定量的數組當作空桶。 6 | 2. Divide - 從待排序數組中取出元素,將元素按照一定的規則塞進對應的桶子去。 7 | 3. 對每個非空桶進行排序,通常可在塞元素入桶時進行插入排序。 8 | 4. Conquer - 從非空桶把元素再放回原來的數組中。 9 | 10 | ## Reference 11 | 12 | - [Bucket Sort Visualization](http://www.cs.usfca.edu/~galles/visualization/BucketSort.html) - 動態示例。 13 | - [桶排序 - 維基百科,自由的百科全書](http://zh.wikipedia.org/wiki/%E6%A1%B6%E6%8E%92%E5%BA%8F) 14 | -------------------------------------------------------------------------------- /zh-tw/basics_sorting/counting_sort.md: -------------------------------------------------------------------------------- 1 | # Counting Sort 2 | 3 | 計數排序,顧名思義,就是對待排序陣列按元素進行計數。使用前提是需要先知道待排序陣列的元素範圍,將這些一定範圍的元素置於新陣列中,新陣列的大小爲待排序陣列中最大元素與最小元素的差值。 4 | 5 | 維基上總結的四個步驟如下: 6 | 7 | 1. 定新陣列大小——找出待排序的陣列中最大和最小的元素 8 | 2. 統計次數——統計陣列中每個值爲i的元素出現的次數,存入新陣列C的第i項 9 | 3. 對統計次數逐個累加——對所有的計數累加(從C中的第一個元素開始,每一項和前一項相加) 10 | 4. 反向填充目標陣列——將每個元素i放在新陣列的第C(i)項,每放一個元素就將C(i)減去1 11 | 12 | 其中反向填充主要是爲了避免重復元素落入新陣列的同一索引處。 13 | 14 | ## Reference 15 | 16 | - [計數排序 - 維基百科,自由的百科全書](http://zh.wikipedia.org/wiki/%E8%AE%A1%E6%95%B0%E6%8E%92%E5%BA%8F) - 中文版的維基感覺比英文版的好理解些。 17 | - [Counting Sort Visualization](https://www.cs.usfca.edu/~galles/visualization/CountingSort.html) - 動畫真心不錯~ 結合著看一遍就理解了。 18 | -------------------------------------------------------------------------------- /zh-tw/basics_sorting/radix_sort.md: -------------------------------------------------------------------------------- 1 | # Radix Sort 2 | 3 | 經典排序演算法 - 基數排序Radix sort 4 | 5 | 原理類似桶排序 Bucket Sort,這裡總是需要10個桶,多次使用 6 | 7 | 首先以個位數的值進行裝桶,即個位數爲1則放入1號桶,爲9則放入9號桶,暫時忽視十位數 8 | 9 | 例如 10 | 11 | 取一個簡單的待排序陣列[62,14,59,88,16] 12 | 13 | 分配10個桶,桶編號爲0-9,以個位數數字爲桶編號依次放入桶,變成下邊這樣 14 | 15 | | 0 | 0 | 62 | 0 | 14 | 0 | 16 | 0 | 88 | 59 | 16 | 17 | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |桶編號 18 | 19 | 將桶裏的數字順序取出來, 20 | 21 | 輸出結果:[62,14,16,88,59] 22 | 23 | 再次入桶,不過這次以十位數的數字爲準,進入相應的桶,變成下邊這樣: 24 | 25 | 由於前邊做了個位數的排序,所以當十位數相等時,個位數字是由小到大的順序入桶的,就是說,入完桶還是有序 26 | 27 | | 0 | 14,16 | 0 | 0 | 0 | 59 | 62 | 0 | 88 | 0 | 28 | 29 | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |桶編號 30 | 31 | 32 | 33 | 34 | 因爲沒有大過100的數字,沒有百位數,所以到這排序完畢,順序取出即可 35 | 36 | 最後輸出結果:[14,16,59,62,88] 37 | 38 | 39 | 文章引用自 40 | http://www.cnblogs.com/kkun/archive/2011/11/23/2260275.html 41 | -------------------------------------------------------------------------------- /zh-tw/basics_sorting/selection_sort.md: -------------------------------------------------------------------------------- 1 | # Selection Sort - 選擇排序 2 | 3 | 核心:不斷地選擇剩餘元素中的最小者。 4 | 5 | 1. 找到陣列中最小元素並將其和陣列第一個元素交換位置。 6 | 2. 在剩下的元素中找到最小元素並將其與陣列第二個元素交換,直至整個陣列排序。 7 | 8 | 性質: 9 | 10 | - 比較次數=(N-1)+(N-2)+(N-3)+...+2+1~N^2/2 11 | - 交換次數=N 12 | - 運行時間與輸入無關 13 | - 數據移動最少 14 | 15 | 下圖來源為 [File:Selection-Sort-Animation.gif - IB Computer Science](http://wiki.ibcsstudent.org/index.php?title=File:Selection-Sort-Animation.gif) 16 | 17 | ![Selection Sort](../../shared-files/images/selection_sort.gif) 18 | 19 | ## Implementation 20 | 21 | ### Python 22 | 23 | ```python 24 | #!/usr/bin/env python 25 | 26 | 27 | def selectionSort(alist): 28 | for i in xrange(len(alist)): 29 | print(alist) 30 | min_index = i 31 | for j in xrange(i + 1, len(alist)): 32 | if alist[j] < alist[min_index]: 33 | min_index = j 34 | alist[min_index], alist[i] = alist[i], alist[min_index] 35 | return alist 36 | 37 | unsorted_list = [8, 5, 2, 6, 9, 3, 1, 4, 0, 7] 38 | print(selectionSort(unsorted_list)) 39 | ``` 40 | 41 | ### Java 42 | 43 | ```java 44 | public class Sort { 45 | public static void main(String[] args) { 46 | int unsortedArray[] = new int[]{8, 5, 2, 6, 9, 3, 1, 4, 0, 7}; 47 | selectionSort(unsortedArray); 48 | System.out.println("After sort: "); 49 | for (int item : unsortedArray) { 50 | System.out.print(item + " "); 51 | } 52 | } 53 | 54 | public static void selectionSort(int[] array) { 55 | int len = array.length; 56 | for (int i = 0; i < len; i++) { 57 | for (int item : array) { 58 | System.out.print(item + " "); 59 | } 60 | System.out.println(); 61 | int min_index = i; 62 | for (int j = i + 1; j < len; j++) { 63 | if (array[j] < array[min_index]) { 64 | min_index = j; 65 | } 66 | } 67 | int temp = array[min_index]; 68 | array[min_index] = array[i]; 69 | array[i] = temp; 70 | } 71 | } 72 | } 73 | ``` 74 | 75 | ###C++ 76 | 77 | ```C++ 78 | void selectionSort(vector & arr){ 79 | int min_idx = 0; 80 | for(int i = 0; i < arr.size(); i++){ 81 | min_idx = i; 82 | for(int j = i + 1; j < arr.size(); j++){ 83 | if (arr[j] < arr[min_idx]) 84 | min_idx = j; 85 | } 86 | std::swap(arr[i], arr[min_idx]); 87 | } 88 | } 89 | ``` 90 | 91 | ## Reference 92 | 93 | - [選擇排序 - 維基百科,自由的百科全書](http://zh.wikipedia.org/wiki/%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F) 94 | - [The Selection Sort — Problem Solving with Algorithms and Data Structures](http://interactivepython.org/runestone/static/pythonds/SortSearch/TheSelectionSort.html) 95 | -------------------------------------------------------------------------------- /zh-tw/binary_search/README.md: -------------------------------------------------------------------------------- 1 | # Search - 搜索 2 | 3 | 本章主要總結二分搜索相關的題目。 4 | 5 | - 能使用二分搜索的前提是數組已排序。 6 | - 二分搜索的使用場景:(1)可轉換為find the first/last position of...(2)時間複雜度至少為$$O(\log n)$$。 7 | - 遞迴和迭代的使用場景:能用迭代就用迭代,特別複雜時採用遞迴。 8 | -------------------------------------------------------------------------------- /zh-tw/binary_search/sqrt_x.md: -------------------------------------------------------------------------------- 1 | # Sqrt x 2 | 3 | ## Question 4 | 5 | - leetcode: [Sqrt(x) | LeetCode OJ](https://leetcode.com/problems/sqrtx/) 6 | - lintcode: [(141) Sqrt(x)](http://www.lintcode.com/en/problem/sqrtx/) 7 | 8 | ## 題解 - 二分搜索 9 | 10 | 由於只需要求整數部分,故對於任意正整數 $$x$$, 設其整數部分為 $$k$$, 顯然有 $$1 \leq k \leq x$$, 求解 $$k$$ 的值也就轉化為了在有序陣列中查找滿足某種約束條件的元素,顯然二分搜索是解決此類問題的良方。 11 | 12 | ### Python 13 | 14 | ```python 15 | class Solution: 16 | # @param {integer} x 17 | # @return {integer} 18 | def mySqrt(self, x): 19 | if x < 0: 20 | return -1 21 | elif x == 0: 22 | return 0 23 | 24 | start, end = 1, x 25 | while start + 1 < end: 26 | mid = start + (end - start) / 2 27 | if mid**2 == x: 28 | return mid 29 | elif mid**2 > x: 30 | end = mid 31 | else: 32 | start = mid 33 | 34 | return start 35 | ``` 36 | 37 | ### 源碼分析 38 | 39 | 1. 異常檢測,先處理小於等於0的值。 40 | 2. 使用二分搜索的經典模板,注意不能使用`start < end`, 否則在給定值1時產生死循環。 41 | 3. 最後返回平方根的整數部分`start`. 42 | 43 | 二分搜索過程很好理解,關鍵是最後的返回結果還需不需要判斷?比如是取 start, end, 還是 mid? 我們首先來分析下二分搜索的循環條件,由`while`循環條件`start + 1 < end`可知,`start`和`end`只可能有兩種關系,一個是`end == 1 || end ==2`這一特殊情況,返回值均為1,另一個就是循環終止時`start`恰好在`end`前一個元素。設值 x 的整數部分為 k, 那麼在執行二分搜索的過程中 $$ start \leq k \leq end$$ 關系一直存在,也就是說在沒有找到 $$mid^2 == x$$ 時,循環退出時有 $$start < k < end$$, 取整的話顯然就是`start`了。 44 | 45 | 46 | ### C++ 47 | ```c++ 48 | class Solution{ 49 | public: 50 | int mySqrt(int x) { 51 | if(x <= 1) return x; 52 | int lo = 2, hi = x; 53 | while(lo < hi){ 54 | int m = lo + (hi - lo)/2; 55 | int q = x/m; 56 | if(q == m and x % m == 0) 57 | return m; 58 | else if(q < m) 59 | hi = m; 60 | else 61 | lo = m + 1; 62 | } 63 | 64 | return lo - 1; 65 | } 66 | }; 67 | ``` 68 | 69 | ### 源碼分析 70 | 此題依然可以被翻譯成"找不大於target的$$x^2$$",而所有待選的自然數當然是有序數列,因此同樣可以用二分搜索的思維解題,然而此題不會出現重複元素,因此可以增加一個相等就返回的條件,另外這邊我們同樣使用[lo, hi)的標示法來處理邊界條件,可以參照[Search for a range],就不再贅述。另外特別注意,判斷找到的條件不是用`m * m == x`而是`x / m == m`,這是因為`x * x`可能會超出`INT_MAX`而溢位,因此用除法可以解決這個問題,再輔以餘數判斷是否整除以及下一步的走法。 71 | 72 | ### 複雜度分析 73 | 74 | 經典的二分搜索,時間複雜度為 $$O(\log n)$$, 使用了`start`, `end`, `mid`變量,空間複雜度為 $$O(1)$$. 75 | 76 | 除了使用二分法求平方根近似解之外,還可使用牛頓迭代法進一步提高運算效率,欲知後事如何,請猛戳 [求平方根sqrt()函數的底層算法效率問題 -- 簡明現代魔法](http://www.nowamagic.net/algorithm/algorithm_EfficacyOfFunctionSqrt.php),不得不感歎演算法的魔力! 77 | -------------------------------------------------------------------------------- /zh-tw/binary_search_tree/README.md: -------------------------------------------------------------------------------- 1 | # Binary Search Tree - 二元搜尋樹 2 | 3 | 二元搜尋樹的定義及簡介在 [Binary Search Trees](http://algorithm.yuanbin.me/zh-hans/basics_data_structure/binary_search_tree.html) 中已經有所介紹。簡單來說就是每個節點的值大於等於左子結點的值,而小於右子節點的值。 4 | -------------------------------------------------------------------------------- /zh-tw/binary_tree/README.md: -------------------------------------------------------------------------------- 1 | Maximum Depth of Binary Tree# Binary Tree - 二元樹 2 | 3 | 二元樹的基本概念在 [Binary Tree | Algorithm](http://algorithm.yuanbin.zh-hans/basics_data_structure/binary_tree.html) 中有簡要的介紹,這裏就二元樹的一些應用做一些實戰演練。 4 | 5 | 二元樹的遍歷大致可分為前序、中序、後序三種方法。 6 | -------------------------------------------------------------------------------- /zh-tw/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/zh-tw/cover.jpg -------------------------------------------------------------------------------- /zh-tw/cover_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billryan/algorithm-exercise/ff1ae6c218ef1e554cba0a3f88aa265240db7d54/zh-tw/cover_small.jpg -------------------------------------------------------------------------------- /zh-tw/data_structure/README.md: -------------------------------------------------------------------------------- 1 | # Data Structure 2 | 3 | 本章主要總結如 Queue, Stack 等資料結構相關的題目。 4 | -------------------------------------------------------------------------------- /zh-tw/dynamic_programming/climbing_stairs.md: -------------------------------------------------------------------------------- 1 | # Climbing Stairs 2 | 3 | ## Question 4 | 5 | - lintcode: [(111) Climbing Stairs](http://www.lintcode.com/en/problem/climbing-stairs/) 6 | 7 | ``` 8 | You are climbing a stair case. It takes n steps to reach to the top. 9 | 10 | Each time you can either climb 1 or 2 steps. 11 | In how many distinct ways can you climb to the top? 12 | 13 | Example 14 | Given an example n=3 , 1+1+1=2+1=1+2=3 15 | 16 | return 3 17 | ``` 18 | 19 | ## 題解 20 | 21 | 題目問的是到達頂端的方法數,我們採用序列類問題的通用分析方法,可以得到如下四要素: 22 | 23 | 1. State: f[i] 爬到第i級的方法數 24 | 2. Function: f[i]=f[i-1]+f[i-2] 25 | 3. Initialization: f[0]=1,f[1]=1 26 | 4. Answer: f[n] 27 | 28 | 尤其注意狀態轉移方程的寫法,f[i]只可能由兩個中間狀態轉化而來,一個是f[i-1],由f[i-1]到f[i]其方法總數並未增加;另一個是f[i-2],由f[i-2]到f[i]隔了兩個臺階,因此有1+1和2兩個方法,因此容易寫成 f[i]=f[i-1]+f[i-2]+1,但仔細分析後能發現,由f[i-2]到f[i]的中間狀態f[i-1]已經被利用過一次,故f[i]=f[i-1]+f[i-2]. 使用動規思想解題時需要分清『重疊子狀態』, 如果有重複的需要去掉。 29 | 30 | ### C++ 31 | 32 | ```c++ 33 | class Solution { 34 | public: 35 | /** 36 | * @param n: An integer 37 | * @return: An integer 38 | */ 39 | int climbStairs(int n) { 40 | if (n < 1) { 41 | return 0; 42 | } 43 | 44 | vector ret(n + 1, 1); 45 | 46 | for (int i = 2; i != n + 1; ++i) { 47 | ret[i] = ret[i - 1] + ret[i - 2]; 48 | } 49 | 50 | return ret[n]; 51 | } 52 | }; 53 | ``` 54 | 55 | 1. 異常處理 56 | 2. 初始化n+1個元素,初始值均爲1。之所以用n+1個元素是下標分析起來更方便 57 | 3. 狀態轉移方程 58 | 4. 返回ret[n] 59 | 60 | 初始化ret[0]也爲1,可以認爲到第0級也是一種方法。 61 | 62 | 以上答案的空間複雜度爲 $$O(n)$$,仔細觀察後可以發現在狀態轉移方程中,我們可以使用三個變數來替代長度爲n+1的數組。具體程式碼可參考 [climbing-stairs | 九章算法 ](http://www.jiuzhang.com/solutions/climbing-stairs/) 63 | 64 | ### Python 65 | ```python 66 | class Solution: 67 | def climbStairs(n): 68 | if n < 1: 69 | return 0 70 | 71 | l = r = 1 72 | for _ in xrange(n - 1): 73 | l, r = r, r + l 74 | return r 75 | ``` 76 | 77 | ### C++ 78 | 79 | ```c++ 80 | class Solution { 81 | public: 82 | /** 83 | * @param n: An integer 84 | * @return: An integer 85 | */ 86 | int climbStairs(int n) { 87 | if (n < 1) { 88 | return 0; 89 | } 90 | 91 | int ret0 = 1, ret1 = 1, ret2 = 1; 92 | 93 | for (int i = 2; i != n + 1; ++i) { 94 | ret0 = ret1 + ret2; 95 | ret2 = ret1; 96 | ret1 = ret0; 97 | } 98 | 99 | return ret0; 100 | } 101 | }; 102 | ``` 103 | -------------------------------------------------------------------------------- /zh-tw/exhaustive_search/README.md: -------------------------------------------------------------------------------- 1 | # Exhaustive Search - 窮竭搜索 2 | 3 | 窮竭搜索又稱暴力搜索,指代將所有可能性列出來,然後再在其中尋找滿足題目條件的解。常用求解方法和工具有: 4 | 5 | 1. 遞歸函數 6 | 2. 棧 7 | 3. 隊列 8 | 4. 深度優先搜索(DFS, Depth-First Search),又常稱為回溯法 9 | 5. 廣度優先搜索(BFS, Breadth-First Search) 10 | 11 | 1, 2, 3 往往在深搜或者廣搜中體現。 12 | 13 | ## DFS 14 | 15 | DFS 通常從某個狀態開始,根據特定的規則轉移狀態,直至無法轉移(節點為空),然後回退到之前一步狀態,繼續按照指定規則轉移狀態,直至遍曆完所有狀態。 16 | 17 | 回溯法包含了多類問題,模板類似。 18 | 19 | 排列組合模板->搜索問題(是否要排序,哪些情況要跳過) 20 | 21 | 使用回溯法的一般步驟: 22 | 23 | 1. 確定所給問題的解空間:首先應明確定義問題的解空間,解空間中至少包含問題的一個解。 24 | 2. 確定結點的擴展搜索規則 25 | 3. 以深度優先方式搜索解空間,並在搜索過程中用剪枝函數避免無效搜索。 26 | 27 | ### BFS 28 | 29 | BFS 從某個狀態開始,搜索**所有可以到達的狀態**,轉移順序為『初始狀態->只需一次轉移就可到達的所有狀態->只需兩次轉移就可到達的所有狀態->...』,所以對於同一個狀態,BFS 只搜索一次,故時間複雜度為 $$O(states \times transfer\_methods)$$. BFS 通常配合隊列一起使用,搜索時先將狀態加入到隊列中,然後從隊列頂端不斷取出狀態,再把從該狀態可轉移到的狀態中尚未訪問過的部分加入隊列,知道隊列為空或已找到解。因此 BFS 適合用於『由近及遠』的搜索,比較適合用於求解最短路徑、最少操作之類的問題。 30 | 31 | ## Reference 32 | 33 | - 《挑戰程序設計競賽》Chaper 2.1 p26 最基礎的「窮竭搜索」 34 | - [Steven Skiena: Lecture15 - Backtracking](http://7xojrx.com1.z0.glb.clouddn.com/docs/algorithm-exercise/docs/lecture15-backtracking.pdf) 35 | - [全面解析回溯法:算法框架與問題求解 - 五嶽 - 博客園](http://www.cnblogs.com/wuyuegb2312/p/3273337.html) 36 | - [五大常用算法之四:回溯法 - 紅臉書生 - 博客園](http://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741376.html) 37 | - [演算法筆記 - Backtracking](http://www.csie.ntnu.edu.tw/~u91029/Backtracking.html) 38 | -------------------------------------------------------------------------------- /zh-tw/faq/README.md: -------------------------------------------------------------------------------- 1 | # FAQ - Frequently Asked Question 2 | 3 | Some guidelines for contributing and other questions are listed here. 4 | 5 | ## How to Contribute? 6 | 7 | - Access [Guidelines for Contributing](http://algorithm.yuanbin.me/en/faq/guidelines_for_contributing.md) for details. -------------------------------------------------------------------------------- /zh-tw/graph/README.md: -------------------------------------------------------------------------------- 1 | # Graph 2 | 3 | 本章主要總結圖與搜索相關題目。 4 | -------------------------------------------------------------------------------- /zh-tw/integer_array/README.md: -------------------------------------------------------------------------------- 1 | # Integer Array - 整數型陣列 2 | 3 | 本章主要總結與整數型陣列相關的題目。 4 | -------------------------------------------------------------------------------- /zh-tw/integer_array/remove_duplicates_from_sorted_array.md: -------------------------------------------------------------------------------- 1 | # Remove Duplicates from Sorted Array 2 | 3 | ## Question 4 | 5 | - lintcode: [(100) Remove Duplicates from Sorted Array](http://www.lintcode.com/en/problem/remove-duplicates-from-sorted-array/) 6 | 7 | ``` 8 | Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length. 9 | 10 | Do not allocate extra space for another array, you must do this in place with constant memory. 11 | 12 | For example, 13 | Given input array A = [1,1,2], 14 | 15 | Your function should return length = 2, and A is now [1,2]. 16 | 17 | Example 18 | ``` 19 | 20 | ## 題解 21 | 22 | 使用雙指標(下標),一個指標(下標)遍歷vector數組,另一個指標(下標)只取不重複的數置於原vector中。 23 | 24 | ```c++ 25 | class Solution { 26 | public: 27 | /** 28 | * @param A: a list of integers 29 | * @return : return an integer 30 | */ 31 | int removeDuplicates(vector &nums) { 32 | if (nums.empty()) { 33 | return 0; 34 | } 35 | 36 | int size = 0; 37 | for (vector::size_type i = 0; i != nums.size(); ++i) { 38 | if (nums[i] != nums[size]) { 39 | nums[++size] = nums[i]; 40 | } 41 | } 42 | return ++size; 43 | } 44 | }; 45 | ``` 46 | 47 | ### 源碼分析 48 | 49 | 注意最後需要返回的是`++size`或者`size + 1` 50 | 51 | -------------------------------------------------------------------------------- /zh-tw/integer_array/remove_duplicates_from_sorted_array_ii.md: -------------------------------------------------------------------------------- 1 | # Remove Duplicates from Sorted Array II 2 | 3 | ## Question 4 | 5 | - lintcode: [(101) Remove Duplicates from Sorted Array II](http://www.lintcode.com/en/problem/remove-duplicates-from-sorted-array-ii/) 6 | 7 | ``` 8 | Follow up for "Remove Duplicates": 9 | What if duplicates are allowed at most twice? 10 | 11 | For example, 12 | Given sorted array A = [1,1,1,2,2,3], 13 | 14 | Your function should return length = 5, and A is now [1,1,2,2,3]. 15 | Example 16 | ``` 17 | 18 | ## 題解 19 | 20 | 在上題基礎上加了限制條件元素最多可重複出現兩次。因此可以在原題的基礎上添加一變量跟蹤元素重複出現的次數,小於指定值時執行賦值操作。但是需要注意的是重複出現次數`occurence`的初始值(從1開始,而不是0)和reset的時機。 21 | 22 | ### C++ 23 | 24 | ```c++ 25 | class Solution { 26 | public: 27 | /** 28 | * @param A: a list of integers 29 | * @return : return an integer 30 | */ 31 | int removeDuplicates(vector &nums) { 32 | if (nums.size() < 3) { 33 | return nums.size(); 34 | } 35 | 36 | int size = 0; 37 | int occurence = 1; 38 | for (vector::size_type i = 1; i != nums.size(); ++i) { 39 | if (nums[size] != nums[i]) { 40 | nums[++size] = nums[i]; 41 | occurence = 1; 42 | } else if (nums[size] == nums[i]) { 43 | if (occurence++ < 2) { 44 | nums[++size] = nums[i]; 45 | } 46 | } 47 | } 48 | 49 | return ++size; 50 | } 51 | }; 52 | ``` 53 | 54 | ### 源碼分析 55 | 56 | 1. 在數組元素小於3(即為2)時可直接返回vector數組大小。 57 | 2. 初始化`occurence`的值為1,而不是0. 理解起來也方便些。 58 | 3. 初始化下標值`i`從1開始 59 | - `nums[size] != nums[i]`時遞增`size`並賦值,同時重置`occurence`的值為1 60 | - `(nums[size] == nums[i])`時,首先判斷`occurence`的值是否小於2,小於2則先遞增`size`,隨後將`nums[i]`的值賦給`nums[size]`。這裡由於小標`i`從1開始,免去了對`i`為0的特殊情況考慮。 61 | 4. 最後返回`size + 1`,即為`++size` 62 | -------------------------------------------------------------------------------- /zh-tw/integer_array/remove_element.md: -------------------------------------------------------------------------------- 1 | # Remove Element 2 | 3 | ## Question 4 | 5 | - leetcode: [Remove Element | LeetCode OJ](https://leetcode.com/problems/remove-element/) 6 | - lintcode: [(172) Remove Element](http://www.lintcode.com/en/problem/remove-element/) 7 | 8 | ``` 9 | Given an array and a value, remove all occurrences of that value in place and return the new length. 10 | 11 | The order of elements can be changed, and the elements after the new length don't matter. 12 | 13 | Example 14 | Given an array [0,4,4,0,0,2,4,4], value=4 15 | 16 | return 4 and front four elements of the array is [0,0,0,2] 17 | ``` 18 | 19 | ## 題解1 - 使用容器 20 | 21 | 入門題,返回刪除指定元素後的陣列長度,使用容器操作非常簡單。以 lintcode 上給出的參數為例,遍歷容器內元素,若元素值與給定刪除值相等,刪除當前元素並往後繼續遍歷。 22 | C++的vector已經支援了刪除操作,因此可以直接拿來使用。 23 | ### C++ 24 | 25 | ```c++ 26 | class Solution { 27 | public: 28 | /** 29 | *@param A: A list of integers 30 | *@param elem: An integer 31 | *@return: The new length after remove 32 | */ 33 | int removeElement(vector &A, int elem) { 34 | for (vector::iterator iter = A.begin(); iter < A.end(); ++iter) { 35 | if (*iter == elem) { 36 | iter = A.erase(iter); 37 | --iter; 38 | } 39 | } 40 | 41 | return A.size(); 42 | } 43 | }; 44 | 45 | ``` 46 | 47 | ### 源碼分析 48 | 49 | 注意在遍歷容器內元素和指定欲刪除值相等時,需要先自減`--iter`, 因為`for`循環會對`iter`自增,`A.erase()`刪除當前元素值並返回指向下一個元素的指針,一增一減正好平衡。如果改用`while`循環,則需注意訪問陣列時是否越界。 50 | 51 | ### 複雜度分析 52 | 53 | 54 | 由於vector每次erase的複雜度是$$O(n)$$,我們遍歷整個向量,最壞情況下,每個元素都與要刪除的目標元素相等,每次都要刪除元素的複雜度高達$$O(n^2)$$ 55 | 觀察此方法會如此低效的原因,是因為我們一次只刪除一個元素,導致很多沒必要的元素交換移動,如果能夠將要刪除的元素集中處理,則可以大幅增加效率,見題解2。 56 | 57 | ### 題解2 - 兩根指針 58 | 59 | 由於題中明確暗示元素的順序可變,且新長度後的元素不用理會。我們可以使用兩根指針分別往前往後遍歷,頭指針用於指示當前遍歷的元素位置,尾指針則用於在當前元素與欲刪除值相等時替換當前元素,兩根指針相遇時返回尾指針索引——即刪除元素後「新陣列」的長度。 60 | 61 | ### C++ 62 | 63 | ```c++ 64 | class Solution { 65 | public: 66 | int removeElement(int A[], int n, int elem) { 67 | for (int i = 0; i < n; ++i) { 68 | if (A[i] == elem) { 69 | A[i] = A[n - 1]; 70 | --i; 71 | --n; 72 | } 73 | } 74 | 75 | return n; 76 | } 77 | }; 78 | ``` 79 | 80 | ### 源碼分析 81 | 82 | 遍歷當前陣列,`A[i] == elem`時將陣列「尾部(以 n 為長度時的尾部)」元素賦給當前遍歷的元素。同時自減`i`和`n`,原因見題解1的分析。需要注意的是`n`在遍歷過程中可能會變化。 83 | 84 | ### 複雜度分析 85 | 86 | 此方法只遍歷一次陣列,且每個循環的操作至多也不過僅是常數次,因此時間複雜度是$$O(n)$$。 87 | 88 | ## Reference 89 | 90 | - [Remove Element | 九章算法](http://www.jiuzhang.com/solutions/remove-element/) 91 | -------------------------------------------------------------------------------- /zh-tw/linked_list/README.md: -------------------------------------------------------------------------------- 1 | # Linked List - 鏈表 2 | 3 | 本節包含鏈表的一些常用操作,如刪除、插入和合併等。 4 | 5 | 常見錯誤有 遍歷鏈表不向前遞推節點,遍歷鏈表前未保存頭節點,返回鏈表節點指標錯誤。 6 | -------------------------------------------------------------------------------- /zh-tw/linked_list/merge_two_sorted_lists.md: -------------------------------------------------------------------------------- 1 | # Merge Two Sorted Lists 2 | 3 | ## Question 4 | 5 | - lintcode: [(165) Merge Two Sorted Lists](http://www.lintcode.com/en/problem/merge-two-sorted-lists/) 6 | - leetcode: [Merge Two Sorted Lists | LeetCode OJ](https://leetcode.com/problems/merge-two-sorted-lists/) 7 | 8 | ``` 9 | Merge two sorted linked lists and return it as a new list. 10 | The new list should be made by splicing together the nodes of the first two lists. 11 | 12 | Example 13 | Given 1->3->8->11->15->null, 2->null , return 1->2->3->8->11->15->null 14 | ``` 15 | 16 | ## 題解 17 | 18 | 此題為兩個鏈表的合併,合併後的表頭節點不一定,故應聯想到使用`dummy`節點。鏈表節點的插入主要涉及節點`next`指標值的改變,兩個鏈表的合併操作則涉及到兩個節點的`next`值變化,若每次合併一個節點都要改變兩個節點`next`的值且要對`NULL`指標做異常處理,勢必會異常麻煩。嗯,第一次做這題時我就是這麼想的... 下面看看相對較好的思路。 19 | 20 | 首先`dummy`節點還是必須要用到,除了`dummy`節點外還引入一個`lastNode`節點充當下一次合併時的頭節點。在`l1`或者`l2`的某一個節點為空指標`NULL`時,退出`while`循環,並將非空鏈表的頭部鏈接到`lastNode->next`中。 21 | 22 | ### C++ 23 | 24 | ```c++ 25 | /** 26 | * Definition for singly-linked list. 27 | * struct ListNode { 28 | * int val; 29 | * ListNode *next; 30 | * ListNode(int x) : val(x), next(NULL) {} 31 | * }; 32 | */ 33 | class Solution { 34 | public: 35 | ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { 36 | ListNode *dummy = new ListNode(0); 37 | ListNode *lastNode = dummy; 38 | while ((NULL != l1) && (NULL != l2)) { 39 | if (l1->val < l2->val) { 40 | lastNode->next = l1; 41 | l1 = l1->next; 42 | } else { 43 | lastNode->next = l2; 44 | l2 = l2->next; 45 | } 46 | 47 | lastNode = lastNode->next; 48 | } 49 | 50 | // do not forget this line! 51 | lastNode->next = (NULL != l1) ? l1 : l2; 52 | 53 | return dummy->next; 54 | } 55 | }; 56 | ``` 57 | 58 | ### 源碼分析 59 | 60 | 1. 異常處理,包含在`dummy->next`中。 61 | 2. 引入`dummy`和`lastNode`節點,此時`lastNode`指向的節點為`dummy` 62 | 3. 對非空l1,l2循環處理,將l1/l2的較小者鏈接到`lastNode->next`,往後遞推`lastNode` 63 | 4. 最後處理l1/l2中某一鏈表為空退出while循環,將非空鏈表頭鏈接到`lastNode->next` 64 | 5. 返回`dummy->next`,即最終的首指標 65 | 66 | 注意`lastNode`的遞推並不影響`dummy->next`的值,因為`lastNode`和`dummy`是兩個不同的指標變量。 67 | 68 | > **Note** 鏈表的合併為常用操作,務必非常熟練,以上的模板非常精煉,有兩個地方需要記牢。1. 循環結束條件中為條件與操作;2. 最後處理`lastNode->next`指標的值。 69 | 70 | ### 複雜度分析 71 | 72 | 最好情況下,一個鏈表為空,時間複雜度為 $$O(1)$$. 最壞情況下,`lastNode`遍曆兩個鏈表中的每一個節點,時間複雜度為 $$O(l1+l2)$$. 空間複雜度近似為 $$O(1)$$. 73 | 74 | 75 | ## Reference 76 | 77 | - [Merge Two Sorted Lists | 九章算法](http://www.jiuzhang.com/solutions/merge-two-sorted-lists/) 78 | -------------------------------------------------------------------------------- /zh-tw/linked_list/remove_linked_list_elements.md: -------------------------------------------------------------------------------- 1 | # Remove Linked List Elements 2 | 3 | ## Question 4 | 5 | - leetcode: [Remove Linked List Elements | LeetCode OJ](https://leetcode.com/problems/remove-linked-list-elements/) 6 | - lintcode: [(452) Remove Linked List Elements](http://www.lintcode.com/en/problem/remove-linked-list-elements/) 7 | 8 | ### Problem Statement 9 | 10 | Remove all elements from a linked list of integers that have value `val`. 11 | 12 | #### Example 13 | 14 | Given `1->2->3->3->4->5->3`, val = 3, you should return the list as 15 | `1->2->4->5` 16 | 17 | ## 題解 18 | 19 | 刪除鏈表中指定值,找到其前一個節點即可,將 next 指向下一個節點即可。 20 | 21 | ### Python 22 | 23 | ```python 24 | # Definition for singly-linked list. 25 | # class ListNode(object): 26 | # def __init__(self, x): 27 | # self.val = x 28 | # self.next = None 29 | 30 | class Solution(object): 31 | def removeElements(self, head, val): 32 | """ 33 | :type head: ListNode 34 | :type val: int 35 | :rtype: ListNode 36 | """ 37 | dummy = ListNode(0) 38 | dummy.next = head 39 | curr = dummy 40 | while curr.next is not None: 41 | if curr.next.val == val: 42 | curr.next = curr.next.next 43 | else: 44 | curr = curr.next 45 | 46 | return dummy.next 47 | ``` 48 | 49 | ### Java 50 | 51 | ```java 52 | /** 53 | * Definition for singly-linked list. 54 | * public class ListNode { 55 | * int val; 56 | * ListNode next; 57 | * ListNode(int x) { val = x; } 58 | * } 59 | */ 60 | public class Solution { 61 | /** 62 | * @param head a ListNode 63 | * @param val an integer 64 | * @return a ListNode 65 | */ 66 | public ListNode removeElements(ListNode head, int val) { 67 | ListNode dummy = new ListNode(0); 68 | dummy.next = head; 69 | ListNode curr = dummy; 70 | while (curr.next != null) { 71 | if (curr.next.val == val) { 72 | curr.next = curr.next.next; 73 | } else { 74 | curr = curr.next; 75 | } 76 | } 77 | 78 | return dummy.next; 79 | } 80 | } 81 | ``` 82 | 83 | ### 源碼分析 84 | 85 | while 循環中使用`curr.next`較爲方便,if 語句中比較時也使用`curr.next.val`也比較簡潔,如果使用`curr`會比較難處理。 86 | 87 | ### 複雜度分析 88 | 89 | 略 90 | -------------------------------------------------------------------------------- /zh-tw/math_and_bit_manipulation/a_plus_b_problem.md: -------------------------------------------------------------------------------- 1 | # A plus B Problem 2 | 3 | ## Question 4 | 5 | - lintcode: [(1) A + B Problem](http://www.lintcode.com/en/problem/a-b-problem/) 6 | 7 | ``` 8 | Write a function that add two numbers A and B. 9 | You should not use + or any arithmetic operators. 10 | 11 | 12 | Example 13 | Given a=1 and b=2 return 3 14 | 15 | Note 16 | There is no need to read data from standard input stream. 17 | Both parameters are given in function aplusb, 18 | you job is to calculate the sum and return it. 19 | Challenge 20 | Of course you can just return a + b to get accepted. 21 | But Can you challenge not do it like that? 22 | Clarification 23 | Are a and b both 32-bit integers? 24 | Yes. 25 | Can I use bit operation? 26 | 27 | Sure you can. 28 | ``` 29 | 30 | ## 題解 31 | 32 | 不用加減法實現加法,類似數字電路中的全加器 (Full Adder),XOR 求得部分和,OR 求得進位,最後將進位作爲加法器的輸入,典型的遞迴實現思路。 33 | 34 | ### Java 35 | 36 | ```java 37 | class Solution { 38 | /* 39 | * param a: The first integer 40 | * param b: The second integer 41 | * return: The sum of a and b 42 | */ 43 | public int aplusb(int a, int b) { 44 | int result = a ^ b; 45 | int carry = a & b; 46 | carry <<= 1; 47 | if (carry != 0) { 48 | result = aplusb(result, carry); 49 | } 50 | 51 | return result; 52 | } 53 | } 54 | ``` 55 | 56 | ### 源碼分析 57 | 58 | 遞迴步爲進位是否爲0,爲0時返回。 59 | 60 | ### 複雜度分析 61 | 62 | 取決於進位,近似爲 $$O(1)$$. 使用了部分額外變量,空間複雜度爲 $$O(1)$$. 63 | -------------------------------------------------------------------------------- /zh-tw/math_and_bit_manipulation/count_1_in_binary.md: -------------------------------------------------------------------------------- 1 | # Count 1 in Binary 2 | 3 | ## Question 4 | 5 | - lintcode: [(365) Count 1 in Binary](http://www.lintcode.com/en/problem/count-1-in-binary/) 6 | 7 | ``` 8 | Count how many 1 in binary representation of a 32-bit integer. 9 | 10 | Example 11 | Given 32, return 1 12 | 13 | Given 5, return 2 14 | 15 | Given 1023, return 9 16 | 17 | Challenge 18 | If the integer is n bits with m 1 bits. Can you do it in O(m) time? 19 | ``` 20 | 21 | ## 題解 22 | 23 | 題 [O1 Check Power of 2](http://algorithm.yuanbin.me/zh-hans/math_and_bit_manipulation/o1_check_power_of_2.html) 的進階版,`x & (x - 1)` 的含義爲去掉二進制數中1的最後一位,無論 x 是正數還是負數都成立。 24 | 25 | ### C++ 26 | ``` c++ 27 | class Solution { 28 | public: 29 | /** 30 | * @param num: an integer 31 | * @return: an integer, the number of ones in num 32 | */ 33 | int countOnes(int num) { 34 | int count=0; 35 | while (num) { 36 | num &= num-1; 37 | count++; 38 | } 39 | return count; 40 | } 41 | }; 42 | ``` 43 | 44 | ### Java 45 | 46 | ```java 47 | public class Solution { 48 | /** 49 | * @param num: an integer 50 | * @return: an integer, the number of ones in num 51 | */ 52 | public int countOnes(int num) { 53 | int count = 0; 54 | while (num != 0) { 55 | num = num & (num - 1); 56 | count++; 57 | } 58 | 59 | return count; 60 | } 61 | } 62 | ``` 63 | 64 | ### 源碼分析 65 | 66 | 累加計數器即可。 67 | 68 | ### 複雜度分析 69 | 70 | 這種算法依賴於數中1的個數,時間複雜度爲 $$O(m)$$. 空間複雜度 $$O(1)$$. 71 | 72 | ## Reference 73 | 74 | - [Number of 1 bits | LeetCode](http://articles.leetcode.com/2010/09/number-of-1-bits.html) - 評論中有關於不同演算法性能的討論 75 | -------------------------------------------------------------------------------- /zh-tw/math_and_bit_manipulation/plus_one.md: -------------------------------------------------------------------------------- 1 | # Plus One 2 | 3 | ## Question 4 | 5 | - leetcode: [Plus One | LeetCode OJ](https://leetcode.com/problems/plus-one/) 6 | - lintcode: [(407) Plus One](http://www.lintcode.com/en/problem/plus-one/) 7 | 8 | ### Problem Statement 9 | 10 | Given a non-negative number represented as an array of digits, plus one to the number. 11 | 12 | The digits are stored such that the most significant digit is at the head of the list. 13 | 14 | #### Example 15 | 16 | Given [1,2,3] which represents 123, return [1,2,4]. 17 | 18 | Given [9,9,9] which represents 999, return [1,0,0,0]. 19 | 20 | ## 題解 21 | 22 | 又是一道兩個整數按數位相加的題,自後往前累加,處理下進位即可。這道題中是加1,其實還可以擴展至加2,加3等。 23 | 24 | ### Java 25 | 26 | ```java 27 | public class Solution { 28 | /** 29 | * @param digits a number represented as an array of digits 30 | * @return the result 31 | */ 32 | public int[] plusOne(int[] digits) { 33 | return plusDigit(digits, 1); 34 | } 35 | 36 | private int[] plusDigit(int[] digits, int digit) { 37 | if (digits == null || digits.length == 0) return null; 38 | 39 | // regard digit(0~9) as carry 40 | int carry = digit; 41 | int[] result = new int[digits.length]; 42 | for (int i = digits.length - 1; i >= 0; i--) { 43 | result[i] = (digits[i] + carry) % 10; 44 | carry = (digits[i] + carry) / 10; 45 | } 46 | 47 | // carry == 1 48 | if (carry == 1) { 49 | int[] finalResult = new int[result.length + 1]; 50 | finalResult[0] = 1; 51 | return finalResult; 52 | } 53 | 54 | return result; 55 | } 56 | } 57 | ``` 58 | ### C++ 59 | ```C 60 | class Solution { 61 | public: 62 | vector plusOne(vector& digits) { 63 | int carry = 1; 64 | for(int i = digits.size() - 1; i >= 0; i--){ 65 | digits[i] += carry; 66 | carry = digits[i] / 10; 67 | digits[i] %= 10; 68 | } 69 | 70 | if(carry == 1){ 71 | digits.insert(digits.begin(), 1); 72 | } 73 | return digits; 74 | } 75 | }; 76 | ``` 77 | 78 | ### 源碼分析 79 | 80 | 源碼中單獨實現了加任何數(0~9)的私有方法,更為通用,對於末尾第一個數,可以將要加的數當做進位處理,這樣就不必單獨區分最後一位了,十分優雅! 81 | 82 | ### 複雜度分析 83 | 84 | Java 中需要返回數組,而這個數組在處理之前是不知道大小的,故需要對最後一個進位單獨處理。時間複雜度 $$O(n)$$, 空間複雜度在最後一位有進位時惡化為 $$O(n)$$, 當然也可以通過兩次循環使得空間複雜度為 $$O(1)$$. 85 | 86 | ## Reference 87 | 88 | - Soulmachine 的 leetcode 題解,將要加的數當做進位處理就是從這學到的。 89 | -------------------------------------------------------------------------------- /zh-tw/part_i_basics/README.md: -------------------------------------------------------------------------------- 1 | # Part I - Basics 2 | 3 | 第一節主要總結一些基礎知識,如基本的資料結構和基礎演算法。 4 | 5 | 本節主要由以下章節構成。 6 | 7 | ## Reference 8 | 9 | - [VisuAlgo - visualising data structures and algorithms through animation](http://visualgo.net/) - 相當厲害的資料結構和演算法可視化。 10 | - [Data Structure Visualization](http://www.cs.usfca.edu/~galles/visualization/Algorithms.html) - 非常好的動畫示例!!涵蓋了常用的各種資料結構/排序/演算法。 11 | -------------------------------------------------------------------------------- /zh-tw/part_ii_coding/README.md: -------------------------------------------------------------------------------- 1 | # Part II - Coding 2 | 3 | 本節主要總結一些leetcode等題目的實戰經驗。 4 | 5 | 主要有以下章節構成。 6 | -------------------------------------------------------------------------------- /zh-tw/part_iii_contest/README.md: -------------------------------------------------------------------------------- 1 | # Part III - Contest 2 | 3 | 本節主要總結一些如 Google APAC, Microsoft 校招等線上測試的題目。 4 | -------------------------------------------------------------------------------- /zh-tw/problem_misc/README.md: -------------------------------------------------------------------------------- 1 | # Problem Misc 2 | 3 | 本章主要總結暫時不方便歸到其他章節的題目。 4 | -------------------------------------------------------------------------------- /zh-tw/problem_misc/minimum_subarray.md: -------------------------------------------------------------------------------- 1 | # Minimum Subarray 2 | 3 | ## Question 4 | 5 | - lintcode: [(44) Minimum Subarray](http://www.lintcode.com/en/problem/minimum-subarray/) 6 | 7 | ``` 8 | Given an array of integers, find the subarray with smallest sum. 9 | 10 | Return the sum of the subarray. 11 | 12 | Example 13 | For [1, -1, -2, 1], return -3 14 | 15 | Note 16 | The subarray should contain at least one integer. 17 | ``` 18 | 19 | ## 題解 20 | 21 | 題目 [Maximum Subarray](http://algorithm.yuanbin.me/zh-hans/dynamic_programming/maximum_subarray.html) 的變形,使用區間和容易理解和實現。 22 | 23 | ### Java 24 | 25 | ```java 26 | public class Solution { 27 | /** 28 | * @param nums: a list of integers 29 | * @return: A integer indicate the sum of minimum subarray 30 | */ 31 | public int minSubArray(ArrayList nums) { 32 | if (nums == null || nums.isEmpty()) return -1; 33 | 34 | int sum = 0, maxSum = 0, minSub = Integer.MAX_VALUE; 35 | for (int num : nums) { 36 | maxSum = Math.max(maxSum, sum); 37 | sum += num; 38 | minSub = Math.min(minSub, sum - maxSum); 39 | } 40 | 41 | return minSub; 42 | } 43 | } 44 | ``` 45 | 46 | ### 源碼分析 47 | 48 | 略 49 | 50 | ### 複雜度分析 51 | 52 | 略 53 | -------------------------------------------------------------------------------- /zh-tw/problem_misc/reverse_integer.md: -------------------------------------------------------------------------------- 1 | # Reverse Integer 2 | 3 | ## Question 4 | 5 | - leetcode: [Reverse Integer | LeetCode OJ](https://leetcode.com/problems/reverse-integer/) 6 | - lintcode: [(413) Reverse Integer](http://www.lintcode.com/en/problem/reverse-integer/) 7 | 8 | ### Problem Statement 9 | 10 | Reverse digits of an integer. Returns 0 when the reversed integer overflows (signed 32-bit integer). 11 | 12 | #### Example 13 | 14 | Given x = 123, return 321 15 | 16 | Given x = -123, return -321 17 | 18 | ## 題解 19 | 20 | 初看這道題覺得先將其轉換爲字符串然後轉置一下就好了,但是仔細一想這種方法存在兩種缺陷,一是負號需要單獨處理,而是轉置後開頭的0也需要處理。另一種方法是將原數字逐個彈出,然後再將彈出的數字組裝爲新數字,乍看以爲需要用到 stack ,實際上卻是 queue... 所以根本不需要輔助資料結構。關於正負號的處理,我最開始是單獨處理的,後來看其他答案時才發現根本就不用分正負考慮。因爲`-1 / 10 = 0`. 21 | 22 | ### Java 23 | 24 | ```java 25 | public class Solution { 26 | /** 27 | * @param n the integer to be reversed 28 | * @return the reversed integer 29 | */ 30 | public int reverseInteger(int n) { 31 | long result = 0; 32 | while (n != 0) { 33 | result = n % 10 + 10 * result; 34 | n /= 10; 35 | } 36 | 37 | if (result < Integer.MIN_VALUE || result > Integer.MAX_VALUE) { 38 | return 0; 39 | } 40 | return (int)result; 41 | } 42 | } 43 | ``` 44 | 45 | ### 源碼分析 46 | 47 | 注意 lintcode 和 leetcode 的方法名不一樣。使用 long 型保存中間結果,最後判斷是否溢出。 48 | 49 | ## Reference 50 | 51 | - [LeetCode-Sol-Res/ReverseInt.java at master · FreeTymeKiyan/LeetCode-Sol-Res](https://github.com/FreeTymeKiyan/LeetCode-Sol-Res/blob/master/Easy/ReverseInt.java) 52 | -------------------------------------------------------------------------------- /zh-tw/string/README.md: -------------------------------------------------------------------------------- 1 | # String - 字串 2 | 3 | 本章主要介紹字串相關題目。 4 | 5 | > 處理字串操作相關問題時,常見的做法是從字串尾部開始編輯,從後往前逆向操作。這麼做的原因是因為字串的尾部往往有足夠空間,可以直接修改而不用擔心覆蓋字串前面的數據。 6 | 7 | 摘自《程序員面試金典》 8 | -------------------------------------------------------------------------------- /zh-tw/string/compare_strings.md: -------------------------------------------------------------------------------- 1 | # Compare Strings 2 | 3 | ## Question 4 | 5 | - lintcode: [(55) Compare Strings](http://www.lintcode.com/en/problem/compare-strings/) 6 | 7 | ``` 8 | Compare two strings A and B, determine whether A contains all of the characters in B. 9 | 10 | The characters in string A and B are all Upper Case letters. 11 | 12 | Example 13 | For A = "ABCD", B = "ABC", return true. 14 | 15 | For A = "ABCD" B = "AABC", return false. 16 | ``` 17 | 18 | ## 題解 19 | 20 | 題 [Two Strings Are Anagrams | Data Structure and Algorithm](http://algorithm.yuanbin.zh-hans/string/two_strings_are_anagrams.html) 的變形題。題目意思是問B中的所有字元是否都在A中,而不是單個字元。比如B="AABC"包含兩個「A」,而A="ABCD"只包含一個「A」,故返回false. 做題時注意題意,必要時可向面試官確認。 21 | 22 | 既然不是類似 strstr 那樣的匹配,直接使用二重循環就不太合適了。題目中另外給的條件則是A和B都是全大寫單字,理解題意後容易想到的方案就是先遍歷 A 和 B 統計各字元出現的次數,然後比較次數大小即可。嗯,祭出萬能的哈希表。 23 | 24 | ### C++ 25 | 26 | ```c++ 27 | class Solution { 28 | public: 29 | /** 30 | * @param A: A string includes Upper Case letters 31 | * @param B: A string includes Upper Case letter 32 | * @return: if string A contains all of the characters in B return true 33 | * else return false 34 | */ 35 | bool compareStrings(string A, string B) { 36 | if (A.size() < B.size()) { 37 | return false; 38 | } 39 | 40 | const int AlphabetNum = 26; 41 | int letterCount[AlphabetNum] = {0}; 42 | for (int i = 0; i != A.size(); ++i) { 43 | ++letterCount[A[i] - 'A']; 44 | } 45 | for (int i = 0; i != B.size(); ++i) { 46 | --letterCount[B[i] - 'A']; 47 | if (letterCount[B[i] - 'A'] < 0) { 48 | return false; 49 | } 50 | } 51 | 52 | return true; 53 | } 54 | }; 55 | ``` 56 | 57 | ### 源碼解析 58 | 59 | 1. 異常處理,B 的長度大於 A 時必定返回`false`, 包含了空串的特殊情況。 60 | 2. 使用額外的輔助空間,統計各字元的頻次。 61 | 62 | ### 複雜度分析 63 | 64 | 遍歷一次 A 字串,遍歷一次 B 字串,時間複雜度最壞 $$O(2n)$$, 空間複雜度為 $$O(26)$$. 65 | -------------------------------------------------------------------------------- /zh-tw/styles/website.css: -------------------------------------------------------------------------------- 1 | .book .book-summary, .book .book-body { 2 | font-family: "Microsoft JhengHei UI", "Microsoft JhengHei", "PingFang TC", "Lantinghei TC", "Noto Sans CJK TC", "Microsoft YaHei UI", "Microsoft Yahei", "PingFang SC", "Lantinghei SC", "Hiragino Sans GB", "WenQuanYi Micro Hei", "WenQuanYi Zen Hei", "Noto Sans CJK SC", "Helvetica Neue", Helvetica, Arial, sans-serif; 3 | } 4 | -------------------------------------------------------------------------------- /zh-tw/tags.md: -------------------------------------------------------------------------------- 1 | # Tags 2 | --------------------------------------------------------------------------------