├── .editorconfig ├── .github └── workflows │ └── label.yml ├── .vscode ├── c_cpp_properties.json ├── launch.json ├── settings.json └── tasks.json ├── LICENSE ├── README.md ├── basic_data_structure ├── array │ ├── README.md │ ├── array │ ├── array.cpp │ ├── array.png │ ├── array0.png │ ├── array1.png │ ├── array2.png │ ├── array3.png │ └── array4.png ├── data_structure.png ├── graph │ ├── graph.cpp │ └── graph.png ├── hash_table │ ├── hash_table │ ├── hash_table.cpp │ └── hash_table.png ├── heap │ ├── heap │ ├── heap.cpp │ └── heap.png ├── linked_list │ ├── linked_list │ ├── linked_list.cpp │ └── linked_list.png ├── queue │ ├── queue │ ├── queue.cpp │ └── queue.png ├── stack │ ├── stack │ ├── stack.cpp │ ├── stack.gif │ └── stack.png └── tree │ ├── tree.cpp │ └── tree.png ├── basic_sorting ├── bubble_sort ├── bubble_sort.cpp ├── insertion_sort ├── insertion_sort.cpp ├── merge_sort ├── merge_sort.cpp ├── quick_sort ├── quick_sort.cpp ├── selection_sort ├── selection_sort.cpp ├── sorting_bubblesort.gif ├── sorting_insertion.gif ├── sorting_mergesort.gif ├── sorting_quicksort.gif └── sorting_selection.gif ├── books └── LeetCode刷题手册.pdf ├── cache_algorithm ├── least_frequently_used(LFU) ├── least_frequently_used(LFU).cpp ├── least_recently_used(LRU) ├── least_recently_used(LRU).cpp ├── lfu │ ├── LFU_1.PNG │ ├── LFU_10.PNG │ ├── LFU_2.PNG │ ├── LFU_3.PNG │ ├── LFU_4.PNG │ ├── LFU_5.PNG │ ├── LFU_6.PNG │ ├── LFU_7.PNG │ ├── LFU_8.PNG │ └── LFU_9.PNG └── lru │ ├── LRU_1.PNG │ ├── LRU_10.PNG │ ├── LRU_2.PNG │ ├── LRU_3.PNG │ ├── LRU_4.PNG │ ├── LRU_5.PNG │ ├── LRU_6.PNG │ ├── LRU_7.PNG │ ├── LRU_8.PNG │ └── LRU_9.PNG ├── cpp_basics ├── example.txt ├── file_stream ├── file_stream.cpp ├── inheritance ├── inheritance.cpp ├── operator_overload ├── operator_overload.cpp ├── pointer ├── pointer.cpp ├── polymorphism ├── polymorphism.cpp ├── preprocessor ├── preprocessor.cpp ├── reference ├── reference.cpp ├── template ├── template.cpp ├── thread ├── thread.cpp ├── time_limit_test └── time_limit_test.cpp ├── js ├── add_carry.js ├── add_strings.js ├── async_worker.js ├── balancing_parentheses.js ├── binary_search.js ├── binary_search_insert.js ├── compare_version.js ├── compose.js ├── create_weighted_sampling.js ├── decode_string.js ├── deep_clone.js ├── event_emitter.js ├── event_loop.js ├── event_loop_browser.js ├── event_loop_in_browser.png ├── event_loop_in_node.js ├── event_loop_in_node.png ├── event_loop_structure_in_browser.jpg ├── expire_storage.js ├── find_pivot_index.js ├── first_uniq_char.js ├── flat.js ├── generator.js ├── instance_of.js ├── is_anagram.js ├── is_prime_or_not.js ├── list_to_tree.js ├── longest_common_prefix.js ├── max_in_array.js ├── merge_sorted_array.js ├── mobile_334.js ├── move_zeroes.js ├── new.js ├── odd_even_linked_list.js ├── pivot_index.js ├── profit_targets.js ├── promise.js ├── proxy.js ├── quick_sort.js ├── random_string.js ├── reduce_map.js ├── reflect.js ├── request_retry.js ├── reverse_integer.js ├── scheduler.js ├── select_sort.js ├── setTimeout-interval.js ├── shallow_copy.js ├── single_number.js ├── str_str.js ├── string_regexp.js ├── throttle.js ├── tree_to_list.js ├── trim.js ├── unique_array.js ├── valid_palindrome.js └── valid_palindrome_ii.js ├── leetcode ├── array │ ├── evaluate_reverse_polish_notation │ ├── evaluate_reverse_polish_notation.cpp │ ├── find_minimum_in_rotated_sorted │ ├── find_minimum_in_rotated_sorted.cpp │ ├── find_peak_element │ ├── find_peak_element.cpp │ ├── find_pivot_index │ ├── find_pivot_index.cpp │ ├── kth_largest_element │ ├── kth_largest_element.cpp │ ├── kth_largest_element.xmind │ ├── median_of_two_sorted_arrays │ ├── median_of_two_sorted_arrays.cpp │ ├── remove_duplicates_from_sorted_array │ ├── remove_duplicates_from_sorted_array.cpp │ ├── remove_element │ ├── remove_element.cpp │ ├── squares-of-a-sorted-array │ ├── squares-of-a-sorted-array.cpp │ ├── two_sum │ └── two_sum.cpp ├── backtracking │ ├── 回溯算法.png │ └── 回溯算法.xmind ├── binary_search │ ├── binary_search │ ├── binary_search.cpp │ ├── search_in_rotated_sorted_array │ ├── search_in_rotated_sorted_array.cpp │ ├── search_matrix │ ├── search_matrix.cpp │ ├── sqrt │ └── sqrt.cpp ├── binary_search_tree │ ├── binary_search_tree_iterator.cpp │ ├── search_range_in_BST.cpp │ └── validate_binary_search_tree.cpp ├── binary_tree │ ├── balanced_binary_tree.cpp │ ├── binary_tree │ ├── binary_tree.cpp │ ├── binary_tree_level_order_traversal │ ├── binary_tree_level_order_traversal.cpp │ ├── max_depth_binary_tree │ ├── max_depth_binary_tree.cpp │ ├── maximum_depth │ ├── maximum_depth.cpp │ ├── path_sum │ └── path_sum.cpp ├── dynamic_programming │ ├── 0_1_knapsack_problem.cpp │ ├── dp_climb_stairs │ ├── dp_climb_stairs.cpp │ ├── dp_fibonacci_numbers │ ├── dp_fibonacci_numbers.cpp │ ├── dp_min_cost_climb_stairs │ ├── dp_min_cost_climb_stairs.cpp │ ├── integer_break │ ├── integer_break.cpp │ ├── unique_binary_search_trees │ ├── unique_binary_search_trees.cpp │ ├── unique_paths │ ├── unique_paths.cpp │ ├── unique_paths_1 │ ├── unique_paths_1.cpp │ ├── 动态规划.png │ └── 动态规划.xmind ├── greedy_algorithm │ ├── assign_cookies │ ├── assign_cookies.cpp │ ├── best_time_to_buy_and_sell_stock_ii │ ├── best_time_to_buy_and_sell_stock_ii.cpp │ ├── burst_balloons.png │ ├── candy │ ├── candy.cpp │ ├── gas_station │ ├── gas_station.cpp │ ├── jump_game │ ├── jump_game.cpp │ ├── jump_game_ii │ ├── jump_game_ii.cpp │ ├── jump_game_ii.png │ ├── maximi_sum_of_array_after_k_negations │ ├── maximi_sum_of_array_after_k_negations.cpp │ ├── maximum_subarray │ ├── maximum_subarray.cpp │ ├── minimum_number_of_arrows_to_burst_balloons │ ├── minimum_number_of_arrows_to_burst_balloons.cpp │ ├── wiggle_subsequence │ ├── wiggle_subsequence.cpp │ ├── 贪心算法.png │ └── 贪心算法.xmind ├── intersection │ ├── interval_list_intersections │ └── interval_list_intersections.cpp ├── linked_list │ ├── linked_list_cycle.cpp │ ├── merge_sorted_list │ ├── merge_sorted_list.cpp │ ├── partition_list │ ├── partition_list.cpp │ ├── remove_duplicates │ ├── remove_duplicates.cpp │ ├── reorder_list │ ├── reorder_list.cpp │ ├── reverse_linked_list │ ├── reverse_linked_list.cpp │ ├── sort_list │ ├── sort_list.cpp │ ├── two_lists_sum │ └── two_lists_sum.cpp ├── math │ ├── is_prime │ └── is_prime.cpp ├── string │ ├── implement_strstr │ ├── implement_strstr.cpp │ ├── replace_string │ ├── replace_string.cpp │ ├── rotate_string_left │ ├── rotate_string_left.cpp │ ├── valid_parentheses │ └── valid_parentheses.cpp └── two_pointers │ ├── container_with_most_water │ ├── container_with_most_water.cpp │ ├── container_with_most_water.png │ ├── remove_element │ ├── remove_element.cpp │ ├── reverse_string │ ├── reverse_string.cpp │ ├── reverse_words_in_a_string │ └── reverse_words_in_a_string.cpp └── ts ├── game.js ├── game.ts ├── react_fiber.ts ├── type.js └── type.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.github/workflows/label.yml: -------------------------------------------------------------------------------- 1 | # This workflow will triage pull requests and apply a label based on the 2 | # paths that are modified in the pull request. 3 | # 4 | # To use this workflow, you will need to set up a .github/labeler.yml 5 | # file with configuration. For more information, see: 6 | # https://github.com/actions/labeler 7 | 8 | name: Labeler 9 | on: [pull_request] 10 | 11 | jobs: 12 | label: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/labeler@v2 18 | with: 19 | repo-token: "${{ secrets.GH_TOKEN }}" 20 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Mac", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "/usr/include", 8 | "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1" 9 | ], 10 | "defines": [], 11 | "macFrameworkPath": [ 12 | "/System/Library/Frameworks", 13 | "/Library/Frameworks" 14 | ], 15 | "compilerPath": "/usr/bin/clang", 16 | "cStandard": "c11", 17 | "cppStandard": "c++11", 18 | "intelliSenseMode": "clang-x64" 19 | } 20 | ], 21 | "version": 4 22 | } 23 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "clang++ - Build and debug active file", 9 | "type": "cppdbg", 10 | "request": "launch", 11 | "program": "${fileDirname}/${fileBasenameNoExtension}", 12 | "args": [], 13 | "stopAtEntry": false, 14 | "cwd": "${workspaceFolder}", 15 | "environment": [], 16 | "externalConsole": false, 17 | "MIMode": "lldb", 18 | "preLaunchTask": "C/C++: clang++ build active file" 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.wpy": "vue", 4 | "*.cjson": "jsonc", 5 | "*.wxss": "css", 6 | "*.wxs": "javascript", 7 | "*.tsx": "typescriptreact", 8 | "unordered_map": "cpp", 9 | "vector": "cpp", 10 | "ostream": "cpp", 11 | "stack": "cpp", 12 | "iostream": "cpp", 13 | "__config": "cpp", 14 | "iosfwd": "cpp", 15 | "__nullptr": "cpp", 16 | "cstddef": "cpp", 17 | "exception": "cpp", 18 | "initializer_list": "cpp", 19 | "new": "cpp", 20 | "stdexcept": "cpp", 21 | "type_traits": "cpp", 22 | "typeinfo": "cpp", 23 | "algorithm": "cpp", 24 | "string": "cpp", 25 | "deque": "cpp", 26 | "__bit_reference": "cpp", 27 | "__functional_03": "cpp", 28 | "__mutex_base": "cpp", 29 | "__node_handle": "cpp", 30 | "array": "cpp", 31 | "functional": "cpp", 32 | "ios": "cpp", 33 | "istream": "cpp", 34 | "memory": "cpp", 35 | "optional": "cpp", 36 | "sstream": "cpp", 37 | "streambuf": "cpp", 38 | "string_view": "cpp", 39 | "tuple": "cpp", 40 | "__debug": "cpp", 41 | "__errc": "cpp", 42 | "__functional_base": "cpp", 43 | "__hash_table": "cpp", 44 | "__locale": "cpp", 45 | "__split_buffer": "cpp", 46 | "__string": "cpp", 47 | "__threading_support": "cpp", 48 | "__tuple": "cpp", 49 | "atomic": "cpp", 50 | "bit": "cpp", 51 | "bitset": "cpp", 52 | "cctype": "cpp", 53 | "chrono": "cpp", 54 | "cmath": "cpp", 55 | "complex": "cpp", 56 | "cstdarg": "cpp", 57 | "cstdint": "cpp", 58 | "cstdio": "cpp", 59 | "cstdlib": "cpp", 60 | "cstring": "cpp", 61 | "ctime": "cpp", 62 | "cwchar": "cpp", 63 | "cwctype": "cpp", 64 | "iterator": "cpp", 65 | "limits": "cpp", 66 | "locale": "cpp", 67 | "mutex": "cpp", 68 | "queue": "cpp", 69 | "ratio": "cpp", 70 | "system_error": "cpp", 71 | "utility": "cpp", 72 | "map": "cpp", 73 | "__tree": "cpp", 74 | "list": "cpp", 75 | "__bits": "cpp", 76 | "clocale": "cpp", 77 | "fstream": "cpp", 78 | "iomanip": "cpp", 79 | "set": "cpp", 80 | "version": "cpp", 81 | "filesystem": "cpp" 82 | }, 83 | "C_Cpp.errorSquiggles": "Disabled", 84 | "fileheader.LastModifiedBy": "Chacha", 85 | "fileheader.Author": "Chacha", 86 | "editor.formatOnSave": true, 87 | "editor.tabSize": 4, 88 | "cSpell.words": [ 89 | "aabaabaafa", 90 | "binarytree", 91 | "editorconfig", 92 | "Heapify", 93 | "inorder", 94 | "leetcode", 95 | "stoi" 96 | ] 97 | } 98 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "type": "cppbuild", 5 | "label": "C/C++: clang++ build active file", 6 | "command": "/usr/bin/clang++", 7 | "args": [ 8 | "-g", 9 | "-std=c++11", 10 | "${file}", 11 | "-o", 12 | "${fileDirname}/${fileBasenameNoExtension}" 13 | ], 14 | "options": { 15 | "cwd": "${workspaceFolder}" 16 | }, 17 | "problemMatcher": [ 18 | "$gcc" 19 | ], 20 | "group": { 21 | "kind": "build", 22 | "isDefault": true 23 | }, 24 | "detail": "Task generated by Debugger." 25 | } 26 | ], 27 | "version": "2.0.0" 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 CHACHA 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /basic_data_structure/array/README.md: -------------------------------------------------------------------------------- 1 | # 数组理论基础 2 | 3 | 数组是存放在连续内存空间上的相同类型数据的集合。数组可以方便的通过下标索引的方式获取到下标下对应的数据。 4 | 举一个字符数组的例子,如图所示: 5 | ![Array](array0.png) 6 | 7 | 需要两点注意的是: 8 | 9 | - 数组下标都是从 0 开始的 10 | - 数组内存空间的地址是连续的 11 | 12 | **正是因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址** 13 | 14 | 例如删除下标为 3 的元素,需要对下标为 3 的元素后面的所有元素都要做移动操作,如图所示: 15 | 16 | ![Array](array1.png) 17 | 18 | 如果使用 C++的话,要注意 vector 和 array 的区别,vector 的底层实现是 array,严格来讲 vector 是容器,不是数组。 19 | 20 | **数组的元素是不能删的,只能覆盖。** 21 | 22 | 二维数组如图所示: 23 | ![Array](array2.png) 24 | 25 | 不同编程语言的内存管理是不一样的,以 C++为例,在 C++中二维数组是连续分布的。 26 | 可以用下面代码做一个实验,C++测试代码如下: 27 | 28 | ```c++ 29 | void test_arr() { 30 | int array[2][3] = { 31 | {0, 1, 2}, 32 | {3, 4, 5} 33 | }; 34 | std::cout << &array[0][0] << " " << &array[0][1] << " " << &array[0][2] << std::endl; 35 | std::cout << &array[1][0] << " " << &array[1][1] << " " << &array[1][2] << std::endl; 36 | } 37 | 38 | int main() { 39 | test_arr(); 40 | } 41 | 42 | ``` 43 | 44 | 测试地址为: 45 | 46 | ```c++ 47 | 0x7ffee4065820 0x7ffee4065824 0x7ffee4065828 48 | 0x7ffee406582c 0x7ffee4065830 0x7ffee4065834 49 | ``` 50 | 51 | 注意地址为 16 进制,可以看出二维数组地址是连续一条线的。0x7ffee4065820 与 0x7ffee4065824 差了一个 4,就是 4 个字节,因为这是一个 int 型的数组,所以两个相邻数组元素地址差 4 个字节。0x7ffee4065828 与 0x7ffee406582c 也是差了 4 个字节,在 16 进制里 8 + 4 = c,c 就是 12。 52 | 53 | 如图: 54 | 55 | ![Array](array3.png) 56 | 57 | **所以可以看出在 C++中二维数组在地址空间上是连续的。** 58 | 59 | Java 是没有指针的,同时也不对程序员暴露其元素的地址,寻址操作完全交给虚拟机。所以看不到每个元素的地址情况,这里以 Java 为例,测试代码: 60 | 61 | ```Java 62 | public static void test_arr() { 63 | int[][] arr = {{1, 2, 3}, {3, 4, 5}, {6, 7, 8}, {9,9,9}}; 64 | System.out.println(arr[0]); 65 | System.out.println(arr[1]); 66 | System.out.println(arr[2]); 67 | System.out.println(arr[3]); 68 | } 69 | ``` 70 | 71 | 输出的地址为: 72 | 73 | ```Java 74 | [I@7852e922 75 | [I@4e25154f 76 | [I@70dea4e 77 | [I@5c647e05 78 | ``` 79 | 80 | 这里的数值也是 16 进制,这不是真正的地址,而是经过处理过后的数值了,我们也可以看出,二维数组的每一行头结点的地址是没有规则的,更谈不上连续。 81 | 82 | 所以 Java 的二维数组可能是如下排列的方式: 83 | 84 | ![Array](array4.png) 85 | -------------------------------------------------------------------------------- /basic_data_structure/array/array: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/array/array -------------------------------------------------------------------------------- /basic_data_structure/array/array.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2021-03-05 00:04:18 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2021-03-05 00:04:56 6 | */ 7 | 8 | #include 9 | using namespace std; 10 | 11 | int main(int argc, char const *argv[]) 12 | { 13 | int nums[5] = {2, 3, 1, 0, 2}; 14 | 15 | printf("This is an array\n"); 16 | 17 | for (int i = 0; i < 5; i++) 18 | { 19 | cout << nums[i] << ' '; 20 | } 21 | 22 | /* code */ 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /basic_data_structure/array/array.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/array/array.png -------------------------------------------------------------------------------- /basic_data_structure/array/array0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/array/array0.png -------------------------------------------------------------------------------- /basic_data_structure/array/array1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/array/array1.png -------------------------------------------------------------------------------- /basic_data_structure/array/array2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/array/array2.png -------------------------------------------------------------------------------- /basic_data_structure/array/array3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/array/array3.png -------------------------------------------------------------------------------- /basic_data_structure/array/array4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/array/array4.png -------------------------------------------------------------------------------- /basic_data_structure/data_structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/data_structure.png -------------------------------------------------------------------------------- /basic_data_structure/graph/graph.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2021-03-07 22:08:23 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2021-03-07 23:00:37 6 | */ 7 | 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | /** 13 | * 图是一种非线性数据结构,由【节点(定点) vertex】和【边 edge】组成,每条边连接一对定点。根据边的方向有无, 14 | * 图可以分为【有向图】和【无向图】。 15 | * 如 ./graph.png 所示,该无向图的 顶点 和 边 集合分别为: 16 | * 1. 顶点集合:vertices = {1, 2, 3, 4, 5} 17 | * 2. 边集合:edges = {{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 4}, {3, 5}, {4, 5}} 18 | * 19 | * 表示上述图的方法有两种: 20 | * 1. 邻接矩阵:使用数组 vertices 存储顶点,邻接矩阵 edges 存储边;edges[i][j] 代表节点 i+1 和 节点 j+1之间是否有边,有边就是1,否则就是0。 21 | * vertices = [1,2,3,4,5] 22 | * 23 | * ⎡0 1 1 1 1⎤ 24 | * ⎢1 0 0 1 0⎥ 25 | * edges = ⎢1 0 0 0 1⎥ 26 | * ⎢1 1 0 0 1⎥ 27 | * ⎣1 0 1 1 0⎦ 28 | * 29 | */ 30 | 31 | // 代码表示上述数据结构​ 32 | int vetices[5] = {1, 2, 3, 4, 5}; 33 | int edges[5][5] = {{0, 1, 1, 1, 1}, 34 | {1, 0, 0, 1, 0}, 35 | {1, 0, 0, 0, 1}, 36 | {1, 1, 0, 0, 1}, 37 | {1, 0, 1, 1, 0}}; 38 | 39 | /** 40 | * 2. 邻接表:使用数组 vetices 存储顶点,邻接表 edges 存储边。edges 为一个二维容器,第一维 i 代表顶点索引, 41 | * 第二维 edges[i] 存储次顶点对应的边集合;例如 edges[0] = [1, 2, 3, 4] 代表 vertices[0] 的边集合为[1, 2, 3, 4]。 42 | * vertices = [1,2,3,4,5] 43 | * 44 | * ⎡[1 2 3 4]⎤ 45 | * ⎢[0 3] ⎥ 46 | * edges = ⎢[0 4] ⎥ 47 | * ⎢[0 1 4] ⎥ 48 | * ⎣[0 2 3] ⎦ 49 | */ 50 | 51 | // 代码表示上述数据结构​ 52 | int vertices1[5] = {1, 2, 3, 4, 5}; 53 | vector> edges1; 54 | 55 | vector edge_1 = {1, 2, 3, 4}; 56 | vector edge_2 = {0, 3}; 57 | vector edge_3 = {0, 4}; 58 | vector edge_4 = {0, 1, 4}; 59 | vector edge_5 = {0, 2, 3}; 60 | edges1.push_back(edge_1); 61 | edges1.push_back(edge_2); 62 | edges1.push_back(edge_3); 63 | edges1.push_back(edge_4); 64 | edges1.push_back(edge_5); 65 | 66 | /** 67 | * 邻接矩阵 VS 邻接表 : 68 | * 邻接矩阵的大小只与节点数量有关,即 N^2,其中 N 为节点数量。因此,当边数量明显少于节点数量时,使用邻接矩阵存储图会造成较大的内存浪费。 69 | * 因此,邻接矩阵适合存储稠密图(顶点较少、边较多),邻接表适合存储稀疏图(顶点较多、边较少)。 70 | */ 71 | -------------------------------------------------------------------------------- /basic_data_structure/graph/graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/graph/graph.png -------------------------------------------------------------------------------- /basic_data_structure/hash_table/hash_table: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/hash_table/hash_table -------------------------------------------------------------------------------- /basic_data_structure/hash_table/hash_table.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2021-03-07 23:06:51 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2021-03-07 23:06:51 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | /** 15 | * 散列表是一种非线性数据结构,通过利用Hash函数将指定的【键 key】映射至对应的【值 value】,以实现高效的元素查找 16 | */ 17 | 18 | int main() 19 | { 20 | // 散列表例子 21 | unordered_map dic; 22 | 23 | // 添加 key -> value 键值对 24 | dic["小力"] = 10001; 25 | dic["小特"] = 10002; 26 | dic["小扣"] = 10003; 27 | 28 | cout << dic["小力"] << endl; 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /basic_data_structure/hash_table/hash_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/hash_table/hash_table.png -------------------------------------------------------------------------------- /basic_data_structure/heap/heap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/heap/heap -------------------------------------------------------------------------------- /basic_data_structure/heap/heap.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2021-03-03 16:06:05 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-14 00:00:49 6 | */ 7 | 8 | /** 9 | * 堆是一种基于【完全二叉树】的数据结构,可使用数组实现。已堆为原理堆排序算法称为【堆排序】, 10 | * 基于堆实现堆数据结构为【优先队列】。堆分为【大顶堆】和【小顶堆】:任意节点堆值不大于(小于) 11 | * 齐父节点堆值。 12 | * 13 | * 完全二叉树的定义:设二叉树的深度为 k,若二叉树除第 k 层外的其他各层(第 1 层至 k - 1一层)的节点达到最大个数, 14 | * 且处于第 k 层的节点都连续集中在最左边,则称此二叉树为完全二叉树。 15 | * 16 | * 如 ./heap.png 所示,为包含 1, 4, 2, 6, 8 元素的小顶堆。将堆(完全二叉树)中的结点按层编号,即可映射到右边的数组存储形式。 17 | * 18 | */ 19 | 20 | // 通过使用【优先队列】的【压入 push()】和【弹出 pop()】操作,即可完成堆排序,实现代码如下 21 | #include 22 | #include 23 | 24 | using namespace std; 25 | 26 | int main() 27 | { 28 | // 初始化小顶堆 29 | priority_queue, greater> minHeap; 30 | 31 | // 初始化大顶堆 32 | priority_queue maxHeap; 33 | 34 | // 元素入堆 35 | minHeap.push(1); 36 | minHeap.push(4); 37 | minHeap.push(2); 38 | minHeap.push(6); 39 | minHeap.push(8); 40 | 41 | // 元素入堆 42 | maxHeap.push(1); 43 | maxHeap.push(4); 44 | maxHeap.push(2); 45 | maxHeap.push(6); 46 | maxHeap.push(8); 47 | 48 | while (!minHeap.empty()) 49 | { 50 | // 元素出堆(从小到大) 51 | cout << minHeap.top() << " "; 52 | minHeap.pop(); 53 | } 54 | 55 | cout << endl; 56 | 57 | while (!maxHeap.empty()) 58 | { 59 | // 元素出堆(从大到小) 60 | cout << maxHeap.top() << " "; 61 | maxHeap.pop(); 62 | } 63 | 64 | cout << endl; 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /basic_data_structure/heap/heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/heap/heap.png -------------------------------------------------------------------------------- /basic_data_structure/linked_list/linked_list: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/linked_list/linked_list -------------------------------------------------------------------------------- /basic_data_structure/linked_list/linked_list.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2018-12-30 13:12:05 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2021-03-05 10:45:20 6 | */ 7 | 8 | #include 9 | using namespace std; 10 | 11 | /** 12 | * Struct definition for singly-linked list(单向链表结构体声明) 13 | * Source: https://zh.wikipedia.org/wiki/链表 14 | */ 15 | struct ListNodeA 16 | { 17 | int val; // 节点值 18 | ListNodeA *next; // 后继节点引用 19 | 20 | ListNodeA(int x) : val(x), next(NULL) {} 21 | }; 22 | 23 | /** 24 | * Class definition for singly-linked list(单向链表类声明) 25 | */ 26 | class ListNodeB 27 | { 28 | public: 29 | int val; 30 | ListNodeB *next; 31 | 32 | ListNodeB(int val) 33 | { 34 | this->val = val; 35 | this->next = NULL; 36 | } 37 | }; 38 | 39 | /** 40 | * Class definition for doubly-linked list(双向链表类声明) 41 | */ 42 | class DListNode 43 | { 44 | public: 45 | int val; 46 | DListNode *prev, *next; 47 | 48 | DListNode(int val) 49 | { 50 | this->val = val; 51 | this->prev = this->next = NULL; 52 | } 53 | }; 54 | 55 | int main(int argc, char const *argv[]) 56 | { 57 | ListNodeA *node1 = new ListNodeA(4); 58 | ListNodeA *node2 = new ListNodeA(5); 59 | ListNodeA *node3 = new ListNodeA(1); 60 | 61 | cout << node1->val << std::endl; 62 | cout << node1->next << std::endl; 63 | 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /basic_data_structure/linked_list/linked_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/linked_list/linked_list.png -------------------------------------------------------------------------------- /basic_data_structure/queue/queue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/queue/queue -------------------------------------------------------------------------------- /basic_data_structure/queue/queue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/queue/queue.png -------------------------------------------------------------------------------- /basic_data_structure/stack/stack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/stack/stack -------------------------------------------------------------------------------- /basic_data_structure/stack/stack.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/stack/stack.gif -------------------------------------------------------------------------------- /basic_data_structure/stack/stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/stack/stack.png -------------------------------------------------------------------------------- /basic_data_structure/tree/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_data_structure/tree/tree.png -------------------------------------------------------------------------------- /basic_sorting/bubble_sort: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_sorting/bubble_sort -------------------------------------------------------------------------------- /basic_sorting/bubble_sort.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2018-12-13 22:10:30 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-16 21:52:41 6 | */ 7 | 8 | /** 9 | * Bubble Sorting 10 | * Source: https://zh.wikipedia.org/wiki/冒泡排序 11 | * 12 | * Time Complexity: O(n^2) 13 | * Space Complexity: O(1) 14 | * 15 | * 核心:冒泡,持续比较相邻元素,大的挪到后面,因此大的会逐步往后挪,故称之为冒泡。 16 | */ 17 | 18 | #include 19 | using namespace std; 20 | 21 | template //整数或浮点数皆可使用,若要使用类(class)或结构体(struct)时必须重载大于(>)运算符 22 | void bubbleSort(T arr[], int len) 23 | { 24 | int i, j; 25 | 26 | for (i = 0; i < len; i++) 27 | { 28 | 29 | for (j = 0; j < len - 1 - i; j++) 30 | { 31 | 32 | if (arr[j] > arr[j + 1]) 33 | { 34 | swap(arr[j], arr[j + 1]); 35 | } 36 | } 37 | } 38 | } 39 | 40 | int main() 41 | { 42 | int arr[] = {2, 6, 4, 20, 9, 8}; 43 | int len = sizeof(arr) / sizeof(int); 44 | 45 | bubbleSort(arr, len); 46 | 47 | for (int i = 0; i < len; i++) 48 | { 49 | cout << arr[i] << ' '; 50 | } 51 | cout << endl; 52 | } 53 | -------------------------------------------------------------------------------- /basic_sorting/insertion_sort: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_sorting/insertion_sort -------------------------------------------------------------------------------- /basic_sorting/insertion_sort.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2018-12-20 22:10:30 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-16 21:56:20 6 | */ 7 | 8 | #include 9 | using namespace std; 10 | 11 | /** 12 | * Insertion Sorting(插入排序) 13 | * Source: https://zh.wikipedia.org/wiki/插入排序 14 | * 15 | * Time Complexity: O(n^2) 16 | * Space Complexity: O(1) 17 | * 18 | * 核心:通过构建有序序列,对于未排序序列,从后向前扫描(对于单向链表则只能从前往后遍历),找到相应位置并插入。 19 | * 实现上通常使用in-place排序(需用到O(1)的额外空间)。 20 | * 21 | * 排序步骤: 22 | * 1. 从第一个元素开始,该元素可认为已排序 23 | * 2. 取下一个元素,对已排序数组从后往前扫描 24 | * 3. 若从排序数组中取出的元素大于新元素,则移至下一位置 25 | * 4. 重复步骤3,直至找到已排序元素小于或等于新元素的位置 26 | * 5. 插入新元素至该位置 27 | * 6. 重复2~5 28 | * 29 | */ 30 | template //整数或浮点数皆可使用,若要使用类(class)或结构体(struct)时必须重载大于(>)运算符 31 | void insertionSort(T arr[], int len) 32 | { 33 | 34 | for (int i = 1; i < len; i++) 35 | { 36 | int key = arr[i]; 37 | int j = i - 1; 38 | 39 | while (j >= 0 && key < arr[j]) 40 | { 41 | arr[j + 1] = arr[j]; 42 | j--; 43 | } 44 | arr[j + 1] = key; 45 | } 46 | } 47 | 48 | /** 49 | * Shell Sorting(希尔排序) 50 | * Source: https://zh.wikipedia.org/wiki/希尔排序 51 | * 52 | * 核心:基于插入排序,使数组中任意间隔为h的元素都是有序的,即将全部元素分为h个区域使用插入排序。 53 | * 其实现可类似于插入排序但使用不同增量。更高效的原因是它权衡了子数组的规模和有序性。 54 | */ 55 | template 56 | void shellSort(T arr[], int len) 57 | { 58 | int gap, i, j; 59 | T temp; 60 | 61 | for (gap = len >> 1; gap > 0; gap >>= 1) 62 | { 63 | 64 | for (i = gap; i < len; i++) 65 | { 66 | temp = arr[i]; 67 | 68 | for (j = i - gap; j >= 0 && arr[j] > temp; j -= gap) 69 | { 70 | arr[j + gap] = arr[j]; 71 | } 72 | arr[j + gap] = temp; 73 | } 74 | } 75 | } 76 | 77 | int main() 78 | { 79 | int arr[] = {2, 6, 4, 20, 9, 8}; 80 | int len = sizeof(arr) / sizeof(int); 81 | 82 | // insertionSort(arr, len); 83 | shellSort(arr, len); 84 | 85 | for (int i = 0; i < len; i++) 86 | { 87 | cout << arr[i] << ' '; 88 | } 89 | cout << endl; 90 | } 91 | -------------------------------------------------------------------------------- /basic_sorting/merge_sort: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_sorting/merge_sort -------------------------------------------------------------------------------- /basic_sorting/merge_sort.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2018-12-25 22:53:20 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2021-03-09 13:49:12 6 | */ 7 | 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | /** 13 | * 归并排序的核心:将两个有序对数组归并成一个更大对有序数组。 14 | * 通常做法为递归排序,并将两个不同的有序数组归并到第三个数组中。 15 | * 16 | * Time Complexity: O(n log n) 17 | * Space Complexity: O(n) 18 | * 19 | * Source: 20 | * https://zh.wikipedia.org/wiki/归并排序 21 | * https://algs4.cs.princeton.edu/22mergesort/ 22 | */ 23 | 24 | // 合并数组操作 25 | template 26 | 27 | void merge(T nums[], int left, int mid, int right, T temp[]) 28 | { 29 | int i = left; // 左序列起始位置 30 | int j = mid + 1; // 右序列起始位置 31 | int t = 0; // 临时数组位置 32 | 33 | while (i <= mid && j <= right) 34 | { 35 | if (nums[i] <= nums[j]) // 如果左序列的值小于或等于右序列的值,就将左序列的那个值复制到临时数组temp里面,反之亦然。 36 | { 37 | temp[t++] = nums[i++]; 38 | } 39 | else 40 | { 41 | temp[t++] = nums[j++]; 42 | } 43 | } 44 | 45 | while (i <= mid) // 将左边剩余元素填充进temp中 46 | { 47 | temp[t++] = nums[i++]; 48 | } 49 | 50 | while (j <= right) // 将右边剩余元素填充进temp中 51 | { 52 | temp[t++] = nums[j++]; 53 | } 54 | 55 | t = 0; 56 | 57 | while (left <= right) // 将temp中的元素全部拷贝到原数组中 58 | { 59 | nums[left++] = temp[t++]; 60 | } 61 | }; 62 | 63 | // 排序操作 64 | template 65 | 66 | void sort(T nums[], int left, int right, T temp[]) 67 | { 68 | if (left >= right) 69 | { 70 | return; 71 | } 72 | 73 | int mid = left + (right - left) / 2; 74 | 75 | sort(nums, left, mid, temp); // 左边归并排序,使得子序列有序 76 | sort(nums, mid + 1, right, temp); // 右边归并排序,使得子序列有序 77 | merge(nums, left, mid, right, temp); // 将两个有序子数组合并操作 78 | }; 79 | 80 | // 归并排序 81 | template 82 | 83 | void mergeSort(T nums[], int len) 84 | { 85 | int temp[len]; // 在排序前,先创建好一个长度等于原数组的临时数组,避免递归中频繁开辟空间 86 | sort(nums, 0, len - 1, temp); 87 | }; 88 | 89 | int main() 90 | { 91 | int nums[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; 92 | int len = sizeof(nums) / sizeof(int); 93 | 94 | mergeSort(nums, len); 95 | 96 | for (int i = 0; i < len; i++) 97 | { 98 | printf("%d ", nums[i]); 99 | } 100 | 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /basic_sorting/quick_sort: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_sorting/quick_sort -------------------------------------------------------------------------------- /basic_sorting/selection_sort: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_sorting/selection_sort -------------------------------------------------------------------------------- /basic_sorting/selection_sort.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2018-12-20 22:00:30 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-08 10:52:28 6 | */ 7 | 8 | /** 9 | * Selection Sorting 10 | * Source: https://zh.wikipedia.org/wiki/选择排序 11 | * 12 | * 核心:不断地选择剩余元素中的最小者。 13 | * 14 | * 1. 找到数组中最小元素并将其和数组第一个元素交换位置。 15 | * 2. 在剩下的元素中找到最小元素并将其与数组第二个元素交还,直至整个数组排序。 16 | * 17 | * 性质 18 | * 1. 比较次数 = (n - 1) + (n - 2) + (n - 3) + ... + 2 + 1 ≈ n^2/2 19 | * 2. 交换次数 = N 20 | * 3. 运行时间与输入无关 21 | * 4. 数据移动最少 22 | */ 23 | 24 | #include 25 | #include 26 | using namespace std; 27 | 28 | template // 整数或浮点数皆可使用,若要使用类(class)或结构体(struct)时必须重载大于(>)运算符 29 | void selectionSort(vector &arr) 30 | { 31 | int len = arr.size(); 32 | 33 | for (int i = 0; i < len - 1; i++) 34 | { 35 | int min = i; 36 | 37 | for (int j = i + 1; j < len; j++) 38 | { 39 | if (arr[j] < arr[min]) 40 | { 41 | min = j; 42 | } 43 | } 44 | swap(arr[i], arr[min]); 45 | } 46 | } 47 | 48 | int main() 49 | { 50 | int arr[] = {2, 6, 4, 20, 9, 8}; 51 | vector nums(arr, arr + sizeof(arr) / sizeof(int)); 52 | 53 | selectionSort(nums); 54 | 55 | for (int i = 0; i < nums.size(); i++) 56 | { 57 | cout << nums[i] << ' '; 58 | } 59 | cout << endl; 60 | } 61 | -------------------------------------------------------------------------------- /basic_sorting/sorting_bubblesort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_sorting/sorting_bubblesort.gif -------------------------------------------------------------------------------- /basic_sorting/sorting_insertion.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_sorting/sorting_insertion.gif -------------------------------------------------------------------------------- /basic_sorting/sorting_mergesort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_sorting/sorting_mergesort.gif -------------------------------------------------------------------------------- /basic_sorting/sorting_quicksort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_sorting/sorting_quicksort.gif -------------------------------------------------------------------------------- /basic_sorting/sorting_selection.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/basic_sorting/sorting_selection.gif -------------------------------------------------------------------------------- /books/LeetCode刷题手册.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/books/LeetCode刷题手册.pdf -------------------------------------------------------------------------------- /cache_algorithm/least_frequently_used(LFU): -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/least_frequently_used(LFU) -------------------------------------------------------------------------------- /cache_algorithm/least_recently_used(LRU): -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/least_recently_used(LRU) -------------------------------------------------------------------------------- /cache_algorithm/lfu/LFU_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lfu/LFU_1.PNG -------------------------------------------------------------------------------- /cache_algorithm/lfu/LFU_10.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lfu/LFU_10.PNG -------------------------------------------------------------------------------- /cache_algorithm/lfu/LFU_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lfu/LFU_2.PNG -------------------------------------------------------------------------------- /cache_algorithm/lfu/LFU_3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lfu/LFU_3.PNG -------------------------------------------------------------------------------- /cache_algorithm/lfu/LFU_4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lfu/LFU_4.PNG -------------------------------------------------------------------------------- /cache_algorithm/lfu/LFU_5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lfu/LFU_5.PNG -------------------------------------------------------------------------------- /cache_algorithm/lfu/LFU_6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lfu/LFU_6.PNG -------------------------------------------------------------------------------- /cache_algorithm/lfu/LFU_7.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lfu/LFU_7.PNG -------------------------------------------------------------------------------- /cache_algorithm/lfu/LFU_8.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lfu/LFU_8.PNG -------------------------------------------------------------------------------- /cache_algorithm/lfu/LFU_9.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lfu/LFU_9.PNG -------------------------------------------------------------------------------- /cache_algorithm/lru/LRU_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lru/LRU_1.PNG -------------------------------------------------------------------------------- /cache_algorithm/lru/LRU_10.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lru/LRU_10.PNG -------------------------------------------------------------------------------- /cache_algorithm/lru/LRU_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lru/LRU_2.PNG -------------------------------------------------------------------------------- /cache_algorithm/lru/LRU_3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lru/LRU_3.PNG -------------------------------------------------------------------------------- /cache_algorithm/lru/LRU_4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lru/LRU_4.PNG -------------------------------------------------------------------------------- /cache_algorithm/lru/LRU_5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lru/LRU_5.PNG -------------------------------------------------------------------------------- /cache_algorithm/lru/LRU_6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lru/LRU_6.PNG -------------------------------------------------------------------------------- /cache_algorithm/lru/LRU_7.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lru/LRU_7.PNG -------------------------------------------------------------------------------- /cache_algorithm/lru/LRU_8.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lru/LRU_8.PNG -------------------------------------------------------------------------------- /cache_algorithm/lru/LRU_9.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cache_algorithm/lru/LRU_9.PNG -------------------------------------------------------------------------------- /cpp_basics/example.txt: -------------------------------------------------------------------------------- 1 | name=Chacha 2 | age=28 3 | -------------------------------------------------------------------------------- /cpp_basics/file_stream: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cpp_basics/file_stream -------------------------------------------------------------------------------- /cpp_basics/file_stream.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-02-28 10:27:17 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-02-28 15:03:56 6 | */ 7 | 8 | /** 9 | * 来源: https://www.runoob.com/cplusplus/cpp-files-streams.html 10 | * 11 | * C++ 文件和流 12 | * iostream 标准库,它提供了 cin 和 cout 方法分别用于从标准输入读取流和向标准输出写入流。 13 | * 14 | * C++ 中另一个标准库 fstream,它定义了三个新的数据类型: 15 | * 1. ofstream, 该数据类型表示输出文件流,用于创建文件并向文件写入信息。 16 | * 2. ifstream, 该数据类型表示输入文件流,用于从文件读取信息。 17 | * 3. fstream, 该数据类型通常表示文件流,且同时具有ofstream 和 ifstream两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。 18 | * 19 | * 要在 C++ 中进行文件处理,必须在 C++ 源代码文件中包含头文件 。 20 | * 21 | * 打开文件 22 | * 在从文件读取信息或者向文件写入信息之前,必须先打开文件。ofstream 和 fstream 对象都可以用来打开文件进行写操作, 23 | * 如果只需要打开文件进行读操作,则使用 ifstream 对象。 24 | * 下面是open() 函数标准语法,open()函数是fstream、ifstream 和 ofstream对象的一个成员。 25 | * void open(const char* filename, ios::openmode mode); 26 | * 在这里,open() 成员函数的第一参数指定要打开的文件的名称和位置,第二个参数定义文件被打开的模式。 27 | * 28 | * 模式标志 29 | * 1. ios::app, 追加模式。所有写入都追加到文件末尾 30 | * 2. ios::ate, 文件打开后定位到文件末尾。 31 | * 3. ios::in, 打开文件用与读取。 32 | * 4. ios::out, 打开文件用于写入。 33 | * 5. ios::trunc, 如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为0。 34 | * 35 | * 可以把以上两种或两种以上的模式结合使用。例如,如果想要以写入模式打开文件,并希望截断文件,以防文件已存在,那么可以使用下面的语法: 36 | * ofstream outfile; 37 | * outfile.open("file.dat", ios::out | ios::trunc); 38 | * 39 | * 类似地,如果想要打开一个文件用于读写,可以使用下面的语法: 40 | * ifstream afile; 41 | * afile.open('file.dat', ios::out | ios::in); 42 | * 43 | * 关闭文件 44 | * 当 C++ 程序终止时,它会自动关闭刷新所有流,释放所有分配的内存,并关闭所有打开的文件。但程序员应该养成一个好习惯,在程序终止前关闭所有打开的文件。 45 | * 下面是 close() 函数的标准语法,close() 函数是 fstream、ifstream 和 ofstream 对象的一个成员。 46 | * void close(); 47 | * 48 | * 写入文件 49 | * 在 C++ 编程中,我们使用流插入运算符 (<<) 向文件写入信息,就像使用该运算符输出信息到屏幕上一样。 50 | * 唯一不同的是,在这里使用的是 ofstream 和 fstream 对象,而不是 cout 对象。 51 | * 52 | * 读取文件 53 | * 在 C++ 编程中,我们使用流提取运算符( >> )从文件读取信息,就像使用该运算符从键盘输入信息一样。 54 | * 唯一不同的是,在这里您使用的是 ifstream 或 fstream 对象,而不是 cin 对象。 55 | * 56 | */ 57 | 58 | // 读取&写入实例 59 | 60 | #include 61 | #include 62 | 63 | using namespace std; 64 | 65 | int main(int argc, char const *argv[]) 66 | { 67 | char data[100]; 68 | 69 | // 以写模式打开文件 70 | ofstream outfile; 71 | outfile.open("./example.txt"); 72 | 73 | cout << "写入文件" << endl; 74 | cout << "输入你的名字: "; 75 | cin.getline(data, 100); 76 | 77 | // 向文件写入用户输入的数据 78 | outfile << "name=" << data << endl; 79 | 80 | cout << "输入你的年龄: "; 81 | cin >> data; 82 | cin.ignore(); 83 | 84 | // 再次向文件写入用户输入的数据 85 | outfile << "age=" << data << endl; 86 | 87 | // 关闭打开的文件 88 | outfile.close(); 89 | 90 | // 以读模式打开文件 91 | ifstream infile; 92 | infile.open("./example.txt"); 93 | 94 | cout << "从文件中读取内容" << endl; 95 | infile >> data; 96 | 97 | // 在屏幕上写入数据 98 | cout << data << endl; 99 | 100 | // 再次从文件读取数据,并显示它 101 | infile >> data; 102 | cout << data << endl; 103 | 104 | // 关闭打开的文件 105 | infile.close(); 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /cpp_basics/inheritance: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cpp_basics/inheritance -------------------------------------------------------------------------------- /cpp_basics/operator_overload: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cpp_basics/operator_overload -------------------------------------------------------------------------------- /cpp_basics/pointer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cpp_basics/pointer -------------------------------------------------------------------------------- /cpp_basics/pointer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-02-24 14:28:15 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-02-25 14:38:54 6 | */ 7 | 8 | /** 9 | * 来源:https://www.runoob.com/cplusplus/cpp-pointers.html 10 | * 11 | * 什么是指针? 12 | * 指针是一个变量,其值为另一个变量地址,即内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前, 13 | * 对其进行声明。指针变量的一般形式为: 14 | * type *var-name; 15 | * 16 | * type 是指针的基类型,它必须是一个有效的 C++ 数据类型,var-name 是指针变量的名称。 17 | * 用来声明指针的星号 * 与乘法中使用的星号是相同的。但是,在这个语句中,星号是用来指定一个变量是指针。 18 | * 以下是有效的指针声明: 19 | * int *ip; // 一个整型的指针 20 | * double *dp; // 一个 double 型的指针 21 | * float *fp; // 一个浮点型的指针 22 | * char *ch; // 一个字符型的指针 23 | * 24 | * 所有指针的值的实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的, 25 | * 都是一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。 26 | * 27 | * Null指针 28 | * 在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。 29 | * NULL 指针是一个定义在标准库中的值为零的常量。 30 | * 在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而,内存地址 0 有特别重要的意义, 31 | * 它表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。 32 | * 33 | * 常量指针和指向常量的指针的区别: 34 | * 1. const char* str: 将 str 声明为指向 const char 的指针。这意味着这个指针指向的数据是不变的,可以修改指针,但任何修改数据的尝试都会引发编译错误。 35 | * a. str++; 有效的,修改指针,而不是指向的数据。 36 | * b. *str = 'a'; 无效的,尝试修改指向的数据。 37 | * 2. char* const str: 将 str 声明为指向 char 的 const 指针。这意味着这个指针是不变的,但指向的数据不是。指针无法修改,但我们可以使用指针修改数据。 38 | * a. str++; 无效的,尝试修改常量指针变量 39 | * b. *str = 'a'; 有效的,尝试修改指向的数据。在我们的例子中,这不会导致编译错误,但会导致运行时错误,因为字符串很可能会进入 40 | * 已编译二进制文件的只读部分。如果我们动态分配内存,这个语句就有意义,例如:char* const str = new char[5]; 41 | * 3. const char* const str: 将 str 声明为指向 const char 的 const 指针。在这种情况下,我们既不能修改指针,也不能修改指向的数据。 42 | * a. str++; 无效的,尝试修改常量指针变量 43 | * b. *str = 'a'; 无效的,尝试修改指向的常量数据 44 | * 45 | * 46 | */ 47 | 48 | // C++中使用指针 49 | #include 50 | #include 51 | 52 | using namespace std; 53 | 54 | // 传递指针给函数 55 | // 在写函数时应习惯性的先声明函数,然后定义函数 56 | void getSeconds(unsigned long *ptr); 57 | 58 | void getSeconds(unsigned long *ptr) 59 | { 60 | *ptr = time(NULL); 61 | return; 62 | } 63 | 64 | int main(int argc, char const *argv[]) 65 | { 66 | int var = 20; // 实际变量声明 67 | int *ip = NULL; // 指针变量声明 68 | unsigned long sec; 69 | 70 | cout << "指针 ip 的值是 " << ip << endl; // 输出 0x0 71 | 72 | ip = &var; // 在指针变量中存储 var 变量的地址 73 | 74 | cout << "变量 var 的地址: "; 75 | cout << &var << endl; 76 | 77 | cout << "变量 var 的值: "; 78 | cout << var << endl; 79 | 80 | cout << "指针变量中存储的地址: "; 81 | cout << ip << endl; 82 | 83 | cout << "访问指针变量中存储的值: "; 84 | cout << *ip << endl; 85 | 86 | getSeconds(&sec); 87 | 88 | cout << "秒数: " << sec << endl; 89 | 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /cpp_basics/polymorphism: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cpp_basics/polymorphism -------------------------------------------------------------------------------- /cpp_basics/preprocessor: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cpp_basics/preprocessor -------------------------------------------------------------------------------- /cpp_basics/preprocessor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-02-28 16:35:56 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-02-28 17:23:35 6 | */ 7 | 8 | /** 9 | * 来源:https://www.runoob.com/cplusplus/cpp-preprocessor.html 10 | * 11 | * C++ 预处理器 12 | * 预处理器是一些指令,指示编译器在实际编译之前所需完成的预处理。所有的预处理器指令都是以井号(#)开头, 13 | * 只有空格字符可以出现在预处理指令之前。预处理指令不是 C++ 语句,所以它们不会以分号(;)结尾。 14 | * 15 | * C++ 提供了下表所示的一些预定义宏: 16 | * 1. __LINE__,这会在程序编译时包含当前行号。 17 | * 2. __FILE__,这会在程序编译时包含当前文件名。 18 | * 3. __DATE__,会包含一个形式为 month/day/year 的字符串,它表示把源文件转换为目标代码的日期。 19 | * 4. __TIME__,会包含一个形式为 hour:minute:second 的字符串,它表示程序被编译的时间。 20 | * 21 | */ 22 | 23 | #include 24 | 25 | using namespace std; 26 | 27 | /** 28 | * #define 预处理 29 | * 30 | * #define 预处理指令用于创建符号常量。该符号常量通常称为宏,指令的一般形式是: 31 | * #define macro-name replacement-text 32 | * 33 | * 当这一行代码出现在一个文件中时,在该文件中后续出现的所有宏都将会在程序编译之前被替换为 replacement-text。 34 | */ 35 | #define PI 3.14159 36 | 37 | /** 38 | * 参数宏 39 | * 40 | * 可以使用 #define 来定义一个带有参数的宏,如下所示: 41 | */ 42 | #define MIN(a, b) (a < b ? a : b) 43 | 44 | /** 45 | * 条件编译 46 | * 47 | * 有几个指令可以用来有选择地对部分程序源代码进行编译。这个过程被称为条件编译。 48 | * 条件预处理器的结构与 if 选择结构很像。 49 | * 50 | * 您可以只在调试时进行编译,调试开关可以使用一个宏来实现,如下所示: 51 | */ 52 | #ifdef DEBUG 53 | cout << "Debug code" << endl; 54 | #endif // DEBUG 55 | 56 | int main(int argc, char const *argv[]) 57 | { 58 | cout << "PI: " << PI << endl; 59 | 60 | int a = 10; 61 | int b = 20; 62 | 63 | cout << "较小的值为: " << MIN(a, b) << endl; 64 | 65 | cout << "__LINE__ : " << __LINE__ << endl; 66 | cout << "__FILE__ : " << __FILE__ << endl; 67 | cout << "__DATE__ : " << __DATE__ << endl; 68 | cout << "__TIME__ : " << __TIME__ << endl; 69 | 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /cpp_basics/reference: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cpp_basics/reference -------------------------------------------------------------------------------- /cpp_basics/reference.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-02-24 15:41:15 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-02-24 16:14:03 6 | */ 7 | 8 | /** 9 | * 来源: https://www.runoob.com/cplusplus/cpp-references.html 10 | * 11 | * C++ 引用 12 | * 引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。 13 | * 14 | * C++ 引用 vs 指针 15 | * 引用和指针三个主要的不同: 16 | * 1. 不存在空引用。引用必须连接到一块合法的内存。 17 | * 2. 一旦引用被初始化为一个对象,就不能被指向到另一个对象,指针可以在任何时候指向到另一个对象。 18 | * 3. 引用必须在创建时被初始化。指针可以在任何时候被初始化。 19 | * 20 | * 把引用作为返回值 21 | * 当返回一个引用时,要注意被引用的对象不能超出作用域。所以返回一个对局部变量的引用是不合法的,但是,可以返回一个对静态变量的引用。 22 | * 23 | */ 24 | 25 | // C++ 引用的使用 26 | #include 27 | 28 | using namespace std; 29 | 30 | int &func() 31 | { 32 | int q; 33 | //! return q; // 在编译时发生错误 34 | static int x; 35 | return x; // 安全,x 在函数作用域外依然是有效的 36 | } 37 | 38 | int main(int argc, char const *argv[]) 39 | { 40 | // 声明简单的变量 41 | int i; 42 | double d; 43 | 44 | // 声明引用变量 45 | int &r = i; // r 是一个初始化为 i 的 int 型引用 46 | double &s = d; // s 是一个初始化为 d 的 double 型引用 47 | 48 | i = 5; 49 | 50 | cout << "i 的值: " << i << endl; 51 | cout << "i 的引用 r 的值: " << r << endl; 52 | 53 | d = 9.9; 54 | 55 | cout << "d 的值: " << d << endl; 56 | cout << "d 的引用 s 的值: " << s << endl; 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /cpp_basics/template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cpp_basics/template -------------------------------------------------------------------------------- /cpp_basics/template.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-02-28 15:03:35 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-02-28 17:51:16 6 | */ 7 | 8 | /** 9 | * 来源:https://www.runoob.com/cplusplus/cpp-templates.html 10 | * 11 | * C++模板 12 | * 模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。 13 | * 模板是创建范型类的蓝图或公式。库容器,比如迭代器和算法,都是范型编程的例子,它们都使用了模板的概念。 14 | * 每个容器都有一个单一的定义,比如 向量,我们可以定义许多不同类型的向量,比如 vector 或 vector 。 15 | * 可以使用模板来定义函数和类,接下来让我们一起来看看如何使用。 16 | * 17 | * 函数模板 18 | * 模板函数定义的一般形式如下所示: 19 | * template ret-type func-name(parameter list) 20 | * { 21 | * // 函数主体 22 | * } 23 | * 在这里,type 是函数所使用的数据类型的占位符名称。这个名称可以在函数定义中使用。 24 | * 25 | * 类模板 26 | * 正如我们定义函数模板一样,我们也可以定义类模板。泛型类声明的一般形式如下所示: 27 | * template class class-name 28 | * { 29 | * } 30 | * 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | using namespace std; 40 | 41 | // 函数模板实例,返回两个数中的最大值: 42 | template 43 | inline T const &Max(T const &a, T const &b) 44 | { 45 | return a < b ? b : a; 46 | } 47 | 48 | // 类模板实例 49 | template 50 | class Stack 51 | { 52 | private: 53 | vector elems; 54 | 55 | public: 56 | void push(T const &); // 入栈 57 | void pop(); // 出栈 58 | T top() const; // 返回栈顶元素 59 | 60 | bool empty() const 61 | { // 如果为空则返回真 62 | return elems.empty(); 63 | } 64 | }; 65 | 66 | template 67 | void Stack::push(T const &elem) 68 | { 69 | elems.push_back(elem); 70 | } 71 | 72 | template 73 | void Stack::pop() 74 | { 75 | if (elems.empty()) 76 | { 77 | throw out_of_range("Stack<>::pop(): empty stack"); 78 | } 79 | 80 | elems.pop_back(); 81 | } 82 | 83 | template 84 | T Stack::top() const 85 | { 86 | if (elems.empty()) 87 | { 88 | throw out_of_range("Stack<>::top(): empty stack"); 89 | } 90 | 91 | return elems.back(); 92 | } 93 | 94 | int main(int argc, char const *argv[]) 95 | { 96 | try 97 | { 98 | // 模板函数调用 99 | int a = 1; 100 | int b = 2; 101 | cout << "Max(a, b): " << Max(a, b) << endl; 102 | 103 | double a1 = 1.1; 104 | double b1 = 2.2; 105 | cout << "Max(a1, b1): " << Max(a1, b1) << endl; 106 | 107 | string a2 = "Hello"; 108 | string b2 = "World"; 109 | cout << "Max(a2, b2): " << Max(a2, b2) << endl; 110 | 111 | // 模板类调用 112 | Stack s; 113 | 114 | s.push(1); 115 | s.push(2); 116 | s.push(3); 117 | 118 | cout << "栈顶元素: " << s.top() << endl; 119 | 120 | s.pop(); 121 | cout << "栈顶元素: " << s.top() << endl; 122 | } 123 | catch (const exception &e) 124 | { 125 | cerr << "Exception: " << e.what() << endl; 126 | } 127 | 128 | return 0; 129 | } 130 | -------------------------------------------------------------------------------- /cpp_basics/thread: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cpp_basics/thread -------------------------------------------------------------------------------- /cpp_basics/time_limit_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/cpp_basics/time_limit_test -------------------------------------------------------------------------------- /cpp_basics/time_limit_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-03 10:58:29 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-03 11:13:36 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | using namespace chrono; 13 | 14 | // O(n) 15 | void function1(long long n) 16 | { 17 | long long k = 0; 18 | for (long long i = 0; i < n; i++) 19 | { 20 | k++; 21 | } 22 | } 23 | 24 | // O(n^2) 25 | void function2(long long n) 26 | { 27 | long long k = 0; 28 | for (long long i = 0; i < n; i++) 29 | { 30 | for (long j = 0; j < n; j++) 31 | { 32 | k++; 33 | } 34 | } 35 | } 36 | // O(n*logn) 37 | void function3(long long n) 38 | { 39 | long long k = 0; 40 | for (long long i = 0; i < n; i++) 41 | { 42 | for (long long j = 1; j < n; j = j * 2) 43 | { // 注意这里j=1 44 | k++; 45 | } 46 | } 47 | } 48 | int main() 49 | { 50 | long long n; // 数据规模 51 | 52 | while (1) 53 | { 54 | cout << "输入n:"; 55 | cin >> n; 56 | 57 | milliseconds start_time = duration_cast( 58 | system_clock::now().time_since_epoch()); 59 | 60 | // function1(n); 61 | function2(n); 62 | // function3(n); 63 | 64 | milliseconds end_time = duration_cast( 65 | system_clock::now().time_since_epoch()); 66 | cout << "耗时:" << milliseconds(end_time).count() - milliseconds(start_time).count() 67 | << " ms" << endl; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /js/add_carry.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-21 17:23:19 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-29 20:36:28 6 | */ 7 | 8 | /** 9 | * 维基百科:https://zh.wikipedia.org/wiki/柯里化 10 | * 11 | * 什么是函数柯里化(curry)? 12 | * 函数柯里化(curry)是函数式编程里面的概念。是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数, 13 | * 并且返回接受余下的参数而且返回结果的新函数的技术。 14 | * 柯里化其实是一种函数的转换,它是指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c)。 15 | * 柯里化不会调用函数,它只是对函数进行转换。 16 | * 17 | * 例如: 18 | * const foo = (a) => (b) => a*a + b*b; 19 | * 20 | * 这样调用上述函数:(foo(3))(4),或直接foo(3)(4)。 21 | * 22 | */ 23 | 24 | const curry = (func) => { 25 | const curried = (...args) => { 26 | if (args.length >= func.length) { 27 | // 如果传入的 args 长度与原始函数所定义的(func.length)相同或者更长,那么只需要使用 func.apply 将调用传递给它即可。 28 | return func.apply(this, args); 29 | } else { 30 | // 否则,获取一个偏函数:目前还没有调用 func。取而代之的是,返回另一个包装器 pass, 31 | // 它将重新应用 curried,将之前传入的参数与新的参数一起传入。 32 | return (...args1) => { 33 | return curried.apply(this, args.concat(args1)); 34 | }; 35 | } 36 | }; 37 | 38 | return curried; 39 | }; 40 | 41 | const sum = (a, b, c) => a + b + c; 42 | 43 | let curriedSum = curry(sum); 44 | 45 | console.log(curriedSum(1, 2, 3)); // 6 46 | console.log(curriedSum(1)(2, 3)); // 6 47 | console.log(curriedSum(1)(2)(3)); // 6 48 | -------------------------------------------------------------------------------- /js/add_strings.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-10 23:47:10 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-11 15:44:23 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/problems/add-strings/ 10 | * 11 | * 给定两个字符串形式的非负整数 num1 和 num2 ,计算它们的和并同样以字符串形式返回。 12 | * 你不能使用任何內建的用于处理大整数的库(比如 BigInteger),也不能直接将输入的字符串转换为整数形式。 13 | * 14 | * 1. 1 <= num1.length, num2.length <= 104 15 | * 2. num1 和num2 都只包含数字 0-9 16 | * 3. num1 和num2 都不包含任何前导零 17 | * 18 | * 19 | * 示例 1: 20 | * 输入:num1 = "11", num2 = "123" 21 | * 输出:"134" 22 | * 23 | * 示例 2: 24 | * 输入:num1 = "456", num2 = "77" 25 | * 输出:"533" 26 | * 27 | * 示例 3: 28 | * 输入:num1 = "0", num2 = "0" 29 | * 输出:"0" 30 | * 31 | */ 32 | 33 | /** 34 | * 双指针法 35 | * 我们可以使用双指针来模拟人工计算,步骤如下: 36 | * 1. 创建指针 i 指向 num1 末位数字,j 指向 num2 末位数字 37 | * 2. i,j数字相加,用 carry 来记录进位值,没有则为0 38 | * 3. 若产生进位,则当前数字为 (i + j) % 10的值 39 | * 4. 若遍历过程中,num1 或 num2 当前无数字,则用 0 来补位 40 | * 41 | * num1: 4 5 6 42 | * num2: 0 7 7 43 | * ans: 5 3 3 44 | * 45 | * 46 | * @param {string} num1 47 | * @param {string} num2 48 | */ 49 | function addStrings(num1, num2) { 50 | let i = num1.length - 1, 51 | j = num2.length - 1, 52 | carry = 0, // 代表进位值 53 | ans = []; 54 | 55 | while (i >= 0 || j >= 0 || carry != 0) { 56 | let c1 = i >= 0 ? num1.charAt(i) - "0" : 0, 57 | c2 = j >= 0 ? num2.charAt(j) - "0" : 0; 58 | 59 | let sum = c1 + c2 + carry; 60 | ans.push(sum % 10); 61 | carry = Math.floor(sum / 10); 62 | i--; 63 | j--; 64 | } 65 | 66 | return ans.reverse().join(""); 67 | } 68 | 69 | console.log( 70 | "num1 = '11', num2 = '123', num1 + num2 =", 71 | addStrings("11", "123") 72 | ); 73 | console.log( 74 | "num1 = '456', num2 = '77', num1 + num2 =", 75 | addStrings("456", "77") 76 | ); 77 | console.log( 78 | "num1 = '179', num2 = '11', num1 + num2 =", 79 | addStrings("179", "11") 80 | ); 81 | -------------------------------------------------------------------------------- /js/async_worker.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-22 14:22:09 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-22 19:25:37 6 | */ 7 | 8 | // 实现一个异步任务执行器, 其最多只能同时执行 capacity 个异步任务, 9 | // 若同时执行任务数达到 capacity, 则需要等待已有任务完成后才能被执行. 10 | 11 | class AsyncWorker { 12 | constructor(capacity) { 13 | this.capacity = capacity; // 任务最大并发数量 14 | this.queue = []; // 任务队列 15 | this.processTasks = []; // 正在执行的任务队列 16 | } 17 | 18 | /** 19 | * @param {() => T | Promise} task 20 | * @returns Promise 21 | */ 22 | exec(task) { 23 | this.queue.push(task); 24 | return new Promise((resolve, reject) => { 25 | this.run(resolve, reject); 26 | }); 27 | } 28 | 29 | run(resolve, reject) { 30 | while (this.processTasks.length <= this.capacity && this.queue.length) { 31 | const task = this.queue.shift(); 32 | const promise = task() 33 | .then((val) => { 34 | // 任务执行完毕,就移除该任务,并准备执行下一个任务。 35 | this.processTasks.splice( 36 | this.processTasks.indexOf(promise), 37 | 1 38 | ); 39 | this.run(resolve, reject); 40 | resolve(val); 41 | }) 42 | .catch((error) => reject(error)); 43 | 44 | this.processTasks.push(promise); 45 | } 46 | } 47 | } 48 | 49 | async function testAsyncWorker() { 50 | const start = Date.now(); 51 | const createTask = (timeout, error) => { 52 | return () => 53 | new Promise((resolve, reject) => { 54 | setTimeout(() => { 55 | const realCost = Date.now() - start; 56 | const idealCost = (realCost - (realCost % 100)) | 0; 57 | 58 | console.log( 59 | `TASK DONE, timeout: ${timeout}, cost: ${idealCost}` 60 | ); 61 | 62 | if (error) reject(error); 63 | else resolve(timeout); 64 | }, timeout); 65 | }); 66 | }; 67 | 68 | const worker = new AsyncWorker(2); 69 | 70 | await Promise.allSettled([ 71 | worker.exec(createTask(100)), 72 | worker.exec(createTask(201)), 73 | worker.exec(createTask(202, "FAKE ERROR")), 74 | worker.exec(createTask(203)), 75 | worker.exec(createTask(300)), 76 | ]); 77 | 78 | const r = await worker.exec(createTask(100)); 79 | console.log("RETURN", r); 80 | 81 | // 期望控制台得到以下输出: 82 | // TASK DONE, timeout: 100, cost: 100 83 | // TASK DONE, timeout: 201, cost: 200 84 | // TASK DONE, timeout: 202, cost: 300 85 | // TASK DONE, timeout: 203, cost: 400 86 | // TASK DONE, timeout: 300, cost: 600 87 | // TASK DONE, timeout: 100, cost: 700 88 | // RETURN 100 89 | } 90 | 91 | testAsyncWorker(); 92 | -------------------------------------------------------------------------------- /js/balancing_parentheses.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-17 22:55:57 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-17 23:18:41 6 | */ 7 | 8 | /** 9 | * 平衡括号 10 | * 11 | * 给定一个由左右括号组成的字符串,"(" 和 ")",根据需要插入括号来平衡括号。确定必须的最小字符数被插入。 12 | * 13 | * 示例 1: 14 | * 输入:S = '()))' 15 | * 输出:2 16 | * 17 | * 示例 2: 18 | * 输入:S = '(()))' 19 | * 输出:1 20 | * 21 | */ 22 | 23 | function minInsertions(str) { 24 | let bal = 0; 25 | let ans = 0; 26 | 27 | for (let i = 0; i < str.length; i++) { 28 | bal += str[i] === "(" ? 1 : -1; 29 | 30 | // 保证 bal >= -1 31 | if (bal === -1) { 32 | ans += 1; 33 | bal += 1; 34 | } 35 | } 36 | 37 | return bal + ans; 38 | } 39 | 40 | console.log("===================================="); 41 | console.log("S = '()))', 最小字符", minInsertions("()))")); 42 | console.log("===================================="); 43 | 44 | console.log("===================================="); 45 | console.log("S = '(()))', 最小字符", minInsertions("(()))")); 46 | console.log("===================================="); 47 | -------------------------------------------------------------------------------- /js/binary_search.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-12 22:44:07 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-12 22:44:53 6 | */ 7 | 8 | /** 9 | * 10 | * 704. 二分查找 11 | * 12 | * 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 13 | * 14 | * 示例 1: 15 | * 输入: nums = [-1,0,3,5,9,12], target = 9 16 | * 输出: 4 17 | * 解释: 9 出现在 nums 中并且下标为 4 18 | * 19 | * 示例 2: 20 | * 输入: nums = [-1,0,3,5,9,12], target = 2 21 | * 输出: -1 22 | * 解释: 2 不存在 nums 中因此返回 -1 23 | * 24 | * 提示: 25 | * 你可以假设 nums 中的所有元素是不重复的。 26 | * n 将在 [1, 10000]之间。 27 | * nums 的每个元素都将在 [-9999, 9999]之间。 28 | * 29 | */ 30 | const search = (nums, target) => { 31 | let i = 0; 32 | let j = nums.length - 1; 33 | let midIndex = 0; 34 | 35 | while (i <= j) { 36 | midIndex = Math.floor((i + j) / 2); 37 | const midValue = nums[midIndex]; 38 | 39 | if (midValue === target) { 40 | return midIndex; 41 | } else if (midValue < target) { 42 | i = midIndex + 1; 43 | } else { 44 | j = midIndex - 1; 45 | } 46 | } 47 | 48 | return -1; 49 | }; 50 | 51 | console.log(search([-1, 0, 3, 5, 9, 12], 9)); 52 | -------------------------------------------------------------------------------- /js/binary_search_insert.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-14 15:02:58 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-14 15:04:12 6 | */ 7 | 8 | // https://leetcode-cn.com/problems/search-insert-position/ 9 | // 35. 搜索插入位置 10 | 11 | const binarySearchInsert = (nums, target) => { 12 | let i = 0; 13 | let j = nums.length - 1; 14 | let midIndex = 0; 15 | 16 | while (i <= j) { 17 | midIndex = Math.floor((i + j) / 2); 18 | const midValue = nums[midIndex]; 19 | 20 | if (midValue === target) { 21 | return midIndex; 22 | } else if (midValue < target) { 23 | i = midIndex + 1; 24 | } else { 25 | j = midIndex - 1; 26 | } 27 | } 28 | 29 | return i; 30 | }; 31 | 32 | console.log(binarySearchInsert([1, 3, 5, 6], 7)); 33 | -------------------------------------------------------------------------------- /js/compare_version.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-12 16:35:07 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-12 16:45:57 6 | */ 7 | 8 | /** 9 | * 说明:实现一个方法,用于比较两个版本号(version1、version2) 10 | * 如果version1 > version2,返回1;如果version1 < version2,返回-1,其他情况返回 0 11 | * 版本号规则`x.y.z`,xyz均为大于等于0的整数,至少有x位 12 | * 示例: 13 | * compareVersion('0.1', '1.1.1'); // 返回-1 14 | * compareVersion('13.37', '1.2 '); // 返回1 15 | * compareVersion('1.1', '1.1.0'); // 返回0 16 | */ 17 | 18 | /** 19 | * 将 version1 和 version2转化成数组,然后对数组的每一项进行比较大小。 20 | * 21 | * @param {string} version1 22 | * @param {string} version2 23 | * @returns 24 | */ 25 | function compareVersion(version1, version2) { 26 | var v1 = version1.split("."); 27 | var v2 = version2.split("."); 28 | 29 | var length = Math.max(v1.length, v2.length); 30 | 31 | for (var i = 0; i < length; i++) { 32 | var num1 = i < v1.length ? Number(v1[i]) : 0; 33 | var num2 = i < v2.length ? Number(v2[i]) : 0; 34 | 35 | var n = num1 - num2; 36 | 37 | if (n < 0) { 38 | return -1; 39 | } else if (n > 0) { 40 | return 1; 41 | } 42 | } 43 | 44 | return 0; 45 | } 46 | 47 | console.log(compareVersion("0.1", "1.1.1")); 48 | console.log(compareVersion("13.37", "1.2 ")); 49 | console.log(compareVersion("1.1", "1.1.0")); 50 | -------------------------------------------------------------------------------- /js/compose.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-23 15:31:04 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-23 15:58:48 6 | */ 7 | // 用法如下: 8 | function fn1(x) { 9 | return x + 1; 10 | } 11 | 12 | function fn2(x) { 13 | return x + 2; 14 | } 15 | 16 | function fn3(x) { 17 | return x + 3; 18 | } 19 | 20 | function fn4(x) { 21 | return x + 4; 22 | } 23 | 24 | const a = compose(fn1, fn2, fn3, fn4); 25 | 26 | console.log(a(1)); // 1+4+3+2+1=11 27 | 28 | function compose(...fn) { 29 | return fn.reduce( 30 | (result, it) => { 31 | return (...args) => result(it(...args)); 32 | }, 33 | (it) => it 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /js/create_weighted_sampling.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-22 10:54:56 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-02 19:39:33 6 | */ 7 | 8 | // 9 | // 函数 createWeightedSampling 接收一个整数数组 arr, 此数组元素个数 10 | // N < 10000, 元素的值大于 0 且小于 100. 返回一个随机函数, 此随机 11 | // 函数返回 [0, N - 1] 之间的一个随机整数. 每个整数 i 被返回的概率为 12 | // 数组 arr 的第 i 个元素的值 / 数组 arr 的所有元素之和. 13 | // 14 | // 例: 给定一个数组 input, 值为 [4, 2, 1, 3], 15 | // 调用 createWeightedSampling(input), 16 | // 返回一个函数, 此函数返回一个 0 - 3 之间的一个随机整数, 相应的概率 17 | // 分别为 4/10, 2/10, 1/10, 3/10. 18 | // 19 | // 在保证时间复杂度为 O(1) 的前提下, 尽可能优化性能 20 | // 21 | /** 22 | * 加权平均数 23 | * 先计算出每个数据项的权重,然后依据权重依次将每个数据项放入一个数组中,数据项在数组中的个数与数据项的权重呈正相关, 24 | * 为了简便,也可以将数据项的索引放到数组中,比如一组数据的权重依次是 4 2 1 3,则可以生成这样一个数组: 25 | * [0, 0, 0, 0, 1, 1, 2, 3, 3, 3],生成数组后,从数组中随机选出一个作为结果。 26 | * 27 | * @param {number[]} input 28 | * @returns {() => []} 29 | */ 30 | function createWeightedSampling(input) { 31 | let data = []; 32 | let sum = input.reduce((prev, curr) => prev + curr); 33 | const length = input.length; 34 | 35 | for (let i = 0; i < length; i++) { 36 | for (let j = 0; j < input[i]; j++) { 37 | data.push(i); 38 | } 39 | } 40 | 41 | console.log("加权后的数据", data); 42 | 43 | return () => { 44 | let index = Math.floor(Math.random() * sum); 45 | return data[index]; 46 | }; 47 | } 48 | 49 | const arr = [4, 2, 1, 3]; 50 | const count = [0, 0, 0, 0]; 51 | const sampling = createWeightedSampling(arr); 52 | 53 | for (let i = 0; i < 10000; i++) { 54 | count[sampling()]++; 55 | } 56 | 57 | const rates = count.map((i) => Math.round(i / 1000)); 58 | 59 | console.log("概率", count, rates); 60 | console.assert(JSON.stringify(rates) === "[4,2,1,3]"); 61 | -------------------------------------------------------------------------------- /js/decode_string.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-12 11:35:35 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-12 20:42:48 6 | */ 7 | 8 | /** 9 | * 说明:给定一个编码字符,按编码规则进行解码,输出字符串 10 | * 编码规则是`count[letter]`,将letter的内容count次输出,count是0或正整数,letter是区分大小写的纯字母 11 | * 示例: 12 | * const s = '3[a]2[bc]'; decodeString(s); // 返回'aaabcbc' 13 | * const s = '3[a2[c]]'; decodeString(s); // 返回'accaccacc' 14 | * const s = '2[abc]3[cd]ef'; decodeString(s); // 返回'abcabccdcdcdef' 15 | */ 16 | 17 | /** 18 | * 题解: 19 | * 从字符串的规则中,可以很容易发现规律,可以用正则表达式写出字符串 '3[a]2[bc]' 的基本规则,然后根据正则表达式匹配获取 20 | * 字符串中的的数字和字母,通过递归逐个匹配计算出字符串数量,最终组合成上述形式。 21 | * 22 | * @param {string} str 23 | */ 24 | function decodeString(str) { 25 | const reg = /(\d?)(\[[a-zA-Z]+\])/g; 26 | 27 | if (!reg.test(str)) return str; 28 | 29 | str = str.replace(reg, function (_, p1, p2) { 30 | let letter = ""; 31 | 32 | console.log(p1, p2); 33 | 34 | if (!p1) { 35 | p1 = 1; 36 | } 37 | 38 | if (/\d/.test(p1)) { 39 | for (let i = 0; i < p1; i++) { 40 | p2 = p2.replace("[", "").replace("]", ""); 41 | letter += p2; 42 | } 43 | } 44 | 45 | return letter; 46 | }); 47 | 48 | return decodeString(str); 49 | } 50 | 51 | const s1 = "3[a]2[bc]"; 52 | const s2 = "3[a2[c]]"; 53 | const s3 = "2[Abc]3[Cd]ef"; 54 | 55 | console.log("===================================="); 56 | console.log("Decode string s1 ", decodeString(s1)); // aaabcbc 57 | console.log("===================================="); 58 | console.log("Decode string s2 ", decodeString(s2)); // accaccacc 59 | console.log("===================================="); 60 | console.log("Decode string s3", decodeString(s3)); // AbcAbcCdCdCdef 61 | console.log("===================================="); 62 | -------------------------------------------------------------------------------- /js/event_emitter.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-12 18:58:03 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-12 19:00:03 6 | */ 7 | 8 | /** 9 | * 说明:简单实现一个事件订阅机制,具有监听on和触发emit方法, off取消绑定 10 | * 示例: 11 | * const event = new EventEmitter(); 12 | * event.on('someEvent', (...args) => { 13 | * console.log('some_event triggered', ...args); 14 | * }); 15 | * event.emit('someEvent', 'abc', '123'); 16 | */ 17 | 18 | function EventEmitter() {} 19 | 20 | /* 功能实现 */ 21 | EventEmitter.prototype.on = function (eventName, callback) { 22 | if (!this.handles) { 23 | this.handles = {}; 24 | } 25 | 26 | if (!this.handles[eventName]) { 27 | this.handles[eventName] = []; 28 | } 29 | 30 | this.handles[eventName].push(callback); 31 | }; 32 | 33 | EventEmitter.prototype.emit = function (eventName, ...args) { 34 | if (!this.handles[eventName]) { 35 | return; 36 | } 37 | 38 | this.handles[eventName].forEach(function (callback) { 39 | callback(...args); 40 | }); 41 | }; 42 | 43 | EventEmitter.prototype.off = function (eventName) { 44 | if (!this.handles[eventName]) { 45 | return; 46 | } 47 | 48 | this.handles[eventName] = []; 49 | }; 50 | 51 | const eventEmitter = new EventEmitter(); 52 | 53 | eventEmitter.on("someEvent1", (...args) => { 54 | console.log("触发了 someEvent1 事件1", ...args); 55 | }); 56 | 57 | eventEmitter.on("someEvent2", (...args) => { 58 | console.log("触发了 someEvent2 事件2", ...args); 59 | }); 60 | 61 | eventEmitter.emit("someEvent1", "abcd"); 62 | eventEmitter.emit("someEvent2", "1234"); 63 | -------------------------------------------------------------------------------- /js/event_loop_browser.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-04 21:18:16 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-04 22:39:58 6 | */ 7 | 8 | /** 9 | * 10 | * Event Loop 在浏览器中的测试用例 11 | * 12 | */ 13 | console.log("1"); 14 | 15 | setTimeout(function () { 16 | console.log("2"); 17 | new Promise(function (resolve) { 18 | console.log("3"); 19 | resolve(); 20 | }).then(function () { 21 | console.log("4"); 22 | }); 23 | setTimeout(function () { 24 | console.log("5"); 25 | new Promise(function (resolve) { 26 | console.log("6"); 27 | resolve(); 28 | }).then(function () { 29 | console.log("7"); 30 | }); 31 | }); 32 | console.log("14"); 33 | }); 34 | 35 | new Promise(function (resolve) { 36 | console.log("8"); 37 | resolve(); 38 | }).then(function () { 39 | console.log("9"); 40 | }); 41 | 42 | setTimeout(function () { 43 | console.log("10"); 44 | new Promise(function (resolve) { 45 | console.log("11"); 46 | resolve(); 47 | }).then(function () { 48 | console.log("12"); 49 | }); 50 | }); 51 | 52 | console.log("13"); 53 | 54 | // 1->8->13->9->2->3->14->4->10->11->12->5->6->7 55 | -------------------------------------------------------------------------------- /js/event_loop_in_browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/js/event_loop_in_browser.png -------------------------------------------------------------------------------- /js/event_loop_in_node.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-04 21:58:32 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-04 22:15:51 6 | */ 7 | 8 | /** 9 | * 10 | * Event Loop 在 Node 中的测试用例 11 | * 12 | */ 13 | 14 | console.log("1"); 15 | 16 | setTimeout(function () { 17 | console.log("2"); 18 | 19 | process.nextTick(function () { 20 | console.log("3"); 21 | }); 22 | 23 | new Promise(function (resolve) { 24 | console.log("4"); 25 | resolve(); 26 | }).then(function () { 27 | console.log("5"); 28 | }); 29 | }); 30 | 31 | process.nextTick(function () { 32 | console.log("6"); 33 | }); 34 | 35 | new Promise(function (resolve) { 36 | console.log("7"); 37 | resolve(); 38 | }).then(function () { 39 | console.log("8"); 40 | }); 41 | 42 | setTimeout(function () { 43 | console.log("9"); 44 | 45 | process.nextTick(function () { 46 | console.log("10"); 47 | }); 48 | 49 | new Promise(function (resolve) { 50 | console.log("11"); 51 | resolve(); 52 | }).then(function () { 53 | console.log("12"); 54 | }); 55 | }); 56 | 57 | console.log("13"); 58 | 59 | // 1->7->13->6->8->2->4->3->5->9->11->10->12 60 | -------------------------------------------------------------------------------- /js/event_loop_in_node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/js/event_loop_in_node.png -------------------------------------------------------------------------------- /js/event_loop_structure_in_browser.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/js/event_loop_structure_in_browser.jpg -------------------------------------------------------------------------------- /js/expire_storage.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-29 11:19:24 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-29 13:18:34 6 | */ 7 | 8 | /** 9 | * Expire storage,支持过期时间的 localStorage 10 | */ 11 | 12 | class ExpireStorage { 13 | prefix = "Chacha"; 14 | 15 | tag = "|Chacha|"; 16 | 17 | defaultTime = Date.now() + 24 * 60 * 60 * 31 * 1000; // 默认时长1个月 18 | 19 | constructor(prefix, tag) { 20 | this.prefix = prefix; 21 | this.tag = tag; 22 | } 23 | 24 | setItem(key, value, time) { 25 | key = `${this.prefix}${key}`; 26 | time = time ? new Date(time).getTime() : this.defaultTime; 27 | 28 | // 构造一个形如 1646094676134|Chacha|"Hello World" 结构的字符串 29 | window.localStorage.setItem( 30 | key, 31 | `${time}${this.tag}${JSON.stringify(value)}` 32 | ); 33 | } 34 | 35 | getItem(key) { 36 | key = `${this.prefix}${key}`; 37 | let value = window.localStorage.getItem(key); 38 | 39 | if (value) { 40 | let index = value.indexOf(this.tag); 41 | let time = +value.slice(0, index); 42 | 43 | // 判断时间是否已过期 44 | if (time > Date.now()) { 45 | value = JSON.parse(value.slice(index + this.tag.length)); 46 | } else { 47 | value = null; 48 | window.localStorage.removeItem(key); 49 | } 50 | } 51 | 52 | return value; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /js/find_pivot_index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-12 23:21:07 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-12 23:24:46 6 | */ 7 | 8 | /** 9 | * 来源: https://leetcode-cn.com/problems/find-pivot-index/ 10 | * 11 | * 寻找数组的中心下标 12 | * 给你一个整数数组 nums ,请计算数组的 中心下标 。数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。 13 | * 如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。 14 | * 如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。 15 | * 16 | */ 17 | 18 | const pivotIndex = (nums) => { 19 | let total = nums.reduce((ret, num) => ret + num, 0); 20 | let sum = 0; 21 | 22 | for (let i = 0, len = nums.length; i < len; i++) { 23 | if (sum * 2 + nums[i] === total) { 24 | return i; 25 | } 26 | 27 | sum += nums[i]; 28 | } 29 | 30 | return -1; 31 | }; 32 | 33 | console.log(pivotIndex([1, 2, 3, 4, 5, 6])); 34 | console.log(pivotIndex([1, 2, 3, 4, 3, 2, 1])); 35 | -------------------------------------------------------------------------------- /js/first_uniq_char.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-24 22:33:31 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-24 22:35:16 6 | */ 7 | 8 | // 字符串中的第一个唯一字符 https://leetcode-cn.com/leetbook/read/top-interview-questions-easy/xn5z8r/ 9 | /** 10 | * 387. 字符串中的第一个唯一字符 11 | * 给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。 12 | * 13 | * 示例: 14 | * s = "leetcode" 15 | * 返回 0 16 | * 17 | * s = "loveleetcode" 18 | * 返回 2 19 | * 提示:你可以假定该字符串只包含小写字母。 20 | * 21 | */ 22 | 23 | // 利用hash表存储数量进行计数,然后再进行一次计算 24 | const firstUniqChar = (s) => { 25 | let cacheMap = {}; 26 | 27 | for (let i = 0, len = s.length; i < len; i++) { 28 | const value = s[i]; 29 | 30 | cacheMap[value] = 31 | typeof cacheMap[value] !== "undefined" ? cacheMap[value] + 1 : 1; 32 | } 33 | 34 | for (let i = 0, len = s.length; i < len; i++) { 35 | if (cacheMap[s[i]] === 1) { 36 | return i; 37 | } 38 | } 39 | 40 | return -1; 41 | }; 42 | 43 | console.log(firstUniqChar("leetcode")); // 0 44 | console.log(firstUniqChar("loveleetcode")); // 2 45 | console.log(firstUniqChar("aadadaad")); // -1 46 | -------------------------------------------------------------------------------- /js/flat.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @param {*} array 深层嵌套的数据 4 | * @returns array 新数组 5 | */ 6 | const flat1 = (array) => { 7 | return array.reduce((result, it) => { 8 | return result.concat(Array.isArray(it) ? flat1(it) : it); 9 | }, []); 10 | }; 11 | 12 | let arr1 = [1, [2, 3, 4], [5, [6, [7, [8]]]]]; 13 | console.log(flat1(arr1)); 14 | 15 | // js原生的flat方法 16 | /** 17 | * 18 | * @param {*} array 深层嵌套的数据 19 | * @returns 新数组 20 | */ 21 | const flat2 = (array) => { 22 | return array.flat(Infinity); 23 | }; 24 | 25 | let arr2 = [1, [2, 3, 4], [5, [6, [7, [8]]]]]; 26 | 27 | console.log(flat2(arr2)); 28 | 29 | const flat3 = (array) => { 30 | const result = []; 31 | const stack = [...array]; 32 | 33 | while (stack.length !== 0) { 34 | const val = stack.pop(); 35 | if (Array.isArray(val)) { 36 | stack.push(...val); 37 | } else { 38 | result.unshift(val); 39 | } 40 | } 41 | return result; 42 | }; 43 | 44 | let arr3 = [1, [2, 3, 4], [5, [6, [7, [8]]]]]; 45 | 46 | console.log(flat3(arr3)); 47 | -------------------------------------------------------------------------------- /js/generator.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-08 11:53:02 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-08 12:08:52 6 | */ 7 | 8 | /** 9 | * 10 | * Generator 11 | * 12 | */ 13 | 14 | function* generator() { 15 | yield "status one"; 16 | yield "status two"; 17 | return "hello world"; 18 | } 19 | 20 | const iterator = generator(); // 调用 Generator函数,函数并没有执行,返回的是一个Iterator对象 21 | 22 | console.log("Iterator对象", iterator); 23 | 24 | for (let value of iterator) { 25 | console.log(value); 26 | } 27 | 28 | console.log("===================================="); 29 | 30 | console.log(iterator.next()); // { value: "status one", done: false },value 表示返回值,done 表示遍历还没有结束 31 | console.log(iterator.next()); // { value: "status two", done: false } 32 | console.log(iterator.next()); // { value: "status one", done: true } 33 | -------------------------------------------------------------------------------- /js/instance_of.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-28 00:00:28 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-07 18:19:32 6 | */ 7 | 8 | /** 9 | * 10 | * @param {*} obj 实例对象 11 | * @param {*} func 构造函数 12 | * @returns true false 13 | */ 14 | const instanceOf1 = (obj, func) => { 15 | if (!(obj && ["object", "function"].includes(typeof obj))) { 16 | return false; 17 | } 18 | 19 | // 获取对象的原型 prototype 20 | let proto = Object.getPrototypeOf(obj); 21 | 22 | if (proto === func.prototype) { 23 | // 如果原型 proto 与 func 的原型一致,就说明 obj 是 func 的实例对象,返回 true。 24 | return true; 25 | } else if (proto === null) { 26 | // 如果 proto 等于 null,返回 false。 27 | return false; 28 | } else { 29 | // 否则,继续向上查找原型的原型 30 | return instanceOf1(proto, func); 31 | } 32 | }; 33 | /** 34 | * 35 | * @param {*} obj 实例对象 36 | * @param {*} func 构造函数 37 | * @returns true false 38 | */ 39 | const instanceOf2 = (obj, func) => { 40 | if (!(obj && ["object", "function"].includes(typeof obj))) { 41 | return false; 42 | } 43 | 44 | let proto = obj; 45 | 46 | while ((proto = Object.getPrototypeOf(proto))) { 47 | if (proto === null) { 48 | return false; 49 | } else if (proto === func.prototype) { 50 | return true; 51 | } 52 | } 53 | 54 | return false; 55 | }; 56 | 57 | let Fn = function () {}; 58 | let p1 = new Fn(); 59 | 60 | console.log(instanceOf1({}, Object)); // true 61 | console.log(instanceOf1(p1, Fn)); // true 62 | console.log(instanceOf1({}, Fn)); // false 63 | console.log(instanceOf1(null, Fn)); // false 64 | console.log(instanceOf1(1, Fn)); // false 65 | console.log(instanceOf1(function a() {}, Function)); // true 66 | 67 | console.log("-----------------------"); 68 | 69 | console.log(instanceOf2({}, Object)); // true 70 | console.log(instanceOf2(p1, Fn)); // true 71 | console.log(instanceOf2({}, Fn)); // false 72 | console.log(instanceOf2(null, Fn)); // false 73 | console.log(instanceOf2(1, Fn)); // false 74 | console.log(instanceOf1(function a() {}, Function)); // true 75 | -------------------------------------------------------------------------------- /js/is_anagram.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-21 23:30:44 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-21 23:35:00 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/leetbook/read/top-interview-questions-easy/xn96us/ 10 | * 11 | * 242. 有效的字母异位词 12 | * 13 | * 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 14 | * 注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。 15 | * 16 | * 示例 1: 17 | * 输入: s = "anagram", t = "nagaram" 18 | * 输出: true 19 | * 20 | * 示例 2: 21 | * 输入: s = "rat", t = "car" 22 | * 输出: false 23 | * 24 | * 提示: 25 | * 1 <= s.length, t.length <= 5 * 10^4 26 | * s 和 t 仅包含小写字母 27 | * 进阶: 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况? 28 | * 29 | */ 30 | 31 | const isAnagram = (s, t) => { 32 | const calcStrCount = (s) => { 33 | let cacheMap = {}; 34 | 35 | for (let i = 0, len = s.length; i < len; i++) { 36 | const value = s[i]; 37 | 38 | // 计算字符串每个字符出现的次数 39 | cacheMap[value] = 40 | typeof cacheMap[value] !== "undefined" 41 | ? cacheMap[value] + 1 42 | : 1; 43 | } 44 | 45 | return cacheMap; 46 | }; 47 | 48 | const sMap = calcStrCount(s); 49 | const tMap = calcStrCount(t); 50 | 51 | const getResult = (map1, map2) => { 52 | if (Object.values(map1).length < Object.values(map2).length) { 53 | return getResult(map2, map1); 54 | } 55 | 56 | for (const item in map1) { 57 | if (map1[item] !== map2[item]) { 58 | return false; 59 | } 60 | } 61 | 62 | return true; 63 | }; 64 | 65 | return getResult(sMap, tMap); 66 | }; 67 | 68 | console.log(isAnagram("anagram", "nagaram")); 69 | console.log(isAnagram("rat", "car")); 70 | -------------------------------------------------------------------------------- /js/is_prime_or_not.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-17 22:06:08 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-17 22:50:58 6 | */ 7 | 8 | /** 9 | * Prime or not? 10 | * 11 | * 给定一个整数 n,如果该数是素数,则返回 1。否则返回大于 1 的最小除数。 12 | * 13 | * 2 ≤ n ≤ 10^12 14 | * 15 | * 示例 1: 16 | * n = 24; 17 | * 数字 24 不是素数:它的除数是 (1, 2, 3, 4, 6, 8, 12, 24)。最小除数大于 1,是 2。 18 | * 19 | */ 20 | 21 | function isPrimeOrNot(n) { 22 | for (let i = 2; i * i <= n; i++) { 23 | if (n % i == 0) { 24 | return i; 25 | } 26 | } 27 | 28 | return 1; 29 | } 30 | 31 | console.log("是否是素数", isPrimeOrNot(2)); 32 | console.log("是否是素数", isPrimeOrNot(4)); 33 | console.log("是否是素数", isPrimeOrNot(7)); 34 | console.log("是否是素数", isPrimeOrNot(13)); 35 | console.log("是否是素数", isPrimeOrNot(15)); 36 | console.log("是否是素数", isPrimeOrNot(24)); 37 | console.log("是否是素数", isPrimeOrNot(31)); 38 | -------------------------------------------------------------------------------- /js/list_to_tree.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-09 23:13:53 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-09 23:15:09 6 | */ 7 | 8 | /** 9 | * 10 | let arr = [ 11 | {id: 1, name: '部门1', pid: 0}, 12 | {id: 2, name: '部门2', pid: 1}, 13 | {id: 3, name: '部门3', pid: 1}, 14 | {id: 4, name: '部门4', pid: 3}, 15 | {id: 5, name: '部门5', pid: 4}, 16 | ] 17 | => 18 | [ 19 | { 20 | "id": 1, 21 | "name": "部门1", 22 | "pid": 0, 23 | "children": [ 24 | { 25 | "id": 2, 26 | "name": "部门2", 27 | "pid": 1, 28 | "children": [] 29 | }, 30 | { 31 | "id": 3, 32 | "name": "部门3", 33 | "pid": 1, 34 | "children": [ 35 | // 结果 ,,, 36 | ] 37 | } 38 | ] 39 | } 40 | ] 41 | * 42 | * 43 | */ 44 | // 非递归版本 45 | const arrayToTree = (array) => { 46 | const hashMap = {}; 47 | let result = []; 48 | 49 | array.forEach((it) => { 50 | const { id, pid } = it; 51 | 52 | // 不存在时,先声明children树形 53 | // 这一步也有可能在下面出现 54 | if (!hashMap[id]) { 55 | hashMap[id] = { 56 | children: [], 57 | }; 58 | } 59 | 60 | hashMap[id] = { 61 | ...it, 62 | children: hashMap[id].children, 63 | }; 64 | // 处理当前的item 65 | const treeIt = hashMap[id]; 66 | 67 | // 根节点,直接push 68 | if (pid === 0) { 69 | result.push(treeIt); 70 | } else { 71 | // 也有可能当前节点的父父节点还没有加入hashMap,所以需要单独处理一下 72 | if (!hashMap[pid]) { 73 | hashMap[pid] = { 74 | children: [], 75 | }; 76 | } 77 | // 非根节点的话,找到父节点,把自己塞到父节点的children中即可 78 | hashMap[pid].children.push(treeIt); 79 | } 80 | }); 81 | 82 | return result; 83 | }; 84 | 85 | const data = [ 86 | // 注意这里,专门把pid为1的元素放一个在前面 87 | { id: 2, name: "部门2", pid: 1 }, 88 | { id: 1, name: "部门1", pid: 0 }, 89 | { id: 3, name: "部门3", pid: 1 }, 90 | { id: 4, name: "部门4", pid: 3 }, 91 | { id: 5, name: "部门5", pid: 4 }, 92 | { id: 7, name: "部门7", pid: 6 }, 93 | ]; 94 | 95 | console.log(JSON.stringify(arrayToTree(data), null, 2)); 96 | -------------------------------------------------------------------------------- /js/longest_common_prefix.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-20 23:43:32 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-20 23:44:48 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/problems/longest-common-prefix/ 10 | * 11 | * 14. 最长公共前缀 12 | * 13 | * 编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。 14 | * 15 | * 示例 1: 16 | * 输入:strs = ["flower","flow","flight"] 17 | * 输出:"fl" 18 | * 19 | * 示例 2: 20 | * 输入:strs = ["dog","racecar","car"] 21 | * 输出:"" 22 | * 解释:输入不存在公共前缀。 23 | * 24 | */ 25 | // 横向扫描 也可以想起 版本比较的算法题,第一个和第二个比较,再拿结果和第三个比较 26 | const longestCommonPrefix = (strs) => { 27 | if (strs.length === 0) { 28 | return ""; 29 | } 30 | 31 | let prefix = strs[0]; 32 | const len = strs.length; 33 | const getPrevfix = (str1, str2) => { 34 | if (str1.length > str2.length) { 35 | return getPrevfix(str2, str1); 36 | } 37 | 38 | let i = 0; 39 | let substrLen = 0; 40 | const len = str1.length; 41 | 42 | while (i < len) { 43 | if (str1[i] === str2[i]) { 44 | substrLen++; 45 | } else { 46 | break; 47 | } 48 | i++; 49 | } 50 | 51 | return str1.substr(0, substrLen); 52 | }; 53 | 54 | for (let i = 1; i < len; i++) { 55 | prefix = getPrevfix(prefix, strs[i]); 56 | 57 | if (prefix === "") { 58 | return ""; 59 | } 60 | } 61 | 62 | return prefix; 63 | }; 64 | 65 | console.log(longestCommonPrefix(["flower", "flow", "flight"])); 66 | -------------------------------------------------------------------------------- /js/max_in_array.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-12 20:54:15 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-12 23:50:58 6 | */ 7 | 8 | /** 9 | * 说明:获取一个数字数组中的最大值 10 | * 示例: 11 | * 输入:[1, 5, 3, 9, 2, 7] 12 | * 输出:9 13 | */ 14 | function getMaxFromArray(arr) { 15 | if (!Array.isArray(arr)) return; 16 | 17 | var max = arr[0]; 18 | arr.forEach(function (item) { 19 | if (max < item) { 20 | max = item; 21 | } 22 | }); 23 | 24 | return max; 25 | } 26 | 27 | const arr = [1, 5, 3, 9, 2, 7]; 28 | 29 | console.log("===================================="); 30 | console.log(getMaxFromArray(arr)); 31 | console.log("===================================="); 32 | -------------------------------------------------------------------------------- /js/merge_sorted_array.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-19 23:27:39 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-19 23:28:56 6 | */ 7 | 8 | /** 9 | * 10 | * 来源:https://leetcode-cn.com/problems/merge-sorted-array/ 11 | * 12 | * 给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。 13 | * 初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。你可以假设 nums1 的空间大小等于 m + n,这样它就有足够的空间保存来自 nums2 的元素。 14 | * 15 | * 示例 1: 16 | * 输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 17 | * 输出:[1,2,2,3,5,6] 18 | * 19 | * 示例 2: 20 | * 输入:nums1 = [1], m = 1, nums2 = [], n = 0 21 | * 输出:[1] 22 | * 23 | */ 24 | const nums1 = [1, 2, 3, 0, 0, 0]; 25 | const m = 3; 26 | const nums2 = [2, 5, 6]; 27 | const n = 3; 28 | 29 | const merge = (num1, m, num2, n) => { 30 | let i = m - 1; 31 | let j = n - 1; 32 | let k = m + n - 1; 33 | 34 | while (i >= 0 && j >= 0) { 35 | if (num1[i] > num2[j]) { 36 | num1[k] = num1[i]; 37 | i--; 38 | k--; 39 | } else { 40 | num1[k] = num2[j]; 41 | j--; 42 | k--; 43 | } 44 | } 45 | 46 | while (j >= 0) { 47 | num1[j] = num2[j]; 48 | j--; 49 | } 50 | 51 | return num1; 52 | }; 53 | 54 | console.log(merge(nums1, m, nums2, n)); 55 | -------------------------------------------------------------------------------- /js/mobile_334.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-03 12:20:57 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-03 12:21:37 6 | */ 7 | 8 | // 适合纯11位手机 9 | const splitMobile = (mobile, format = "-") => { 10 | return String(mobile).replace(/(?=(\d{4})+$)/g, format); 11 | }; 12 | // 适合11位以内的分割 13 | const splitMobile2 = (mobile, format = "-") => { 14 | return String(mobile) 15 | .replace(/(?<=(\d{3}))/, format) 16 | .replace(/(?<=([\d\-]{8}))/, format); 17 | }; 18 | 19 | console.log(splitMobile(13798247501)); 20 | console.log(splitMobile2(13798247501)); 21 | -------------------------------------------------------------------------------- /js/move_zeroes.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-21 22:39:49 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-21 22:41:42 6 | */ 7 | 8 | /** 9 | * 283. 移动零 https://leetcode-cn.com/problems/move-zeroes/ 10 | * 11 | * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 12 | * 13 | * 示例: 14 | * 输入: [0,1,0,3,12] 15 | * 输出: [1,3,12,0,0] 16 | * 说明: 必须在原数组上操作,不能拷贝额外的数组。尽量减少操作次数。 17 | * 18 | */ 19 | 20 | // 思路就是将非零的不断往前移动,零的不断往后移动 21 | const moveZeroes = (nums) => { 22 | let len = nums.length; 23 | let j = 0; 24 | 25 | for (let i = 0; i < len; i++) { 26 | if (nums[i] !== 0) { 27 | let temp = nums[i]; 28 | 29 | nums[i] = nums[j]; 30 | nums[j] = temp; 31 | 32 | j++; 33 | } 34 | } 35 | 36 | return nums; 37 | }; 38 | 39 | console.log("===================================="); 40 | console.log(moveZeroes([0, 1, 0, 3, 12])); 41 | console.log("===================================="); 42 | -------------------------------------------------------------------------------- /js/new.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-11 16:31:46 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-12 19:11:49 6 | */ 7 | 8 | /** 9 | * JavaScript之 new 的模拟实现 10 | * 11 | * new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象类型之一 12 | * 13 | */ 14 | 15 | function objectFactory() { 16 | var constructor = Array.prototype.shift.call(arguments); // 取出第一个参数,就是我们要传入的构造函数 17 | var obj = Object.create(constructor.prototype); // 根据构造函数的原型创建一个对象 18 | var result = constructor.apply(obj, arguments); 19 | 20 | return typeof result === "object" && result !== null ? result : obj; 21 | } 22 | 23 | function Test(name, age) { 24 | this.name = name; 25 | this.age = age; 26 | this.habit = "Games"; 27 | } 28 | 29 | Test.prototype.height = 177; 30 | 31 | Test.prototype.sayYourName = function () { 32 | console.log("I am " + this.name); 33 | }; 34 | 35 | let person = objectFactory(Test, "Chacha", "28"); 36 | 37 | console.log(person.name); // Chacha 38 | console.log(person.habit); // Games 39 | console.log(person.height); // 177 40 | 41 | person.sayYourName(); 42 | -------------------------------------------------------------------------------- /js/odd_even_linked_list.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-10 21:46:56 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-10 21:49:27 6 | */ 7 | /** 8 | * 奇偶链表 9 | * 10 | */ 11 | class ListNode { 12 | constructor(val, next) { 13 | this.val = val === undefined ? 0 : val; 14 | this.next = next === undefined ? null : next; 15 | } 16 | } 17 | 18 | const oddEvenList = function (head) { 19 | if (head === null) { 20 | return null; 21 | } 22 | 23 | if (head.next === null) { 24 | return head; 25 | } 26 | 27 | let odd = head, 28 | even = head.next, 29 | evenHead = head.next; 30 | 31 | // console.log(evenHead); 32 | 33 | while (even !== null && even.next !== null) { 34 | odd.next = odd.next.next; 35 | odd = odd.next; 36 | even.next = even.next.next; 37 | even = even.next; 38 | } 39 | 40 | odd.next = evenHead; 41 | 42 | // console.log(evenHead, head.next); 43 | 44 | return head; 45 | }; 46 | 47 | let node5 = new ListNode(5); 48 | let node4 = new ListNode(4, node5); 49 | let node3 = new ListNode(3, node4); 50 | let node2 = new ListNode(2, node3); 51 | let node1 = new ListNode(1, node2); 52 | 53 | console.log(oddEvenList(node1)); 54 | -------------------------------------------------------------------------------- /js/pivot_index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-14 15:07:38 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-14 15:08:47 6 | */ 7 | /** 8 | * 来源:https://leetcode-cn.com/problems/find-pivot-index/ 9 | * 10 | * 724. 寻找数组的中心下标 11 | * 12 | * 给你一个整数数组 nums ,请计算数组的 中心下标 。数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。 13 | * 如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。 14 | * 如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。 15 | * 16 | */ 17 | 18 | const pivotIndex = (nums) => { 19 | let total = nums.reduce((ret, num) => ret + num, 0); 20 | let sum = 0; 21 | 22 | for (let i = 0, len = nums.length; i < len; i++) { 23 | if (sum * 2 + nums[i] === total) { 24 | return i; 25 | } 26 | 27 | sum += nums[i]; 28 | } 29 | 30 | return -1; 31 | }; 32 | -------------------------------------------------------------------------------- /js/profit_targets.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-19 17:01:38 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-11 10:57:05 6 | */ 7 | 8 | /** 9 | * 双指针法 10 | * 11 | * 金融分析师负责以一系列为代表的有利可图股票投资组合。每个的数组中的项目代表相应股票的年利润。 12 | * 分析师收集了所有达到目标利润的不同对股票。不同的对是至少不同的对一个元素。给定利润数组, 13 | * 找到不同一对股票的数量,其中每对的总和利润与目标利润完全相等。 14 | * 15 | * 示例 1: 16 | * 输入: 17 | * stocksProfit = [5, 7, 9, 13, 11, 6, 6, 3, 31] 18 | * target = 12 (利润目标) 19 | * 20 | * 输出:3 21 | * 因为存在 3 对股票组合的利润是 12:[5, 7],[3, 9],[6, 6] 22 | * 23 | */ 24 | 25 | function stockPairs(stocksProfit, target) { 26 | let pairs = 0; 27 | let low = 0, 28 | high = stocksProfit.length - 1; 29 | 30 | // 将数组排序 31 | stocksProfit.sort((a, b) => a - b); 32 | 33 | while (low < high) { 34 | if (stocksProfit[low] + stocksProfit[high] === target) { 35 | // 移除重复元素 36 | while (low < high && stocksProfit[low] === stocksProfit[low + 1]) { 37 | low++; 38 | } 39 | while ( 40 | low < high && 41 | stocksProfit[high] === stocksProfit[high - 1] 42 | ) { 43 | high--; 44 | } 45 | 46 | pairs += 1; 47 | 48 | low++; 49 | high--; 50 | } else if (stocksProfit[low] + stocksProfit[high] < target) { 51 | low++; 52 | } else { 53 | high--; 54 | } 55 | } 56 | 57 | return pairs; 58 | } 59 | 60 | console.log("===================================="); 61 | console.log(stockPairs([5, 6, 5, 7, 7, 8], 13)); // 输出 2 62 | console.log("===================================="); 63 | 64 | console.log("===================================="); 65 | console.log(stockPairs([5, 7, 9, 13, 11, 6, 6, 3, 31], 12)); // 输出 3 66 | console.log("===================================="); 67 | -------------------------------------------------------------------------------- /js/proxy.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-28 23:19:39 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-28 23:36:05 6 | */ 7 | 8 | /** 9 | * Proxy 10 | * Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等), 11 | * 等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。 12 | * 13 | * Proxy 就像在目标对象之间的一个代理,任何对目标的操作都要经过代理。代理就可以对外界的操作进行过滤和改写。 14 | * 15 | * Proxy 是构造函数,它有两个参数 target 和 handler。 16 | * target是用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。 17 | * handler 是一个对象,其属性是当执行一个操作时定义代理的行为函数。 18 | * 19 | * Proxy 只有一个静态方法revocable(target, handler)可以用来创建一个可撤销的代理对象。 20 | * 两个参数和构造函数的相同。它返回一个包含了所生成的代理对象本身以及该代理对象的撤销方法的对象。 21 | * 22 | * 一旦某个代理对象被撤销,它将变的几乎完全不可用,在它身上执行任何的可代理操作都会抛出 TypeError 异常 23 | * (注意,可代理操作一共有 14 种,执行这 14 种操作以外的操作不会抛出异常)。 24 | * 一旦被撤销,这个代理对象永远不可能恢复到原来的状态,同时和它关联的目标对象以及处理器对象将有可能被垃圾回收掉。 25 | * 调用撤销方法多次将不会有任何效果,当然,也不会报错。 26 | * 27 | */ 28 | const obj = new Proxy( 29 | {}, 30 | { 31 | get: function (target, key, receiver) { 32 | console.log("===================================="); 33 | console.log("Getting key: ", key); 34 | console.log("===================================="); 35 | return Reflect.get(target, key, receiver); 36 | }, 37 | 38 | set: function (target, key, value, receiver) { 39 | console.log("===================================="); 40 | console.log("Setting key: ", key); 41 | console.log("===================================="); 42 | return Reflect.set(target, key, value, receiver); 43 | }, 44 | } 45 | ); 46 | 47 | obj.count = 1; 48 | obj.count++; 49 | 50 | console.log("===================================="); 51 | console.log("obj", obj); 52 | console.log("===================================="); 53 | 54 | const revocable = Proxy.revocable( 55 | {}, 56 | { 57 | get(target, name) { 58 | return "[[" + name + "]]"; 59 | }, 60 | } 61 | ); 62 | // revocable => {"proxy":proxy,"revoke":revoke} 63 | 64 | const proxy = revocable.proxy; 65 | proxy.foo; // "[[foo]]" 66 | 67 | console.log("===================================="); 68 | console.log("proxy", proxy, proxy.foo); 69 | console.log("===================================="); 70 | 71 | revocable.revoke(); // 执行撤销方法 72 | 73 | // proxy.foo; // TypeError: Cannot perform 'get' on a proxy that has been revoked 74 | // proxy.foo = 1; // TypeError: Cannot perform 'get' on a proxy that has been revoked 75 | // delete proxy.foo; // TypeError: Cannot perform 'get' on a proxy that has been revoked 76 | console.log(typeof proxy); // "object" 因为typeof 不属于代理操作 77 | -------------------------------------------------------------------------------- /js/quick_sort.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-04 16:55:30 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-04 17:06:03 6 | */ 7 | 8 | /** 9 | * 快速排序 10 | * 1. 选择一个基准元素 pivot,比如第一个元素 11 | * 2. 遍历数组,比 pivot 更小的元素创建一个数组,更大的创建一个数组,相等的也创建一个数组 12 | * 3. 递归大小两个数组,继续执行1,直到数组只剩1个元素;递归的同时把这三部分连接起来 13 | * 14 | */ 15 | 16 | /** 17 | * 快速排序 18 | * @param {[]} array 19 | * @returns {[]} array 20 | */ 21 | const quickSort = (array) => { 22 | const length = array.length; 23 | 24 | if (length <= 1) { 25 | return array; 26 | } 27 | 28 | const pivotIndex = Math.floor(length / 2); // 基准元素下标 29 | const pivotValue = array.splice(pivotIndex, 1)[0]; 30 | let leftArray = [], 31 | rightArray = [], 32 | index = 0; 33 | 34 | while (index < length - 1) { 35 | const currentValue = array[index]; 36 | 37 | if (currentValue <= pivotValue) { 38 | leftArray.push(currentValue); 39 | } else { 40 | rightArray.push(currentValue); 41 | } 42 | 43 | index++; 44 | } 45 | 46 | return quickSort(leftArray).concat([pivotValue], quickSort(rightArray)); 47 | }; 48 | 49 | const arr = [-10, 10, 1, 34, 5, 1]; 50 | 51 | console.log(quickSort(arr)); // 输出 [ -10, 1, 1, 5, 10, 34 ] 52 | -------------------------------------------------------------------------------- /js/random_string.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-02 19:38:45 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-02 19:51:36 6 | */ 7 | 8 | /** 9 | * 10 | * 实现一个randomString函数,返回一个数组, 该数组内有一千个字符串, 每串字符串为6位数0-9的随机验证码,不可重复? 11 | * 12 | */ 13 | 14 | const randomString = (length) => { 15 | let data = []; 16 | let map = {}; 17 | 18 | for (let i = 0; i < length; i++) { 19 | let num = Math.random().toString().slice(2, 8); 20 | 21 | while (map[num]) { 22 | // 当 map 里面存在当前字符串时,重新赋值 num 23 | num = Math.random().toString().slice(2, 8); 24 | } 25 | 26 | // 将随机字符串存入 map 中,方便后续判断该字符串是否存在 27 | map[num] = true; 28 | data.push(num); 29 | } 30 | 31 | return data; 32 | }; 33 | 34 | const result = randomString(10); 35 | console.log(result); 36 | -------------------------------------------------------------------------------- /js/reduce_map.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-06 17:15:45 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-06 19:52:19 6 | */ 7 | 8 | /** 9 | * map: 遍历数组的每一项,并执行回调函数的操作,返回一个对每一项进行操作后的新数组。 10 | * 11 | * reduce: 对数组累积执行回调函数,返回最终计算结果。 12 | * 13 | * @param {*} callback 14 | * @param {*} ctx 15 | * @returns 16 | * 17 | */ 18 | Array.prototype.map2 = function (callback, ctx = null) { 19 | if (typeof callback !== "function") { 20 | throw new Error("callback must be a function"); 21 | } 22 | 23 | return this.reduce( 24 | (result, cur, index, array) => 25 | result.concat(callback.call(ctx, cur, index, array)), 26 | [] 27 | ); 28 | }; 29 | 30 | let arr = [1, 2]; 31 | let arr1 = arr.map2( 32 | function (it, i, array) { 33 | console.log(it, i, array, this); 34 | return it * 2; 35 | }, 36 | { name: "Chacha" } 37 | ); 38 | 39 | console.log("===================================="); 40 | console.log(arr1); 41 | console.log("===================================="); 42 | -------------------------------------------------------------------------------- /js/request_retry.js: -------------------------------------------------------------------------------- 1 | function requestWithRetry1(url, attempts = 3) { 2 | return new Promise(function (resolve, reject) { 3 | fetch(url) 4 | .then(function (result) { 5 | resolve(result); 6 | }) 7 | .catch(function (error) { 8 | attempts--; // 2, 1, 0 9 | 10 | if (attempts === 0) { 11 | reject(error); 12 | } else { 13 | setTimeout(() => { 14 | requestWithRetry1(url, attempts); 15 | }, 3000); 16 | } 17 | }); 18 | }); 19 | } 20 | 21 | async function requestWithRetry2(url, attempts = 3) { 22 | const retry = async (attempt = 1) => { 23 | try { 24 | return await fetch(url); 25 | } catch (error) { 26 | if (attempt >= attempts) { 27 | throw error; 28 | } 29 | 30 | // Use an increasing delay to prevent flodding the 31 | // server with requests in case of a short downtime. 32 | const delay = 1000 * attempt; 33 | 34 | return new Promise((resolve) => 35 | setTimeout(() => resolve(retry(attempt + 1)), delay) 36 | ); 37 | } 38 | }; 39 | 40 | return retry; 41 | } 42 | -------------------------------------------------------------------------------- /js/reverse_integer.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-02 22:32:27 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-07 17:50:19 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/problems/reverse-integer/ 10 | * 11 | * 整数反转 12 | * 给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。 13 | * 如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。 14 | * 假设环境不允许存储 64 位整数(有符号或无符号)。 15 | * 16 | * 示例 1: 17 | * 输入:x = 123 18 | * 输出:321 19 | * 20 | * 示例 2: 21 | * 输入:x = -123 22 | * 输出:-321 23 | * 24 | * 示例 3: 25 | * 输入:x = 120 26 | * 输出:21 27 | * 28 | * 示例 4: 29 | * 输入:x = 0 30 | * 输出:0 31 | * 32 | */ 33 | 34 | /** 35 | * @param {number} num 36 | * @returns {number} 37 | */ 38 | const reverseNum = (num) => { 39 | let result = 0; 40 | 41 | while (num != 0) { 42 | result = result * 10 + (num % 10); 43 | 44 | if (result > Infinity || result < -Infinity) return 0; 45 | 46 | // ~~会把后面的表达式强行变成int 47 | num = ~~(num / 10); 48 | } 49 | 50 | return result; 51 | }; 52 | 53 | console.log("x = 123, 反转之后", reverseNum(123)); // 321 54 | console.log("x = -123, 反转之后", reverseNum(-123)); // -321 55 | console.log("x = 120, 反转之后", reverseNum(120)); // 21 56 | console.log("x = 0, 反转之后", reverseNum(0)); // 0 57 | -------------------------------------------------------------------------------- /js/scheduler.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-26 16:18:26 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-26 16:25:18 6 | */ 7 | 8 | /** 9 | * JS实现一个带并发限制的异步调度器Scheduler,保证同时运行的任务最多有两个。完善下面代码的Scheduler类,使以下程序能够正常输出: 10 | * class Scheduler { 11 | * add(promiseCreator) { ... } 12 | * // ... 13 | * } 14 | * 15 | * const timeout = time => { 16 | * return new Promise(resolve => { 17 | * setTimeout(resolve, time) 18 | * } 19 | * }) 20 | * 21 | * const scheduler = new Scheduler() 22 | * 23 | * const addTask = (time,order) => { 24 | * scheduler.add(() => timeout(time).then(()=>console.log(order))) 25 | * } 26 | * 27 | * addTask(1000, '1') 28 | * addTask(500, '2') 29 | * addTask(300, '3') 30 | * addTask(400, '4') 31 | * // output: 2 3 1 4 32 | * 33 | * 整个的完整执行流程: 34 | * 起始1、2两个任务开始执行 35 | * 500ms时,2任务执行完毕,输出2,任务3开始执行 36 | * 800ms时,3任务执行完毕,输出3,任务4开始执行 37 | * 1000ms时,1任务执行完毕,输出1,此时只剩下4任务在执行 38 | * 1200ms时,4任务执行完毕,输出4 39 | * 40 | */ 41 | 42 | class Scheduler { 43 | constructor() { 44 | this.queue = []; // 任务列表 45 | this.capacity = 2; // 任务队列容量 46 | this.runCount = 0; // 运行任务计数器 47 | } 48 | 49 | add(promiseCreator) { 50 | // 小于等于2,直接执行 51 | this.queue.push(promiseCreator); 52 | this.runQueue(); 53 | } 54 | 55 | runQueue() { 56 | // 队列中还有任务才会被执行 57 | if (this.queue.length && this.runCount < this.capacity) { 58 | // 执行先加入队列的函数 59 | const promiseCreator = this.queue.shift(); 60 | // 开始执行任务 计数+1 61 | this.runCount += 1; 62 | 63 | promiseCreator().then(() => { 64 | // 任务执行完毕,计数-1 65 | this.runCount -= 1; 66 | this.runQueue(); 67 | }); 68 | } 69 | } 70 | } 71 | 72 | const timeout = (time) => { 73 | return new Promise((resolve) => { 74 | setTimeout(resolve, time); 75 | }); 76 | }; 77 | 78 | const scheduler = new Scheduler(); 79 | 80 | const addTask = (time, order) => { 81 | scheduler.add(() => timeout(time).then(() => console.log(order))); 82 | }; 83 | 84 | addTask(1000, "1"); 85 | addTask(500, "2"); 86 | addTask(300, "3"); 87 | addTask(400, "4"); 88 | 89 | // 控制台输出 2 3 1 4 90 | -------------------------------------------------------------------------------- /js/select_sort.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-03 23:25:18 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-03 23:33:11 6 | */ 7 | 8 | /** 9 | * 选择排序 10 | * 11 | * 排序步骤: 12 | * 1. 取出未排序部分的第一个元素,遍历该元素之后的部分并比较大小。对于第一次遍历,就是取出第一个元素 13 | * 2. 如果有更小的,与该元素交换位置 14 | * 3. 每次遍历都能找出剩余元素中的最小值并放在已排序部分的最后 15 | * 16 | */ 17 | 18 | /** 19 | * 20 | * @param {[]} arr 数组 21 | * @param {number} a 下标 a 22 | * @param {number} b 下标 b 23 | * @returns {[]} 24 | */ 25 | const swap = (arr, a, b) => ([arr[b], arr[a]] = [arr[a], arr[b]]); 26 | 27 | const selectSort = (arr) => { 28 | const length = arr.length; 29 | 30 | for (let i = 0; i < length; i++) { 31 | let minIndex = i; 32 | 33 | for (let j = i + 1; j < length; j++) { 34 | if (arr[j] < arr[minIndex]) { 35 | minIndex = j; 36 | } 37 | } 38 | 39 | if (minIndex !== i) { 40 | swap(arr, i, minIndex); 41 | } 42 | } 43 | 44 | return arr; 45 | }; 46 | 47 | console.log(selectSort([-1, 10, 10, 2])); 48 | -------------------------------------------------------------------------------- /js/setTimeout-interval.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-23 23:33:55 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-23 23:34:16 6 | */ 7 | 8 | const simulateSetInterval = (func, timeout) => { 9 | let timer = null; 10 | 11 | const interval = () => { 12 | timer = setTimeout(() => { 13 | func(); 14 | interval(); 15 | }, timeout); 16 | }; 17 | 18 | interval(); 19 | 20 | return () => clearTimeout(timer); 21 | }; 22 | 23 | const cancel = simulateSetInterval(() => { 24 | console.log(1); 25 | }, 300); 26 | 27 | setTimeout(() => { 28 | cancel(); 29 | }, 1000); 30 | -------------------------------------------------------------------------------- /js/shallow_copy.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-22 13:46:02 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-22 13:52:51 6 | */ 7 | 8 | // Q1: 实现一个非原生类的浅拷贝函数 9 | function shallowCopy(obj) { 10 | let data = Object.create(null); 11 | 12 | for (const key in obj) { 13 | if (Object.hasOwnProperty.call(obj, key)) { 14 | data[key] = obj[key]; 15 | } 16 | } 17 | 18 | // 将对象 obj 的原型对象设置给 data 19 | return Object.setPrototypeOf(data, Object.getPrototypeOf(obj)); 20 | } 21 | 22 | class UserModel { 23 | firstName; 24 | lastName; 25 | 26 | constructor(firstName, lastName) { 27 | this.firstName = firstName; 28 | this.lastName = lastName; 29 | } 30 | 31 | fullName() { 32 | return this.firstName + " " + this.lastName; 33 | } 34 | } 35 | 36 | const user = new UserModel("Hello", "Chacha"); 37 | const user2 = shallowCopy(user); 38 | 39 | user2.firstName = "Hello 1"; 40 | user2.lastName = "Chacha 1"; 41 | 42 | console.log("===================================="); 43 | console.log(user, user2); 44 | console.log("===================================="); 45 | 46 | console.assert(user2 instanceof UserModel); 47 | console.assert(user.fullName() === "Hello Chacha"); 48 | console.assert(user2.fullName() === "Hello 1 Chacha 1"); 49 | -------------------------------------------------------------------------------- /js/single_number.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-07 13:44:05 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-07 14:08:25 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/problems/single-number 10 | * 11 | * 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 12 | * 13 | * 说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? 14 | * 15 | * 示例 1: 16 | * 输入: [2,2,1] 17 | * 输出: 1 18 | * 19 | * 示例 2: 20 | * 输入: [4,1,2,1,2] 21 | * 输出: 4 22 | * 23 | */ 24 | 25 | // 异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同为0,异为1) 26 | const singleNumber = (nums) => { 27 | let ans = 0; 28 | 29 | for (const num of nums) { 30 | // 异或计算 31 | ans = ans ^ num; 32 | } 33 | 34 | return ans; 35 | }; 36 | 37 | console.log(singleNumber([2, 2, 1])); 38 | console.log(singleNumber([4, 1, 2, 1, 2])); 39 | -------------------------------------------------------------------------------- /js/str_str.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-02 20:14:54 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-02 20:24:39 6 | */ 7 | 8 | /** 9 | * 实现 strStr() 函数。 10 | * 11 | * 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。 12 | * 13 | * 说明: 14 | * 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 15 | * 对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。 16 | * 17 | * 示例 1: 18 | * 输入:haystack = "hello", needle = "ll" 19 | * 输出:2 20 | * 21 | * 示例 2: 22 | * 输入:haystack = "aaaaa", needle = "bba" 23 | * 输出:-1 24 | * 25 | * 示例 3: 26 | * 输入:haystack = "", needle = "" 27 | * 输出:0 28 | * 29 | * 来源:力扣(LeetCode) 30 | * 链接:https://leetcode-cn.com/problems/implement-strstr 31 | * 32 | */ 33 | 34 | const strStr = (haystack, needle) => { 35 | const l1 = haystack.length; 36 | const l2 = needle.length; 37 | let i = 0; 38 | 39 | while (i < l1) { 40 | const value = haystack.substr(i, l2); 41 | 42 | console.log(value); 43 | 44 | if (value == needle) { 45 | return i; 46 | } 47 | 48 | i++; 49 | } 50 | 51 | return -1; 52 | }; 53 | 54 | const haystack = "hello"; 55 | const haystack1 = "aaaaa"; 56 | const haystack2 = "aabaabaafa"; 57 | const needle = "ll"; 58 | const needle1 = "bba"; 59 | const needle2 = "aabaaf"; 60 | 61 | console.log(strStr(haystack, needle)); // 2 62 | console.log(strStr(haystack1, needle1)); // -1 63 | console.log(strStr(haystack2, needle2)); // 3 64 | -------------------------------------------------------------------------------- /js/throttle.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-30 18:35:01 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-30 19:16:06 6 | */ 7 | 8 | /** 9 | * 节流(Throttle) 10 | * 11 | */ 12 | 13 | const throttle = function (func, delay) { 14 | let startTime = Date.now(); 15 | 16 | return function (...args) { 17 | let lastTime = Date.now(); 18 | 19 | if (lastTime - startTime > delay) { 20 | func.apply(this, args); 21 | startTime = Date.now(); 22 | } 23 | }; 24 | }; 25 | 26 | const throttle2 = function (func, delay) { 27 | let timer = null; 28 | 29 | return function (...args) { 30 | if (!timer) { 31 | timer = setTimeout(() => { 32 | func.apply(this, args); 33 | timer = null; 34 | }, delay); 35 | } 36 | }; 37 | }; 38 | 39 | let t1 = Date.now(); 40 | 41 | const showName = throttle2(function (name) { 42 | const t2 = Date.now(); 43 | console.log(this, name, t2 - t1); 44 | t1 = Date.now(); 45 | }, 2000); 46 | 47 | setInterval(() => { 48 | showName.call({ name: "Hello Chacha" }, "Hello Chacha"); 49 | }, 10); 50 | -------------------------------------------------------------------------------- /js/tree_to_list.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-09 23:25:02 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-09 23:25:25 6 | */ 7 | 8 | /** 9 | * 10 | [ 11 | { 12 | "id": 1, 13 | "name": "部门1", 14 | "pid": 0, 15 | "children": [ 16 | { 17 | "id": 2, 18 | "name": "部门2", 19 | "pid": 1, 20 | "children": [] 21 | }, 22 | { 23 | "id": 3, 24 | "name": "部门3", 25 | "pid": 1, 26 | "children": [ 27 | { 28 | "id": 4, 29 | "name": "部门4", 30 | "pid": 3, 31 | "children": [ 32 | { 33 | "id": 5, 34 | "name": "部门5", 35 | "pid": 4, 36 | "children": [] 37 | } 38 | ] 39 | } 40 | ] 41 | } 42 | ] 43 | } 44 | ] 45 | => 46 | [ 47 | {id: 1, name: '部门1', pid: 0}, 48 | {id: 2, name: '部门2', pid: 1}, 49 | {id: 3, name: '部门3', pid: 1}, 50 | {id: 4, name: '部门4', pid: 3}, 51 | {id: 5, name: '部门5', pid: 4}, 52 | ] 53 | * 54 | */ 55 | 56 | const tree2list = (tree) => { 57 | let list = []; 58 | let queue = [...tree]; 59 | 60 | while (queue.length) { 61 | // 从前面开始取出节点 62 | const node = queue.shift(); 63 | const children = node.children; 64 | 65 | if (children.length) { 66 | queue.push(...children); 67 | } 68 | // 删除多余的children树形 69 | delete node.children; 70 | 71 | list.push(node); 72 | } 73 | 74 | return list; 75 | }; 76 | 77 | const data = [ 78 | { 79 | id: 1, 80 | name: "部门1", 81 | pid: 0, 82 | children: [ 83 | { 84 | id: 2, 85 | name: "部门2", 86 | pid: 1, 87 | children: [], 88 | }, 89 | { 90 | id: 3, 91 | name: "部门3", 92 | pid: 1, 93 | children: [ 94 | { 95 | id: 4, 96 | name: "部门4", 97 | pid: 3, 98 | children: [ 99 | { 100 | id: 5, 101 | name: "部门5", 102 | pid: 4, 103 | children: [], 104 | }, 105 | ], 106 | }, 107 | ], 108 | }, 109 | ], 110 | }, 111 | ]; 112 | 113 | console.log(tree2list(data)); 114 | -------------------------------------------------------------------------------- /js/trim.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-11 14:31:57 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-11 15:40:45 6 | */ 7 | 8 | /** 9 | * JS 实现 trim 函数 10 | */ 11 | 12 | String.prototype.trim1 = function () { 13 | return this.replace(/^\s\s*/, "").replace(/^\s\s*$/, ""); 14 | }; 15 | 16 | String.prototype.trim2 = function () { 17 | var str = this; 18 | 19 | whitespace = 20 | " \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000"; 21 | 22 | for (let i = 0, len = str.length; i < len; i++) { 23 | if (whitespace.indexOf(str.charAt(i)) === -1) { 24 | str = str.substring(i); 25 | break; 26 | } 27 | } 28 | 29 | for (let i = str.length - 1; i >= 0; i--) { 30 | if (whitespace.indexOf(str.charAt(i)) === -1) { 31 | str = str.substring(0, i + 1); 32 | break; 33 | } 34 | } 35 | 36 | return whitespace.indexOf(str.charAt(0)) === -1 ? str : ""; 37 | }; 38 | 39 | let hello = " hello world "; 40 | 41 | console.log(hello); 42 | console.log("Trim result is", hello.trim1()); 43 | console.log("Trim result is", hello.trim2()); 44 | -------------------------------------------------------------------------------- /js/unique_array.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-08 11:30:09 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-08 15:46:10 6 | */ 7 | 8 | // 1. 最简短方便的方式 9 | const uniqueArray1 = (array) => { 10 | return [...new Set(array)]; 11 | }; 12 | 13 | // 2. indexOf去重 14 | const uniqueArray2 = (array) => { 15 | let result = []; 16 | 17 | array.forEach((it, i) => { 18 | if (result.indexOf(it) === -1) { 19 | result.push(it); 20 | } 21 | }); 22 | 23 | return result; 24 | }; 25 | 26 | // 3. indexOf去重另一个版本 27 | const uniqueArray3 = (array) => { 28 | return array.filter((it, i) => array.indexOf(it) === i); 29 | }; 30 | 31 | // 4. Array.from去重 32 | const uniqueArray4 = (array) => { 33 | return Array.from(new Set(array)); 34 | }; 35 | 36 | let testArray = [1, 2, 3, 1, 2, 3, 4]; 37 | 38 | console.log(uniqueArray1(testArray)); 39 | console.log(uniqueArray2(testArray)); 40 | console.log(uniqueArray3(testArray)); 41 | console.log(uniqueArray4(testArray)); 42 | -------------------------------------------------------------------------------- /js/valid_palindrome.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-28 10:26:36 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-28 10:37:28 6 | */ 7 | 8 | /** 9 | * 验证回文字符串 https://leetcode-cn.com/problems/valid-palindrome/ 10 | * 11 | * 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。 12 | * 说明:本题中,我们将空字符串定义为有效的回文串。 13 | * 14 | * 示例 1: 15 | * 输入: "A man, a plan, a canal: Panama" 16 | * 输出: true 17 | * 解释:"amanaplanacanalpanama" 是回文串 18 | * 19 | * 示例 1: 20 | * 输入: "race a car" 21 | * 输出: false 22 | * 解释:"raceacar" 不是回文串 23 | * 24 | */ 25 | 26 | function isPalindrome(str) { 27 | str = str.replace(/[^a-zA-Z\d]/g, "").toLowerCase(); 28 | const len = str.length; 29 | let i = 0; 30 | 31 | console.log("===================================="); 32 | console.log(str); 33 | console.log("===================================="); 34 | 35 | while (i < len / 2) { 36 | if (str[i] !== str[len - 1 - i]) { 37 | return false; 38 | } 39 | i++; 40 | } 41 | 42 | return true; 43 | } 44 | 45 | const str = "A man, a plan, a canal: Panama"; 46 | const str1 = "race a car"; 47 | 48 | console.log("===================================="); 49 | console.log("str 是否是回文串:", isPalindrome(str)); 50 | console.log("===================================="); 51 | 52 | console.log("===================================="); 53 | console.log("str1 是否是回文串:", isPalindrome(str1)); 54 | console.log("===================================="); 55 | -------------------------------------------------------------------------------- /js/valid_palindrome_ii.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-05 10:48:06 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-05 10:54:20 6 | */ 7 | 8 | /** 9 | * 10 | * 来源:https://leetcode-cn.com/problems/valid-palindrome-ii/ 11 | * 12 | * 680. 验证回文字符串 13 | * 给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。 14 | * 15 | * 示例 1: 16 | * 输入: s = "aba" 17 | * 输出: true 18 | * 19 | * 示例 2: 20 | * 输入: s = "abca" 21 | * 输出: true 22 | * 解释: 你可以删除c字符。 23 | * 24 | * 示例 3: 25 | * 输入: s = "abc" 26 | * 输出: false 27 | * 28 | */ 29 | 30 | const validPalindrome = (s) => { 31 | const isPalindrome = (start, end) => { 32 | while (start < end) { 33 | if (s[start] !== s[end]) { 34 | return false; 35 | } 36 | 37 | start++; 38 | end--; 39 | } 40 | 41 | return true; 42 | }; 43 | 44 | let i = 0; // 头指针 45 | let j = s.length - 1; // 尾指针 46 | 47 | while (i < j && s[i] === s[j]) { 48 | i++; 49 | j--; 50 | } 51 | 52 | if (isPalindrome(i + 1, j)) { 53 | return true; 54 | } 55 | 56 | if (isPalindrome(i, j - 1)) { 57 | return true; 58 | } 59 | 60 | return false; 61 | }; 62 | 63 | console.log(validPalindrome("aba")); 64 | console.log(validPalindrome("abca")); 65 | console.log(validPalindrome("abc")); 66 | console.log(validPalindrome("deeee")); 67 | -------------------------------------------------------------------------------- /leetcode/array/evaluate_reverse_polish_notation: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/array/evaluate_reverse_polish_notation -------------------------------------------------------------------------------- /leetcode/array/find_minimum_in_rotated_sorted: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/array/find_minimum_in_rotated_sorted -------------------------------------------------------------------------------- /leetcode/array/find_peak_element: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/array/find_peak_element -------------------------------------------------------------------------------- /leetcode/array/find_pivot_index: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/array/find_pivot_index -------------------------------------------------------------------------------- /leetcode/array/find_pivot_index.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2018-12-28 18:05:11 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-08 10:57:34 6 | */ 7 | 8 | /** 9 | * 给你一个整数数组 nums,请编写一个能够返回数组 “中心下标” 的方法。数组 中心下标 是数组的一个下标, 10 | * 其左侧所有元素相加的和等于右侧所有元素相加的和。如果数组不存在中心下标,返回 -1 。 11 | * 如果数组有多个中心下标,应该返回最靠近左边的那一个。 12 | * 13 | * 注意:中心下标可能出现在数组的两端。 14 | * 15 | * 示例: 16 | * 输入: nums = [1, 7, 3, 6, 5, 6] 17 | * 输出: 3 18 | * 19 | * 解释: 20 | * 左侧数之和 (1 + 7 + 3 = 11),右侧数之和 (5 + 6 = 11) ,二者相等。 21 | * 22 | * Note: 23 | * 1. nums 的长度范围为 [0, 10000] 24 | * 2. 任何一个 nums[i] 将会是一个范围在 [-1000, 1000]的整数 25 | * 26 | * 来源: https://leetcode-cn.com/problems/find-pivot-index/ 27 | */ 28 | 29 | #include 30 | #include 31 | 32 | using namespace std; 33 | 34 | /** 35 | * 题解: 36 | * 计算出全部数组的和,当遍历到第i个元素时,设其左侧元素之和为sum,则其右侧元素之和为 total - nums[i] - sum。 37 | * 左右侧元素相等即为 sum = total - nums[i] - sum,即 2 x sum + nums[i] = total。 38 | * 39 | * 当中心索引左侧或右侧没有元素时,即为零个项相加,这在数学上称作「空和」(empty sum)。在程序设计中我们约定「空和是零」。 40 | * 41 | * 复杂度: 42 | * 时间复杂度:O(n),其中 n 为数组的长度 43 | * 空间复杂度:O(1) 44 | * 45 | */ 46 | int pivotIndex(vector &nums) 47 | { 48 | int total = 0; 49 | 50 | for (int num : nums) 51 | total += num; 52 | 53 | int sum = 0; 54 | for (int i = 0; i < nums.size(); sum += nums[i++]) 55 | { 56 | if (sum * 2 == total - nums[i]) 57 | return i; 58 | } 59 | 60 | return -1; 61 | } 62 | 63 | int main() 64 | { 65 | int arr[] = {1, 7, 3, 6, 5, 6}; 66 | vector nums(arr, arr + sizeof(arr) / sizeof(int)); 67 | 68 | int result = pivotIndex(nums); 69 | 70 | cout << "Result is " << result << endl; 71 | } 72 | -------------------------------------------------------------------------------- /leetcode/array/kth_largest_element: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/array/kth_largest_element -------------------------------------------------------------------------------- /leetcode/array/kth_largest_element.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/array/kth_largest_element.xmind -------------------------------------------------------------------------------- /leetcode/array/median_of_two_sorted_arrays: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/array/median_of_two_sorted_arrays -------------------------------------------------------------------------------- /leetcode/array/remove_duplicates_from_sorted_array: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/array/remove_duplicates_from_sorted_array -------------------------------------------------------------------------------- /leetcode/array/remove_element: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/array/remove_element -------------------------------------------------------------------------------- /leetcode/array/remove_element.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2018-12-27 23:20:14 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2021-03-26 18:13:16 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | /*********************************************************************************** 14 | * Given an array nums and a value val, remove all instances of that value in-place and return the new length. 15 | * Do not allocate extra space for another array, you must do this by modifying 16 | * the input array in-place with O(1) extra memory. The order of elements can be changed. 17 | * It doesn't matter what you leave beyond the new length. 18 | * 19 | * Example 1: 20 | * Given nums = [3,2,2,3], val = 3, 21 | * Your function should return length = 2, with the first two elements of nums being 2. 22 | * It doesn't matter what you leave beyond the returned length. 23 | * 24 | * Example 2: 25 | * Given nums = [0,1,2,2,3,0,4,2], val = 2, 26 | * Your function should return length = 5, with the first five elements 27 | * of nums containing 0, 1, 3, 0, and 4. 28 | * Note that the order of those five elements can be arbitrary. 29 | * It doesn't matter what values are set beyond the returned length. 30 | * 31 | * Source: https://leetcode.com/problems/remove-element/ 32 | * 33 | ************************************************************************************/ 34 | 35 | int removeElement(vector &nums, int val) 36 | { 37 | 38 | vector::iterator iter = nums.begin(); 39 | 40 | for (; iter < nums.end(); ++iter) 41 | { 42 | if (*iter == val) 43 | { 44 | iter = nums.erase(iter); 45 | --iter; 46 | } 47 | } 48 | 49 | return nums.size(); 50 | } 51 | 52 | int main() 53 | { 54 | int arr[] = {0, 0, 1, 1, 1, 1, 2, 3, 3}; 55 | vector nums(arr, arr + sizeof(arr) / sizeof(int)); 56 | 57 | int result = removeElement(nums, 1); 58 | 59 | cout << "Result is " << result << endl; 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /leetcode/array/squares-of-a-sorted-array: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/array/squares-of-a-sorted-array -------------------------------------------------------------------------------- /leetcode/array/squares-of-a-sorted-array.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-07-24 22:29:36 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-07-24 23:08:35 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode.cn/problems/squares-of-a-sorted-array/ 10 | * 11 | * 977. 有序数组的平方 12 | * 13 | * 给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。 14 | * 15 | * 示例 1: 16 | * 输入:nums = [-4,-1,0,3,10] 17 | * 输出:[0,1,9,16,100] 18 | * 解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100] 19 | * 20 | * 示例 2: 21 | * 输入:nums = [-7,-3,2,3,11] 22 | * 输出:[4,9,9,49,121] 23 | * 24 | * 提示: 25 | * 1. 1 <= tokens.length <= 10^4 26 | * 2. -10^4 <= nums[i] <= 10^4 27 | * 3. nums 已按 非递减顺序 排序 28 | * 29 | */ 30 | 31 | #include 32 | #include 33 | 34 | using namespace std; 35 | 36 | class Solution 37 | { 38 | private: 39 | /* data */ 40 | public: 41 | vector sortSquares(vector &nums); 42 | }; 43 | 44 | /** 45 | * 方法:双指针法 46 | * 47 | * 数组其实是有序的,只不过负数平方之后可能成为最大数了,那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。 48 | * 此时可以考虑双指针法了,i指向起始位置,j指向终止位置。定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。 49 | * 如果A[i] * A[i] < A[j] * A[j] 那么result[k--] = A[j] * A[j]; 50 | * 如果A[i] * A[i] >= A[j] * A[j] 那么result[k--] = A[i] * A[i]; 51 | * 52 | */ 53 | vector Solution::sortSquares(vector &nums) 54 | { 55 | int k = nums.size() - 1; 56 | vector result(nums.size(), 0); 57 | 58 | for (int i = 0, j = nums.size() - 1; i <= j;) 59 | { 60 | // 注意这里要i <= j,因为最后要处理两个元素 61 | if (nums[i] * nums[i] < nums[j] * nums[j]) 62 | { 63 | result[k--] = nums[j] * nums[j]; 64 | j--; 65 | } 66 | else 67 | { 68 | result[k--] = nums[i] * nums[i]; 69 | i++; 70 | } 71 | } 72 | 73 | return result; 74 | } 75 | 76 | void printVector(vector &vec) 77 | { 78 | for (int i = 0; i < vec.size(); i++) 79 | { 80 | printf("%3d ", vec[i]); 81 | } 82 | cout << endl; 83 | } 84 | 85 | int main(int argc, char const *argv[]) 86 | { 87 | Solution s; 88 | 89 | vector nums = {-4, -1, 0, 3, 10}; 90 | vector _nums = s.sortSquares(nums); 91 | 92 | cout << "nums = [-4, -1, 0, 3, 10], 运算结果为: " << endl; 93 | 94 | printVector(_nums); 95 | 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /leetcode/array/two_sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/array/two_sum -------------------------------------------------------------------------------- /leetcode/array/two_sum.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2018-11-24 12:10:01 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-13 17:05:57 6 | */ 7 | 8 | /** 9 | * 1. 两数之和 10 | * 11 | * 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回它们的数组下标。 12 | * 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。 13 | * 14 | * 示例: 15 | * 给定 nums = [2, 7, 11, 15], target = 9, 16 | * 因为 nums[0] + nums[1] = 2 + 7 = 9, 17 | * 返回 [0, 1]. 18 | * 19 | * 来源:https://leetcode-cn.com/problems/two-sum/ 20 | * 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | using namespace std; 29 | 30 | /** 31 | * 方法一 32 | * 暴力枚举,枚举数组中的每一个数 x,寻找数组中是否存在 target - x。当我们使用遍历整个数组的方式寻找target - x时, 33 | * 需要注意到每一个位于 x 之前到元素都已经和 x 匹配过。而每一个元素不能被使用两次, 34 | * 所以我们只需要在 x 后面的元素中寻找 target - x。 35 | * 36 | * 复杂度: 37 | * 时间复杂度:O(N^2),其中 N 是数组中的元素数量。最坏情况下数组中任意两个数都要被匹配一次。 38 | * 空间复杂度:O(1) 39 | * 40 | */ 41 | vector twoSum1(vector &nums, int target) 42 | { 43 | int n = nums.size(); 44 | vector result(0); 45 | 46 | for (int i = 0; i < n - 1; i++) 47 | { 48 | for (int j = i + 1; j < n; j++) 49 | { 50 | if (nums[i] + nums[j] == target) 51 | { 52 | cout << "i " << i << endl; 53 | cout << "j " << j << endl; 54 | result.push_back(i); 55 | result.push_back(j); 56 | return result; 57 | } 58 | } 59 | } 60 | 61 | return result; 62 | } 63 | 64 | /** 65 | * 方法二 66 | * 哈希表,方法一的时间复杂度较高的原因是寻找 target - x 的时间复杂度过高, 67 | * 所以我们可以使用哈希表将 寻找 target - x 的时间复杂度从 O(N^2) 降低到 O(1)。 68 | * 我们创建一个哈希表,对于每一个 x, 我们首先查询哈希表中是否存在 target - x,然后将 x 插入到哈希表中, 69 | * 即保证不会让 x 和自己匹配。 70 | * 71 | * 复杂度: 72 | * 时间复杂度:O(N),其中 N 是数组正宗到元素数量。对于每一个元素 x,我们可以 O(1) 地寻找 target - x。 73 | * 空间复杂度:O(N),主要为哈希表的开销。 74 | * 75 | */ 76 | vector twoSum2(vector &nums, int target) 77 | { 78 | // Key is the number and value is its index in the vector. 79 | unordered_map hash; 80 | vector result; 81 | 82 | for (int i = 0; i < nums.size(); i++) 83 | { 84 | int number = target - nums[i]; 85 | 86 | // if number is found in map, return them 87 | if (hash.find(number) != hash.end()) 88 | { 89 | result.push_back(hash[number]); 90 | result.push_back(i); 91 | return result; 92 | } 93 | 94 | hash[nums[i]] = i; 95 | } 96 | 97 | return result; 98 | } 99 | 100 | void printVector(vector &vec) 101 | { 102 | for (int i = 0; i < vec.size(); i++) 103 | { 104 | printf("%3d", vec[i]); 105 | } 106 | cout << endl; 107 | } 108 | 109 | int main() 110 | { 111 | /* code */ 112 | int arr[] = {2, 7, 11, 15}; 113 | vector nums(arr, arr + sizeof(arr) / sizeof(int)); 114 | vector result = twoSum1(nums, 9); 115 | 116 | printVector(result); 117 | } 118 | -------------------------------------------------------------------------------- /leetcode/backtracking/回溯算法.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/backtracking/回溯算法.png -------------------------------------------------------------------------------- /leetcode/backtracking/回溯算法.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/backtracking/回溯算法.xmind -------------------------------------------------------------------------------- /leetcode/binary_search/binary_search: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/binary_search/binary_search -------------------------------------------------------------------------------- /leetcode/binary_search/search_in_rotated_sorted_array: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/binary_search/search_in_rotated_sorted_array -------------------------------------------------------------------------------- /leetcode/binary_search/search_matrix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/binary_search/search_matrix -------------------------------------------------------------------------------- /leetcode/binary_search/sqrt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/binary_search/sqrt -------------------------------------------------------------------------------- /leetcode/binary_search/sqrt.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2018-11-26 11:11:37 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2021-03-26 18:08:00 6 | */ 7 | 8 | /** 9 | * Implement int sqrt(int x). 10 | * Compute and return the square root of x, where x is guaranteed to be a non-negative integer. 11 | * Since the return type is an integer, the decimal digits are truncated 12 | * and only the integer part of the result is returned. 13 | * Source: https://leetcode.com/problems/sqrtx/ 14 | * 15 | * Example 1: 16 | * Input: 4 17 | * Output: 2 18 | * 19 | * Example 2: 20 | * Input: 8 21 | * Output: 2 22 | * Explanation: The square root of 8 is 2.82842..., and since the decimal part is truncated, 2 is returned. 23 | */ 24 | 25 | #include 26 | 27 | using namespace std; 28 | 29 | int sqrt(int x) 30 | { 31 | if (x < 0) 32 | { 33 | return -1; 34 | } 35 | else if (x == 0) 36 | { 37 | return 0; 38 | } 39 | 40 | long start = 1; 41 | long end = x; 42 | long mid; 43 | 44 | while (start + 1 < end) 45 | { 46 | mid = start + (end - start) / 2; 47 | 48 | if (mid * mid == x) 49 | { 50 | return mid; 51 | } 52 | else if (mid * mid > x) 53 | { 54 | end = mid; 55 | } 56 | else 57 | { 58 | start = mid; 59 | } 60 | } 61 | 62 | return start; 63 | } 64 | 65 | // Babylonian method for finding square roots 66 | int sqrtByBabylonian(int x) 67 | { 68 | if (x == 0) 69 | { 70 | return 0; 71 | } 72 | 73 | double preSqrt, curSqrt = x, xFloat = x; 74 | 75 | while (true) 76 | { 77 | preSqrt = curSqrt; 78 | curSqrt = (curSqrt + xFloat / curSqrt) / 2; 79 | 80 | if (preSqrt == curSqrt) 81 | { 82 | return curSqrt; 83 | } 84 | } 85 | } 86 | 87 | int main() 88 | { 89 | int result1 = sqrt(8); 90 | int result2 = sqrtByBabylonian(10); 91 | cout << "Result1 is " << result1 << "\n"; 92 | cout << "Result2 is " << result2 << endl; 93 | } 94 | -------------------------------------------------------------------------------- /leetcode/binary_search_tree/search_range_in_BST.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2018-12-19 22:21:32 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-02 10:49:31 6 | */ 7 | 8 | /*********************************************************************************** 9 | * Given a binary search tree and a range [k1, k2], return all elements in the given range. 10 | * 11 | * Example: 12 | * If k1 = 10 and k2 = 22, then your function should return [12, 20, 22]. 13 | * 20 14 | * / \ 15 | * 8 22 16 | * / \ 17 | * 4 12 18 | * 19 | * Source: https://www.lintcode.com/problem/search-range-in-binary-search-tree/description 20 | ************************************************************************************/ 21 | 22 | #include 23 | #include 24 | 25 | using namespace std; 26 | 27 | /** 28 | * Definition for a binary tree node. 29 | */ 30 | struct TreeNode 31 | { 32 | int val; 33 | TreeNode *left; 34 | TreeNode *right; 35 | TreeNode(int x) : val(x), left(NULL), right(NULL) {} 36 | }; 37 | 38 | void inorder_defs(vector &ret, TreeNode *root, int k1, int k2) 39 | { 40 | 41 | if (root == NULL) 42 | { 43 | return; 44 | } 45 | 46 | inorder_defs(ret, root->left, k1, k2); 47 | 48 | if ((root->val >= k1) && (root->val <= k2)) 49 | { 50 | ret.push_back(root->val); 51 | } 52 | 53 | inorder_defs(ret, root->left, k1, k2); 54 | } 55 | 56 | vector searchRange(TreeNode *root, int k1, int k2) 57 | { 58 | vector result; 59 | inorder_defs(result, root, k1, k2); 60 | 61 | return result; 62 | } 63 | 64 | int main() 65 | { 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /leetcode/binary_search_tree/validate_binary_search_tree.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2018-12-09 21:54:02 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2021-03-26 18:05:21 6 | */ 7 | 8 | /*********************************************************************************** 9 | * Given a binary tree, determine if it is a valid binary search tree (BST). 10 | * Assume a BST is defined as follows: 11 | * 1. The left subtree of a node contains only nodes with keys less than the node's key. 12 | * 2. The right subtree of a node contains only nodes with keys greater than the node's key. 13 | * 3. Both the left and right subtrees must also be binary search trees. 14 | * 15 | * Example 1: 16 | * Input: 17 | * 2 18 | * / \ 19 | * 1 3 20 | * Output: true 21 | * 22 | * Example 2: 23 | * 5 24 | * / \ 25 | * 1 4 26 | * / \ 27 | * 3 6 28 | * Output: false 29 | * Explanation: The input is: [5,1,4,null,null,3,6]. The root node's value 30 | * is 5 but its right child's value is 4. 31 | * 32 | * Source: https://leetcode.com/problems/validate-binary-search-tree/ 33 | ************************************************************************************/ 34 | #include 35 | #include 36 | 37 | using namespace std; 38 | 39 | struct TreeNode 40 | { 41 | int val; 42 | TreeNode *left; 43 | TreeNode *right; 44 | TreeNode(int x) : val(x), left(NULL), right(NULL) {} 45 | }; 46 | 47 | int lastVal = INT_MIN; 48 | bool firstNode = true; 49 | 50 | // Preorder Traversal Ways 51 | int isValidBST1(TreeNode *root) 52 | { 53 | 54 | if (root == NULL) 55 | { 56 | return true; 57 | } 58 | 59 | if (!isValidBST1(root->left)) 60 | { 61 | return false; 62 | } 63 | 64 | if (!firstNode && lastVal >= root->val) 65 | { 66 | return false; 67 | } 68 | 69 | firstNode = false; 70 | lastVal = root->val; 71 | 72 | if (!isValidBST1(root->right)) 73 | { 74 | return false; 75 | } 76 | 77 | return true; 78 | } 79 | 80 | // Divide & Conquer 81 | int validateHelper(TreeNode *root, int lower, int upper) 82 | { 83 | 84 | if (root == NULL) 85 | { 86 | return true; 87 | } 88 | 89 | if (root->val <= lower || root->val >= upper) 90 | { 91 | bool right_max = root->val == INT_MAX && root->right == NULL; 92 | bool left_min = root->val == INT_MIN && root->left == NULL; 93 | 94 | if (!(right_max || left_min)) 95 | { 96 | return false; 97 | } 98 | } 99 | 100 | bool isLeftValidBST = validateHelper(root->left, lower, root->val); 101 | bool isRightValidBST = validateHelper(root->right, root->val, upper); 102 | 103 | return isLeftValidBST && isRightValidBST; 104 | } 105 | 106 | int isValidBST2(TreeNode *root) 107 | { 108 | 109 | if (root == NULL) 110 | return true; 111 | 112 | return validateHelper(root, INT_MIN, INT_MAX); 113 | } 114 | 115 | int main() 116 | { 117 | return 0; 118 | } 119 | -------------------------------------------------------------------------------- /leetcode/binary_tree/binary_tree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/binary_tree/binary_tree -------------------------------------------------------------------------------- /leetcode/binary_tree/binary_tree_level_order_traversal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/binary_tree/binary_tree_level_order_traversal -------------------------------------------------------------------------------- /leetcode/binary_tree/max_depth_binary_tree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/binary_tree/max_depth_binary_tree -------------------------------------------------------------------------------- /leetcode/binary_tree/maximum_depth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/binary_tree/maximum_depth -------------------------------------------------------------------------------- /leetcode/binary_tree/maximum_depth.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2019-02-16 13:26:00 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2019-02-16 18:30:38 6 | */ 7 | 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | struct TreeNode 13 | { 14 | int val; 15 | TreeNode *left; 16 | TreeNode *right; 17 | TreeNode(int x) : val(x), left(NULL), right(NULL) {} 18 | }; 19 | 20 | class Solution 21 | { 22 | public: 23 | int maxDepth(TreeNode *root) 24 | { 25 | if (root == NULL) 26 | return 0; 27 | 28 | queue q; 29 | q.push(root); 30 | 31 | int max_depth = 0; 32 | 33 | while (!q.empty()) 34 | { 35 | int size = q.size(); 36 | for (int i = 0; i < size; i++) 37 | { 38 | TreeNode *node = q.front(); 39 | q.pop(); 40 | 41 | if (node->left) 42 | { 43 | q.push(node->left); 44 | } 45 | 46 | if (node->right) 47 | { 48 | q.push(node->right); 49 | } 50 | } 51 | ++max_depth; 52 | } 53 | 54 | return max_depth; 55 | } 56 | }; 57 | 58 | int main() 59 | { 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /leetcode/binary_tree/path_sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/binary_tree/path_sum -------------------------------------------------------------------------------- /leetcode/binary_tree/path_sum.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2019-02-15 15:12:02 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-11 19:25:50 6 | */ 7 | 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | struct TreeNode 13 | { 14 | int val; 15 | TreeNode *left; 16 | TreeNode *right; 17 | TreeNode(int x) : val(x), left(NULL), right(NULL) {} 18 | }; 19 | 20 | class Solution 21 | { 22 | public: 23 | /** 24 | * Given a binary tree and a sum, determine if the tree has a root-to-leaf path such 25 | * that adding up all the values along the path equals the given sum. 26 | * 27 | * Example: 28 | * Given the below binary tree and sum = 22 29 | * 5 30 | / \ 31 | 4 8 32 | / / \ 33 | 11 13 4 34 | / \ \ 35 | 7 2 1 36 | 37 | * return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22. 38 | * 39 | * Source: 40 | * https://leetcode.com/problems/path-sum/ 41 | */ 42 | bool hasPathSum(TreeNode *root, int sum) 43 | { 44 | if (root == NULL) 45 | return false; 46 | if (root->val == sum && root->left == NULL && root->right == NULL) 47 | return true; 48 | return hasPathSum(root->left, sum - root->val) || hasPathSum(root->right, sum - root->val); 49 | } 50 | }; 51 | 52 | int main() 53 | { 54 | TreeNode *root = new TreeNode(5); 55 | TreeNode *n1 = new TreeNode(4); 56 | TreeNode *n2 = new TreeNode(8); 57 | TreeNode *n3 = new TreeNode(11); 58 | TreeNode *n4 = new TreeNode(13); 59 | TreeNode *n5 = new TreeNode(4); 60 | TreeNode *n6 = new TreeNode(7); 61 | TreeNode *n7 = new TreeNode(2); 62 | TreeNode *n8 = new TreeNode(1); 63 | 64 | root->left = n1; 65 | root->right = n2; 66 | n1->left = n3; 67 | n2->left = n4; 68 | n2->right = n5; 69 | n3->left = n6; 70 | n3->right = n7; 71 | n5->right = n8; 72 | 73 | Solution s; 74 | 75 | cout << "Has path sum " << s.hasPathSum(root, 21) << endl; 76 | cout << "Has path sum " << s.hasPathSum(root, 22) << endl; 77 | 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /leetcode/dynamic_programming/0_1_knapsack_problem.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-16 22:11:22 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-16 22:29:18 6 | */ 7 | /** 8 | * 来源:https://programmercarl.com/背包理论基础01背包-1.html#_01-背包 9 | * 10 | * 01 背包 11 | * 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。 12 | * 每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。 13 | * 14 | * 15 | * 16 | */ 17 | -------------------------------------------------------------------------------- /leetcode/dynamic_programming/dp_climb_stairs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/dynamic_programming/dp_climb_stairs -------------------------------------------------------------------------------- /leetcode/dynamic_programming/dp_climb_stairs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-01 17:19:41 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-02 16:07:52 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/problems/climbing-stairs/ 10 | * 11 | * 动态规划 - 爬楼梯 12 | * 13 | * 假设你正在爬楼梯。需要 n (1 <= n <= 45) 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 14 | * 15 | * 示例 1: 16 | * 输入:n = 2 17 | * 输出:2 18 | * 解释:有两种方法可以爬到楼顶。 19 | * 1. 1 阶 + 1 阶 20 | * 2. 2 阶 21 | * 22 | * 示例 2: 23 | * 输入:n = 3 24 | * 输出:3 25 | * 解释:有三种方法可以爬到楼顶。 26 | * 1. 1 阶 + 1 阶 + 1 阶 27 | * 2. 1 阶 + 2 阶 28 | * 3. 2 阶 + 1 阶 29 | * 30 | */ 31 | 32 | #include 33 | #include 34 | 35 | using namespace std; 36 | 37 | class Solution 38 | { 39 | private: 40 | /* data */ 41 | public: 42 | int climbStairs(int n); 43 | 44 | int climbStairs1(int n); 45 | 46 | int climbStairs2(int n); 47 | }; 48 | 49 | /** 50 | * 题解: 51 | * 爬到第一层楼梯有一种方法,爬到二层楼梯有两种方法。那么第一层楼梯再跨两步就到第三层,第二层楼梯再跨一步就到第三层。 52 | * 所以到第三层楼梯的状态可以由第二层楼梯和到第一层楼梯状态推导出来。 53 | * 54 | * 动态规划五部曲: 55 | * 定义一个一维数组来记录不同楼层的状态 56 | * 1. 确定dp数组以及下标的含义 57 | * dp[i]: 爬到第i层楼,有dp[i]种方法 58 | * 2. 确定递推公式 59 | * 从dp[i]的定义可以看出,dp[i]可以有两个方向推出来。首先是dp[i-1], 上 i-1 层楼梯,有d[i-1]种方法,那么再一步跳一个台阶就是dp[i]。 60 | * 还有就是dp[i-2],上 i-2 层楼梯,有dp[i-2]种方法,那么再一步跳两个台阶就是dp[i]。所以 dp[i] = dp[i-1] + dp[i-2]。 61 | * 3. dp数组初始化 62 | * dp[i]的定义:爬到第i层楼梯,有dp[i]种方法。 63 | * 因为 n >= 1,所以不考虑dp[0]的始化,只初始化dp[1] = 1,dp[2] = 2,然后从i = 3开始递推,这样才符合dp[i]的定义。 64 | * 4. 确定遍历顺序 65 | * 从递推公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,遍历顺序一定是从前向后遍历的 66 | * 5. 推导dp数组 67 | * 68 | * 时间复杂度:O(n) 69 | * 空间复杂度:O(n) 70 | * 71 | */ 72 | int Solution::climbStairs(int n) 73 | { 74 | if (n < 2) 75 | return n; 76 | 77 | vector dp(n + 1); 78 | 79 | dp[1] = 1; 80 | dp[2] = 2; 81 | 82 | for (int i = 3; i <= n; i++) 83 | { 84 | dp[i] = dp[i - 1] + dp[i - 2]; 85 | } 86 | 87 | return dp[n]; 88 | }; 89 | 90 | /** 91 | * 用滚动数组的方式优化空间复杂度 92 | * 93 | * 时间复杂度:O(n) 94 | * 空间复杂度:O(1) 95 | */ 96 | int Solution::climbStairs1(int n) 97 | { 98 | if (n < 2) 99 | return n; 100 | 101 | int dp[3]; 102 | 103 | dp[1] = 1; 104 | dp[2] = 2; 105 | 106 | for (int i = 3; i <= n; i++) 107 | { 108 | int sum = dp[1] + dp[2]; 109 | dp[1] = dp[2]; 110 | dp[2] = sum; 111 | } 112 | 113 | return dp[2]; 114 | }; 115 | 116 | /** 117 | * 假如讲一步1个台阶或2个台阶改为,一步1个台阶,2个台阶,3个台阶... 直到m个台阶。问有多少种不同的方法可以爬到楼顶? 118 | * 119 | */ 120 | int Solution::climbStairs2(int n) 121 | { 122 | return 0; 123 | }; 124 | 125 | int main(int argc, char const *argv[]) 126 | { 127 | Solution s; 128 | 129 | cout << "dp[2] = " << s.climbStairs(2) << endl; 130 | cout << "dp[3] = " << s.climbStairs(3) << endl; 131 | cout << "dp[4] = " << s.climbStairs(4) << endl; 132 | cout << "dp[5] = " << s.climbStairs(5) << endl; 133 | cout << "dp[6] = " << s.climbStairs(6) << endl; 134 | cout << "dp[7] = " << s.climbStairs(7) << endl; 135 | 136 | return 0; 137 | } 138 | -------------------------------------------------------------------------------- /leetcode/dynamic_programming/dp_fibonacci_numbers: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/dynamic_programming/dp_fibonacci_numbers -------------------------------------------------------------------------------- /leetcode/dynamic_programming/dp_fibonacci_numbers.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-01 10:21:49 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-01 14:07:24 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/problems/fibonacci-number/ 10 | * 11 | * 动态规划 - 斐波那契数 12 | * 斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: 13 | * F(0) = 0, F(1) = 1 14 | * F(n) = F(n-1) + F(n-2), 其中 n > 1 (1 < n <= 30) 15 | * 16 | * 示例 1: 17 | * 输入:n = 2 18 | * 输出:1 19 | * 解释:F(2) = F(1) + F(0) = 1 + 0 = 1 20 | * 21 | * 示例 2: 22 | * 输入:n = 3 23 | * 输出:2 24 | * 解释:F(3) = F(2) + F(1) = 1 + 1 = 2 25 | * 26 | * 示例 3: 27 | * 输入:n = 4 28 | * 输出:3 29 | * 解释:F(4) = F(3) + F(2) = 2 + 1 = 3 30 | * 31 | */ 32 | 33 | #include 34 | 35 | using namespace std; 36 | 37 | class Solution 38 | { 39 | private: 40 | /* data */ 41 | public: 42 | int fib(int n); 43 | 44 | int fib1(int n); 45 | }; 46 | 47 | /** 48 | * 解法1: 直接利用公式递归 49 | * 50 | * 时间复杂度: O(2^n) 51 | * 空间复杂度: O(n) 52 | * 53 | */ 54 | int Solution::fib(int n) 55 | { 56 | return n < 2 ? n : fib(n - 1) + fib(n - 2); 57 | } 58 | 59 | /** 60 | * 解法2: 动态规划 61 | * 62 | * 动规五部曲: 63 | * 这里我们要用一个一维dp数组来保存递归的结果 64 | * 1. 确定dp数组以及下标的含义 65 | * dp[i]的定义为:第i个数的斐波那契数值是dp[i] 66 | * 2. 确定递推公式 67 | * 斐波那契数列的公式: dp[i] = dp[i-1] + dp[i-2]; 68 | * 3. dp数组初始化 69 | * dp[0] = 0; dp[1] = 1; 70 | * 4. 确定遍历顺序,从递归公式 dp[i] = dp[i - 1] + dp[i - 2]; 中可以看出, 71 | * dp[i]是依赖 dp[i - 1] 和 dp[i - 2],那么遍历的顺序一定是从前到后遍历的 72 | * 5. 举例推导dp数组 73 | * 按照这个递推公式dp[i] = dp[i - 1] + dp[i - 2],我们来推导一下,当N为10的时候,dp数组应该是如下的数列: 74 | * 0 1 1 2 3 5 8 13 21 34 55 75 | * 76 | * 77 | * 时间复杂度: O(n) 78 | * 空间复杂度: O(1) 79 | * 80 | */ 81 | 82 | int Solution::fib1(int n) 83 | { 84 | if (n < 2) 85 | return n; 86 | 87 | int dp[2]; 88 | 89 | dp[0] = 0; 90 | dp[1] = 1; 91 | 92 | for (int i = 2; i <= n; i++) 93 | { 94 | int sum = dp[0] + dp[1]; 95 | dp[0] = dp[1]; 96 | dp[1] = sum; 97 | } 98 | return dp[1]; 99 | } 100 | 101 | int main(int argc, char const *argv[]) 102 | { 103 | Solution s; 104 | 105 | cout << "F(4) = " << s.fib(4) << endl; 106 | cout << "F(5) = " << s.fib(5) << endl; 107 | cout << "F(6) = " << s.fib(6) << endl; 108 | 109 | cout << "\nF(4) = " << s.fib1(4) << endl; 110 | cout << "F(5) = " << s.fib1(5) << endl; 111 | cout << "F(6) = " << s.fib1(6) << endl; 112 | return 0; 113 | } 114 | -------------------------------------------------------------------------------- /leetcode/dynamic_programming/dp_min_cost_climb_stairs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/dynamic_programming/dp_min_cost_climb_stairs -------------------------------------------------------------------------------- /leetcode/dynamic_programming/integer_break: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/dynamic_programming/integer_break -------------------------------------------------------------------------------- /leetcode/dynamic_programming/unique_binary_search_trees: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/dynamic_programming/unique_binary_search_trees -------------------------------------------------------------------------------- /leetcode/dynamic_programming/unique_paths: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/dynamic_programming/unique_paths -------------------------------------------------------------------------------- /leetcode/dynamic_programming/unique_paths_1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/dynamic_programming/unique_paths_1 -------------------------------------------------------------------------------- /leetcode/dynamic_programming/动态规划.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/dynamic_programming/动态规划.png -------------------------------------------------------------------------------- /leetcode/dynamic_programming/动态规划.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/dynamic_programming/动态规划.xmind -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/assign_cookies: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/greedy_algorithm/assign_cookies -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/assign_cookies.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-15 22:47:36 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-15 23:27:18 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/problems/assign-cookies/ 10 | * 11 | * 455. 分发饼干 12 | * 13 | * 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 14 | * 对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。 15 | * 如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。 16 | * 你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 17 | * 18 | * 示例 1: 19 | * 输入: g = [1,2,3], s = [1,1] 20 | * 输出: 1 21 | * 解释: 22 | * 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 23 | * 虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。所以你应该输出1。 24 | * 25 | * 示例 2: 26 | * 输入: g = [1,2], s = [1,2,3] 27 | * 输出: 2 28 | * 解释: 29 | * 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 30 | * 你拥有的饼干数量和尺寸都足以让所有孩子满足。所以你应该输出2. 31 | * 32 | * 33 | */ 34 | 35 | #include 36 | #include 37 | 38 | using namespace std; 39 | 40 | class Solution 41 | { 42 | private: 43 | /* data */ 44 | public: 45 | int findContentChildren(vector &g, vector &s); 46 | }; 47 | 48 | /** 49 | * 排序 + 贪心 50 | * 51 | * 为了满足更多的小孩,就不要造成饼干尺寸的浪费。 52 | * 大尺寸的饼干既可以满足胃口大的孩子也可以满足胃口小的孩子,那么就应该优先满足胃口大的。 53 | * 这里的局部最优就是大饼干喂给胃口大的,充分利用饼干尺寸喂饱一个,全局最优就是喂饱尽可能多的小孩。 54 | * 可以尝试使用贪心策略,先将饼干数组和小孩数组排序。然后从后向前遍历小孩数组,用大饼干优先满足胃口大的,并统计满足小孩数量。 55 | * 56 | * 饼干: 1 3 5 9 57 | * 小孩: 1 2 7 10 58 | * 59 | * 这个例子可以看出饼干9只有喂给胃口为7的小孩,这样才是整体最优解,并想不出反例。 60 | * 61 | * 时间复杂度:O(NlogN) 62 | * 空间复杂度:O(1) 63 | * 64 | */ 65 | int Solution::findContentChildren(vector &g, vector &s) 66 | { 67 | // 对 g 和 s 排序 68 | sort(g.begin(), g.end()); 69 | sort(s.begin(), s.end()); 70 | 71 | int index = s.size() - 1; // 饼干数组的下标 72 | int result = 0; 73 | 74 | for (int i = g.size() - 1; i >= 0; i--) 75 | { 76 | if (index >= 0 && s[index] >= g[i]) 77 | { 78 | index--; 79 | result++; 80 | } 81 | } 82 | 83 | return result; 84 | } 85 | 86 | int main(int argc, char const *argv[]) 87 | { 88 | Solution s; 89 | vector c(4); 90 | vector g(4); 91 | 92 | c[0] = 1; 93 | c[1] = 3; 94 | c[2] = 5; 95 | c[3] = 9; 96 | 97 | g[0] = 1; 98 | g[1] = 2; 99 | g[2] = 7; 100 | g[3] = 10; 101 | 102 | cout << "最大数值为:" << s.findContentChildren(c, g) << endl; 103 | 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/best_time_to_buy_and_sell_stock_ii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/greedy_algorithm/best_time_to_buy_and_sell_stock_ii -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/best_time_to_buy_and_sell_stock_ii.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-23 23:33:43 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-24 16:46:52 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ 10 | * 11 | * 给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。 12 | * 在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。 13 | * 返回 你能获得的 最大 利润 。 14 | * 15 | * 示例 1: 16 | * 输入:prices = [7,1,5,3,6,4] 17 | * 输出:7 18 | * 解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。 19 | * 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。 20 | * 总利润为 4 + 3 = 7 。 21 | * 22 | * 示例 2: 23 | * 输入:prices = [1,2,3,4,5] 24 | * 输出:4 25 | * 解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。 26 | * 总利润为 4 。 27 | * 28 | * 示例 3: 29 | * 输入:prices = [7,6,4,3,1] 30 | * 输出:0 31 | * 解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。 32 | * 33 | * 34 | */ 35 | #include 36 | #include 37 | 38 | using namespace std; 39 | 40 | class Solution 41 | { 42 | private: 43 | /* data */ 44 | public: 45 | int maxProfit(vector &prices); 46 | }; 47 | 48 | /** 49 | * 方法:贪心算法 50 | * 51 | * 思路: 52 | * 本题首先要清楚两点: 53 | * 1.只有一只股票 54 | * 2.当前只有买股票或者买股票的操作 55 | * 想获得利润至少要两天为一个交易单元。 56 | * 57 | * 如果想到其实最终利润是可以分解的,那么本题就很容易了!如何分解呢? 58 | * 假如第0天买入,第3天卖出,那么利润为:prices[3] - prices[0]。 59 | * 相当于(prices[3] - prices[2]) + (prices[2] - prices[1]) + (prices[1] - prices[0])。 60 | * 此时就是把利润分解为每天为单位的维度,而不是从0天到第3天整体去考虑。 61 | * 那么根据prices可以得到每天的利润序列:(prices[i] - prices[i - 1]).....(prices[1] - prices[0])。 62 | * 63 | * 如图: 64 | * 股票价格: 7 1 5 3 6 4 65 | * 每天利润: -6 4 -2 3 -2 66 | * 贪心,每天只收集整利润: 4 + 3 = 7 67 | * 68 | * 局部最优:收集每天的正利润,全局最优:求得最大利润。 69 | * 70 | * 时间复杂度:O(n) 71 | * 空间复杂度:O(1) 72 | * 73 | */ 74 | int Solution::maxProfit(vector &prices) 75 | { 76 | int result = 0; 77 | for (int i = 1; i < prices.size(); i++) 78 | { 79 | result += max(prices[i] - prices[i - 1], 0); 80 | } 81 | return result; 82 | }; 83 | 84 | int main(int argc, char const *argv[]) 85 | { 86 | Solution s; 87 | vector prices = {7, 1, 5, 3, 6, 4}; 88 | vector prices1 = {1, 2, 3, 4, 5}; 89 | 90 | cout << "prices = [7, 1, 5, 3, 6, 4], 最大利润为" << s.maxProfit(prices) << endl; // 7 91 | cout << "prices = [1, 2, 3, 4, 5], 最大利润为" << s.maxProfit(prices1) << endl; // 4 92 | 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/burst_balloons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/greedy_algorithm/burst_balloons.png -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/candy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/greedy_algorithm/candy -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/gas_station: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/greedy_algorithm/gas_station -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/jump_game: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/greedy_algorithm/jump_game -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/jump_game.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-25 16:10:12 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-07 12:51:33 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/problems/jump-game/ 10 | * 11 | * 55. 跳跃游戏 12 | * 13 | * 给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。 14 | * 数组中的每个元素代表你在该位置可以跳跃的最大长度。 15 | * 判断你是否能够到达最后一个下标。 16 | * 17 | * 示例 1: 18 | * 输入:nums = [2,3,1,1,4] 19 | * 输出:true 20 | * 解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。 21 | * 22 | * 示例 2: 23 | * 输入:nums = [3,2,1,0,4] 24 | * 输出:false 25 | * 解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。 26 | * 27 | * 28 | */ 29 | #include 30 | #include 31 | 32 | using namespace std; 33 | 34 | class Solution 35 | { 36 | private: 37 | /* data */ 38 | public: 39 | bool canJump(vector &nums); 40 | }; 41 | 42 | /** 43 | * 方法:贪心算法 44 | * 45 | * 思路: 46 | * 刚看到本题一开始可能想:当前位置元素如果是3,我究竟是跳一步呢,还是两步呢,还是三步呢,究竟跳几步才是最优呢? 47 | * 其实跳几步无所谓,关键在于可跳的覆盖范围!不一定非要明确一次究竟跳几步,每次取最大的跳跃步数,这个就是可以跳跃的覆盖范围。 48 | * 这个范围内,别管是怎么跳的,反正一定可以跳过来。那么这个问题就转化为跳跃覆盖范围究竟可不可以覆盖到终点! 49 | * 50 | * 贪心算法局部最优解:每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到整体最大覆盖范围,看是否能到终点。 51 | * 52 | * 如图: 53 | * 54 | * 下标i: 0 1 2 3 4 0 1 2 3 4 55 | * 3 2 1 0 4 2 3 1 1 4 56 | * 57 | * cover: --------------- ----------- 58 | * ---------- ---------------- 59 | * ----- 60 | * cover 仅覆盖了下标 3 cover 能覆盖下标 4 61 | * 62 | * 63 | */ 64 | bool Solution::canJump(vector &nums) 65 | { 66 | int cover = 0; 67 | 68 | if (nums.size() == 1) 69 | { 70 | return true; // 只有一个元素就能到达 71 | } 72 | 73 | for (int i = 0; i <= cover; i++) 74 | { 75 | cover = max(i + nums[i], cover); 76 | 77 | if (cover >= nums.size() - 1) 78 | { 79 | return true; 80 | } 81 | } 82 | 83 | return false; 84 | }; 85 | 86 | int main(int argc, char const *argv[]) 87 | { 88 | Solution s; 89 | vector nums = {3, 2, 1, 0, 4}; 90 | vector nums1 = {2, 3, 1, 1, 4}; 91 | 92 | cout << "nums = [2,3,1,1,4], 是否能够到达最后一个下标? " << s.canJump(nums) << endl; 93 | cout << "\nnums = [3,2,1,0,4], 是否能够到达最后一个下标? " << s.canJump(nums1) << endl; 94 | 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/jump_game_ii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/greedy_algorithm/jump_game_ii -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/jump_game_ii.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-07 11:47:52 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-07 16:06:32 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/problems/jump-game-ii/ 10 | * 11 | * 45. 跳跃游戏 II 12 | * 13 | * 给你一个非负整数数组 nums ,你最初位于数组的第一个位置。数组中的每个元素代表你在该位置可以跳跃的最大长度。 14 | * 你的目标是使用最少的跳跃次数到达数组的最后一个位置。假设你总是可以到达数组的最后一个位置。 15 | * 16 | * 示例 1: 17 | * 输入: nums = [2,3,1,1,4] 18 | * 输出: 2 19 | * 解释: 跳到最后一个位置的最小跳跃数是 2。从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。 20 | * 21 | * 示例 2: 22 | * 输入: nums = [2,3,0,1,4] 23 | * 输出: 2 24 | * 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | using namespace std; 31 | 32 | class Solution 33 | { 34 | private: 35 | /* data */ 36 | public: 37 | int jump(vector &nums); 38 | }; 39 | 40 | /** 41 | * 方法:贪心算法,正向查找可到达的最大位置 42 | * 43 | * 思路:如果我们「贪心」地进行正向查找,每次找到可到达的最远位置,就可以在线性时间内得到最少的跳跃次数。 44 | * 45 | * 例如,对于数组 [2,3,1,2,4,2,3],初始位置是下标 0,从下标 0 出发,最远可到达下标 2。 46 | * 下标 0 可到达的位置中,下标 1 的值是 3,从下标 1 出发可以达到更远的位置,因此第一步到达下标 1。 47 | * 从下标 1 出发,最远可到达下标 4。下标 1 可到达的位置中,下标 4 的值是 4 ,从下标 4 出发可以达到更远的位置,因此第二步到达下标 4。 48 | * 49 | * 如图 ./jump_game_ii.png 50 | * 51 | * 在具体的实现中,我们维护当前能够到达的最大下标位置,记为边界。我们从左到右遍历数组,到达边界时,更新边界并将跳跃次数增加 1。 52 | * 53 | * 在遍历数组时,我们不访问最后一个元素,这是因为在访问最后一个元素之前,我们的边界一定大于等于最后一个位置, 54 | * 否则就无法跳到最后一个位置了。如果访问最后一个元素,在边界正好为最后一个位置的情况下, 55 | * 我们会增加一次「不必要的跳跃次数」,因此我们不必访问最后一个元素。 56 | * 57 | * 时间复杂度:O(n),其中 n 是数组长度。 58 | * 空间复杂度:O(1)。 59 | * 60 | * 题解:https://leetcode-cn.com/problems/jump-game-ii/solution/tiao-yue-you-xi-ii-by-leetcode-solution/ 61 | * 62 | */ 63 | int Solution::jump(vector &nums) 64 | { 65 | int maxPos = 0; // 目前能跳到的最远位置 66 | int n = nums.size(); // 数组长度 67 | int step = 0; // 跳跃次数 68 | int end = 0; // 上次跳跃可达范围右边界(下次的最右起跳点) 69 | 70 | for (int i = 0; i < n - 1; i++) 71 | { 72 | if (maxPos >= i) 73 | { 74 | maxPos = max(maxPos, i + nums[i]); 75 | 76 | if (i == end) 77 | { 78 | end = maxPos; 79 | step++; 80 | } 81 | } 82 | } 83 | 84 | return step; 85 | }; 86 | 87 | int main(int argc, char const *argv[]) 88 | { 89 | Solution s; 90 | vector nums = {2, 3, 1, 2, 4, 2, 3}; 91 | vector nums1 = {2, 3, 1, 1, 4}; 92 | 93 | cout << "nums = [2, 3, 1, 2, 4, 2, 3], 最少的跳跃次数为: " << s.jump(nums) << endl; 94 | cout << "\nnums = [2, 3, 1, 1, 4], 最少的跳跃次数为: " << s.jump(nums1) << endl; 95 | 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/jump_game_ii.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/greedy_algorithm/jump_game_ii.png -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/maximi_sum_of_array_after_k_negations: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/greedy_algorithm/maximi_sum_of_array_after_k_negations -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/maximi_sum_of_array_after_k_negations.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-05-17 22:14:56 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-05-17 22:42:44 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations/ 10 | * 11 | * 1005. K 次取反后最大化的数组和 12 | * 13 | * 给你一个整数数组 nums 和一个整数 k ,按以下方法修改该数组: 14 | * 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。 15 | * 重复这个过程恰好 k 次。可以多次选择同一个下标 i 。 16 | * 以这种方式修改数组后,返回数组 可能的最大和 。 17 | * 18 | * 示例 1: 19 | * 输入:nums = [4,2,3], k = 1 20 | * 输出:5 21 | * 解释:选择下标 1 ,nums 变为 [4,-2,3] 。 22 | * 23 | * 示例 2: 24 | * 输入:nums = [3,-1,0,2], k = 3 25 | * 输出:6 26 | * 解释:选择下标 (1, 2, 2) ,nums 变为 [3,1,0,2] 。 27 | * 28 | * 示例 3: 29 | * 输入:nums = [2,-3,-1,5,-4], k = 2 30 | * 输出:13 31 | * 解释:选择下标 (1, 4) ,nums 变为 [2,3,-1,5,4] 。 32 | * 33 | */ 34 | #include 35 | #include 36 | 37 | using namespace std; 38 | 39 | class Solution 40 | { 41 | 42 | static bool compare(int a, int b); 43 | 44 | private: 45 | /* data */ 46 | public: 47 | int largestSumAfterKNegations(vector &nums, int k); 48 | }; 49 | 50 | bool Solution::compare(int a, int b) 51 | { 52 | return abs(a) > abs(b); 53 | } 54 | 55 | /** 56 | * 方法:贪心的思路 57 | * 58 | * 局部最优:让绝对值大的负数变为正数,当前数值达到最大,整体最优:整个数组和达到最大。 59 | * 那么如果将负数都转变为正数了,K依然大于0,此时的问题是一个有序正整数序列,如何转变K次正负,让数组和达到最大。 60 | * 那么又是一个贪心:局部最优:只找数值最小的正整数进行反转,当前数值可以达到最大, 61 | * 例如正整数数组{5, 3, 1},反转1 得到-1 比 反转5得到的-5 大多了,全局最优:整个 数组和 达到最大。 62 | * 63 | * 解题步骤: 64 | * 1. 将数组按照绝对值大小从大到小排序,注意要按照绝对值的大小。 65 | * 2. 从前向后遍历,遇到负数将其变为正数,同时K-- 66 | * 3. 如果K还大于0,那么反复转变数值最小的元素,将K用完 67 | * 4. 求和 68 | * 69 | */ 70 | int Solution::largestSumAfterKNegations(vector &nums, int k) 71 | { 72 | // 按绝对值大小从大到小排序 73 | sort(nums.begin(), nums.end(), compare); 74 | 75 | for (int i = 0; i < nums.size(); i++) 76 | { 77 | if (nums[i] < 0 && k > 0) 78 | { 79 | nums[i] *= -1; 80 | k--; 81 | } 82 | } 83 | 84 | if (k % 2 == 1) 85 | { 86 | nums[nums.size() - 1] *= -1; 87 | } 88 | 89 | int result = 0; 90 | for (int n : nums) 91 | result += n; // 第四步 92 | 93 | return result; 94 | } 95 | 96 | int main(int argc, char const *argv[]) 97 | { 98 | Solution s; 99 | vector nums = {4, 2, 3}; 100 | vector nums1 = {3, -1, 0, 2}; 101 | vector nums2 = {2, -3, -1, 5, -4}; 102 | 103 | cout << "nums = [4, 2, 3], k = 1, 最大和: " << s.largestSumAfterKNegations(nums, 1) << endl; 104 | cout << "nums = [3,-1,0,2], k = 3, 最大和: " << s.largestSumAfterKNegations(nums1, 3) << endl; 105 | cout << "nums = [2,-3,-1,5,-4], k = 2, 最大和: " << s.largestSumAfterKNegations(nums2, 2) << endl; 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/maximum_subarray: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/greedy_algorithm/maximum_subarray -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/minimum_number_of_arrows_to_burst_balloons: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/greedy_algorithm/minimum_number_of_arrows_to_burst_balloons -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/minimum_number_of_arrows_to_burst_balloons.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-11 11:06:31 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-15 22:46:06 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/problems/minimum-number-of-arrows-to-burst-balloons/ 10 | * 11 | * 452. 用最少数量的箭引爆气球 12 | * 13 | * 在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。 14 | * 由于它是水平的,所以纵坐标并不重要,因此只要知道开始和结束的横坐标就足够了。开始坐标总是小于结束坐标。 15 | * 16 | * 一支弓箭可以沿着 x 轴从不同点完全垂直地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 17 | * 且满足 xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。弓箭一旦被射出之后,可以无限地前进。 18 | * 我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。 19 | * 20 | * 给你一个数组 points ,其中 points [i] = [xstart,xend] ,返回引爆所有气球所必须射出的最小弓箭数。 21 | * 22 | * 示例 1: 23 | * 输入:points = [[10,16],[2,8],[1,6],[7,12]] 24 | * 输出:2 25 | * 解释:对于该样例,x = 6 可以射爆 [2,8],[1,6] 两个气球,以及 x = 11 射爆另外两个气球 26 | * 27 | * 示例 2: 28 | * 输入:points = [[1,2],[3,4],[5,6],[7,8]] 29 | * 输出:4 30 | * 31 | * 示例 3: 32 | * 输入:points = [[1,2],[2,3],[3,4],[4,5]] 33 | * 输出:2 34 | * 35 | * 示例 4: 36 | * 输入:points = [[1,2]] 37 | * 输出:1 38 | * 39 | * 示例 5: 40 | * 输入:points = [[2,3],[2,3]] 41 | * 输出:1 42 | * 43 | * 提示: 44 | * 0 <= points.length <= 104 45 | * points[i].length == 2 46 | * -2^31 <= xstart < xend <= 2^31 - 1 47 | * 48 | */ 49 | 50 | #include 51 | #include 52 | 53 | using namespace std; 54 | 55 | class Solution 56 | { 57 | private: 58 | /* data */ 59 | public: 60 | int findMinArrowShots(vector> &points); 61 | }; 62 | 63 | /** 64 | * 排序 + 贪心 65 | * 66 | * 时间复杂度:O(NlogN),其中 N 是数组 points 的长度。排序的时间复杂度为 O(NlogN), 67 | * 对所有气球进行遍历并计算答案的时间复杂度为 O(N),其在渐进意义下小于前者,因此可以忽略。 68 | * 空间复杂度:O(logN),即为排序需要使用的栈空间。 69 | * 70 | */ 71 | int Solution::findMinArrowShots(vector> &points) 72 | { 73 | if (points.empty()) 74 | { 75 | return 0; 76 | } 77 | 78 | // 将 points 按照 y 值(右边界)进行升序排序 79 | // 比如 [[10,16],[2,8],[1,6],[7,12]] -> [[1,6],[2,8],[7,12],[10,16]] 80 | sort(points.begin(), points.end(), [](const vector &u, const vector &v) 81 | { return u[1] < v[1]; }); 82 | 83 | int pos = points[0][1]; 84 | int ans = 1; 85 | 86 | for (const vector &balloon : points) 87 | { 88 | if (balloon[0] > pos) 89 | { 90 | pos = balloon[1]; 91 | ++ans; 92 | } 93 | } 94 | 95 | return ans; 96 | } 97 | 98 | int main(int argc, char const *argv[]) 99 | { 100 | Solution s; 101 | vector> a; 102 | vector> b; 103 | 104 | a[0] = vector(10, 16); 105 | a[1] = vector(2, 8); 106 | a[2] = vector(1, 6); 107 | a[3] = vector(7, 12); 108 | 109 | b[0] = vector(1, 2); 110 | b[1] = vector(2, 3); 111 | b[2] = vector(3, 4); 112 | b[3] = vector(4, 5); 113 | 114 | cout << "[[10,16],[2,8],[1,6],[7,12]] findMinArrowShots" << s.findMinArrowShots(a) << endl; 115 | cout << "[[1,2],[3,4],[5,6],[7,8]] findMinArrowShots" << s.findMinArrowShots(b) << endl; 116 | 117 | return 0; 118 | } 119 | -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/wiggle_subsequence: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/greedy_algorithm/wiggle_subsequence -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/贪心算法.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/greedy_algorithm/贪心算法.png -------------------------------------------------------------------------------- /leetcode/greedy_algorithm/贪心算法.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/greedy_algorithm/贪心算法.xmind -------------------------------------------------------------------------------- /leetcode/intersection/interval_list_intersections: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/intersection/interval_list_intersections -------------------------------------------------------------------------------- /leetcode/linked_list/linked_list_cycle.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2019-01-14 15:24:40 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2021-03-26 17:35:37 6 | */ 7 | 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | /** 13 | * Definition for singly-linked list(单向链表) 14 | * Source: https://zh.wikipedia.org/wiki/链表 15 | */ 16 | struct ListNode 17 | { 18 | int val; 19 | ListNode *next; 20 | ListNode(int x) : val(x), next(NULL) {} 21 | }; 22 | 23 | class Solution 24 | { 25 | public: 26 | /** 27 | * Given a linked list, determine if it has a cycle in it. 28 | * Example: 29 | * Given -21->10->4->5, tail connects to node index 1, return true 30 | * Source: https://leetcode.com/problems/linked-list-cycle/ 31 | */ 32 | bool hasCycle(ListNode *head) 33 | { 34 | if (head == NULL || head->next == NULL) 35 | return false; 36 | 37 | ListNode *slow = head; 38 | ListNode *fast = head->next; 39 | 40 | while (fast != NULL && fast->next != NULL) 41 | { 42 | fast = fast->next->next; 43 | slow = slow->next; 44 | 45 | if (slow == fast) 46 | return true; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Given a linked list, return the node where the cycle begins. If there is no cycle, return null. 54 | * 55 | * Example: 56 | * Given -21->10->4->5, tail connects to node index 1,return node 10 57 | * 58 | * Source: 59 | */ 60 | ListNode *detectCycle(ListNode *head) 61 | { 62 | if (head == NULL || head->next == NULL) 63 | return NULL; 64 | 65 | ListNode *slow = head; 66 | ListNode *fast = head; 67 | 68 | while (fast != NULL && fast->next != NULL) 69 | { 70 | fast = fast->next->next; 71 | slow = slow->next; 72 | 73 | if (slow == fast) 74 | { 75 | fast = head; 76 | while (slow != fast) 77 | { 78 | fast = fast->next; 79 | slow = slow->next; 80 | } 81 | return slow; 82 | }; 83 | } 84 | 85 | return NULL; 86 | } 87 | }; 88 | 89 | int main() 90 | { 91 | return 0; 92 | } 93 | -------------------------------------------------------------------------------- /leetcode/linked_list/merge_sorted_list: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/linked_list/merge_sorted_list -------------------------------------------------------------------------------- /leetcode/linked_list/partition_list: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/linked_list/partition_list -------------------------------------------------------------------------------- /leetcode/linked_list/partition_list.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Chacha 3 | * @Date: 2019-01-10 20:22:11 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2019-01-10 21:45:48 6 | */ 7 | 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | /** 13 | * Definition for singly-linked list(单向链表) 14 | * Source: https://zh.wikipedia.org/wiki/链表 15 | */ 16 | struct ListNode { 17 | int val; 18 | ListNode *next; 19 | ListNode(int x) : val(x), next(NULL) {} 20 | }; 21 | 22 | class Solution { 23 | public: 24 | /** 25 | * Given a linked list and a value x, partition it such that 26 | * all nodes less than x come before nodes greater than or equal to x. 27 | * You should preserve the original relative order of the nodes in each of the two partitions. 28 | * 29 | * Example: 30 | * Input: head = 1->4->3->2->5->2, x = 3 31 | * Output: 1->2->2->4->3->5 32 | * 33 | * Source: https://leetcode.com/problems/partition-list/ 34 | * 35 | */ 36 | ListNode* partitionList(ListNode* head, int x) { 37 | if (head == NULL) return NULL; 38 | 39 | ListNode* leftDummy = new ListNode(0); 40 | ListNode* rightDummy = new ListNode(0); 41 | ListNode* left = leftDummy; 42 | ListNode* right = rightDummy; 43 | 44 | while(head != NULL){ 45 | if (head->val < x) { 46 | left->next = head; 47 | left = left->next; 48 | } else { 49 | right->next = head; 50 | right = right->next; 51 | } 52 | head = head->next; 53 | } 54 | 55 | right->next = NULL; 56 | left->next = rightDummy->next; 57 | 58 | return leftDummy; 59 | } 60 | }; 61 | 62 | /* Function to print nodes in a given linked list */ 63 | void printList(ListNode *node) { 64 | while (node != NULL) { 65 | printf("%d ", node->val); 66 | node = node->next; 67 | } 68 | } 69 | 70 | int main() { 71 | ListNode* head = new ListNode(1); 72 | head->next = new ListNode(4); 73 | head->next->next = new ListNode(3); 74 | head->next->next->next = new ListNode(2); 75 | head->next->next->next->next = new ListNode(5); 76 | head->next->next->next->next->next = new ListNode(2); 77 | 78 | ListNode* result = Solution().partitionList(head, 3); 79 | printList(result); 80 | 81 | return 0; 82 | } -------------------------------------------------------------------------------- /leetcode/linked_list/remove_duplicates: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/linked_list/remove_duplicates -------------------------------------------------------------------------------- /leetcode/linked_list/reorder_list: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/linked_list/reorder_list -------------------------------------------------------------------------------- /leetcode/linked_list/reverse_linked_list: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/linked_list/reverse_linked_list -------------------------------------------------------------------------------- /leetcode/linked_list/sort_list: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/linked_list/sort_list -------------------------------------------------------------------------------- /leetcode/linked_list/two_lists_sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/linked_list/two_lists_sum -------------------------------------------------------------------------------- /leetcode/math/is_prime: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/math/is_prime -------------------------------------------------------------------------------- /leetcode/math/is_prime.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-15 14:19:00 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-15 15:02:31 6 | */ 7 | 8 | /** 9 | * 判断一个数是否为质数(素数)。 10 | * 定义:约数只有 1 和本身的整数成为质数,或称素数。 11 | * 注意:最小的质数是2。 12 | * 13 | */ 14 | #include 15 | #include 16 | #include 17 | 18 | using namespace std; 19 | 20 | class Solution 21 | { 22 | private: 23 | /* data */ 24 | public: 25 | bool isPrime1(int num); 26 | 27 | bool isPrime2(int num); 28 | 29 | bool isPrime3(int num); 30 | }; 31 | 32 | /** 33 | * 方法一: 34 | * 直观判断法(效率比较低) 35 | * 质数除了1和本身之外没有其他约数,所以判断n是否为质数,根据定义直接判断从2到n-1是否存在n的约数即可。 36 | * 37 | * 时间复杂度:O(n); 38 | * 39 | */ 40 | bool Solution::isPrime1(int num) 41 | { 42 | for (int i = 2; i < num; i++) 43 | { 44 | if (num % i == 0) 45 | return 0; 46 | } 47 | return 1; 48 | }; 49 | 50 | /** 51 | * 方法二: 52 | * 方法一的优化方法。 53 | * 对于每个数n,其实并不需要从2判断到n-1,我们知道,一个数若可以进行因数分解,那么分解时得到的两个数一定是一个小于等于sqrt(n), 54 | * 一个大于等于sqrt(n),据此,上述代码中并不需要遍历到n-1,遍历到sqrt(n)即可,因为若sqrt(n)左侧找不到约数,那么右侧也一定找不到约数。 55 | * 56 | * 时间复杂度:O(sqrt(n)); 57 | * 58 | */ 59 | bool Solution::isPrime2(int num) 60 | { 61 | int n = sqrt(num); 62 | for (int i = 2; i <= n; i++) 63 | { 64 | if (n % i == 0) 65 | return 0; 66 | } 67 | return 1; 68 | }; 69 | 70 | /** 71 | * 方法三: 72 | * 质数分布的规律:大于等于5的质数一定和6的倍数相邻。例如5和7,11和13,17和19等等; 73 | * 74 | * 1. 能被6整除的,肯定不是素数,故6x不是素数 75 | * 2. 能被2或3整除的,肯定不是素数,故6x+2、6x+3、6x+4也肯定不是素数 76 | * 3. 即6x+1、6x+5(等同6x-1)有可能为素数 77 | * 78 | * 步长设为6,每次只判断6前后的两个数即可。 79 | * 80 | */ 81 | bool Solution::isPrime3(int num) 82 | { 83 | // 排除特殊情况 84 | if (num <= 3) 85 | { 86 | return num > 1; 87 | } 88 | 89 | // 不在6的两侧,肯定不是质数 90 | if (num % 6 != 1 && num % 6 != 5) 91 | { 92 | return 0; 93 | } 94 | 95 | int n = sqrt(num); 96 | for (int i = 5; i <= n; i += 6) 97 | { 98 | if (num % i == 0 || num % (i + 2) == 0) 99 | { 100 | return 0; 101 | } 102 | } 103 | 104 | return 1; 105 | }; 106 | 107 | int main(int argc, char const *argv[]) 108 | { 109 | Solution s; 110 | int test_num = 100000; 111 | int t_start, t_stop; 112 | 113 | t_start = clock(); 114 | 115 | for (int i = 2; i <= test_num; i++) 116 | { 117 | s.isPrime1(i); 118 | } 119 | 120 | t_stop = clock(); 121 | 122 | cout << "方法一所需时间(ms):" << t_stop - t_start << endl; 123 | 124 | t_start = clock(); 125 | 126 | for (int i = 2; i <= test_num; i++) 127 | { 128 | s.isPrime2(i); 129 | } 130 | 131 | t_stop = clock(); 132 | 133 | cout << "方法二所需时间(ms):" << t_stop - t_start << endl; 134 | 135 | t_start = clock(); 136 | 137 | for (int i = 2; i <= test_num; i++) 138 | { 139 | s.isPrime3(i); 140 | } 141 | 142 | t_stop = clock(); 143 | 144 | cout << "方法三所需时间(ms):" << t_stop - t_start << endl; 145 | 146 | return 0; 147 | } 148 | -------------------------------------------------------------------------------- /leetcode/string/implement_strstr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/string/implement_strstr -------------------------------------------------------------------------------- /leetcode/string/replace_string: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/string/replace_string -------------------------------------------------------------------------------- /leetcode/string/replace_string.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2021-03-26 16:12:33 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2021-03-26 18:04:33 6 | */ 7 | 8 | /** 9 | * 题目: 10 | * 请实现一个函数,把字符串 s 中的每个空格替换成 "%20"。 11 | * 12 | * 来源:https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof/ 13 | * 14 | * 示例: 15 | * 输入:s = "We are coder." 16 | * 输出:"We%20are%20coder" 17 | * 18 | * 限制: 19 | * 0 <= s的长度 <= 10000 20 | */ 21 | 22 | /** 23 | * 题解: 24 | * 25 | * 来源:https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/50c26h/ 26 | * 27 | * 在 C++ 语言中, string 被设计成「可变」的类型(参考资料:https://stackoverflow.com/questions/28442719/are-c-strings-mutable-unlike-java-strings), 28 | * 因此可以在不新建字符串的情况下实现原地修改。由于需要将空格替换成 "%20",字符串的总数增加,因此需要扩展原字符串的长度。 29 | * 计算公式为:新字符串长度 = 原字符串 + 2 * 空格个数 30 | * 31 | * 算法步骤: 32 | * 1. 初始化:空格数量 count,字符串 s 的长度 len; 33 | * 2. 统计空格数量:遍历 s,遇到空格就count++; 34 | * 3. 修改 s 长度:添加完 "%20"后的字符串长度应为 len + 2 * count; 35 | * 4. 倒序遍历修改:i 指向原字符串尾部元素,j 指向新字符串尾部元素;当 i = j 时跳出(代表左方已经没有空格,无需继续遍历); 36 | * a. 当 s[i] 不为空格时:执行 s[j] = s[i] 37 | * b. 当 s[i] 为空格时:将字符串闭区间[j - 2, j] 的元素修改为 "%20";由于修改了3个元素,因此需要 j -= 2; 38 | * 5. 返回值:已修改的字符串 s; 39 | * 40 | * 复杂度: 41 | * 时间复杂度 O(n):遍历统计、遍历修改都使用 O(n) 时间 42 | * 空间复杂度 O(1):因为是原地扩展 s 的长度,所以使用 O(1) 额外空间 43 | * 44 | */ 45 | 46 | #include 47 | 48 | using namespace std; 49 | 50 | class Solution 51 | { 52 | private: 53 | /* data */ 54 | public: 55 | string replaceSpace(string s) 56 | { 57 | int count = 0, len = s.size(); 58 | 59 | // 计算空格长度 60 | for (char c : s) 61 | { 62 | if (c == ' ') 63 | { 64 | count++; 65 | } 66 | } 67 | 68 | // 修改 s 的长度 69 | s.resize(len + 2 * count); 70 | 71 | // 倒序遍历修改字符串 72 | for (int i = len - 1, j = s.size() - 1; i < j; i--, j--) 73 | { 74 | // 当 s[i] 不为空格时 75 | if (s[i] != ' ') 76 | { 77 | s[j] = s[i]; 78 | } 79 | else 80 | { // 当 s[i] 为空格时 81 | s[j - 2] = '%'; 82 | s[j - 1] = '2'; 83 | s[j] = '0'; 84 | j -= 2; 85 | } 86 | } 87 | 88 | return s; 89 | } 90 | }; 91 | 92 | int main(int argc, char const *argv[]) 93 | { 94 | string s = "We are coder"; 95 | 96 | std::cout << Solution().replaceSpace(s) << std::endl; 97 | 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /leetcode/string/rotate_string_left: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/string/rotate_string_left -------------------------------------------------------------------------------- /leetcode/string/rotate_string_left.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-20 13:26:59 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-20 13:54:43 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/ 10 | * 11 | * 剑指 Offer 58 - II.左旋转字符串 12 | * 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。 13 | * 比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。 14 | * 15 | * 1 <= k < s.length <= 10000 16 | * 17 | * 示例 1: 18 | * 输入: s = "abcdefg", k = 2 19 | * 输出: "cdefgab" 20 | * 21 | * 示例 2: 22 | * 输入: s = "lrloseumgh", k = 6 23 | * 输出: "umghlrlose" 24 | * 25 | */ 26 | #include 27 | #include 28 | 29 | using namespace std; 30 | 31 | class Solution 32 | { 33 | private: 34 | /* data */ 35 | public: 36 | string reverseStringLeft(string s, int n); 37 | }; 38 | 39 | /** 40 | * 41 | * 可以通过 局部反转+整体反转 达到左旋转的目的。具体步骤为: 42 | * 1. 反转区间为前 k 的子串 43 | * 2. 反转区间为 k 到末尾的子串 44 | * 3. 反转整个字符串 45 | * 46 | * 最后就可以得到左旋n的目的,而不用定义新的字符串,完全在本串上操作。 47 | * 48 | * 示例 1: 49 | * 50 | * 字符串: a b | c d e f g 51 | * 反转 0 到 k-1: b a | c d e f g 52 | * 反转 k 到 len-1: b a | g f e d c 53 | * 反转整个字符串: c d e f g a b 54 | * 55 | * 最后得到 cdefgab 56 | * 57 | */ 58 | string Solution::reverseStringLeft(string s, int k) 59 | { 60 | reverse(s.begin(), s.begin() + k); 61 | reverse(s.begin() + k, s.end()); 62 | reverse(s.begin(), s.end()); 63 | return s; 64 | } 65 | 66 | int main(int argc, char const *argv[]) 67 | { 68 | Solution s; 69 | 70 | string str1 = "abcdefg"; 71 | string str2 = "lrloseumgh"; 72 | 73 | cout << "abcdefg 在 k = 2 反转后:" << s.reverseStringLeft(str1, 2) << endl; // cdefgab 74 | cout << "lrloseumgh 在 k = 6 反转后:" << s.reverseStringLeft(str2, 6) << endl; // umghlrlose 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /leetcode/string/valid_parentheses: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/string/valid_parentheses -------------------------------------------------------------------------------- /leetcode/string/valid_parentheses.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-31 21:48:11 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-01 22:39:48 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/problems/valid-parentheses 10 | * 11 | * 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。 12 | * 有效字符串需满足: 13 | * 1. 左括号必须用相同类型的右括号闭合。 14 | * 2. 左括号必须以正确的顺序闭合。 15 | * 16 | * 示例 1: 17 | * 输入:s = "()" 18 | * 输出:true 19 | * 20 | * 示例 2: 21 | * 输入:s = "()[]{}" 22 | * 输出:true 23 | * 24 | * 示例 3: 25 | * 输入:s = "(]" 26 | * 输出:false 27 | * 28 | * 示例 4: 29 | * 输入:s = "([)]" 30 | * 输出:false 31 | * 32 | * 示例 5: 33 | * 输入:s = "{[]}" 34 | * 输出:true 35 | * 36 | */ 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | using namespace std; 43 | 44 | class Solution 45 | { 46 | private: 47 | /* data */ 48 | public: 49 | bool isValid(string s); 50 | }; 51 | 52 | /** 53 | * 判断括号的有效性可以使用「栈」这一数据结构来解决。 54 | * 1. 栈先入后出特点恰好与本题括号排序特点一致,即若遇到左括号入栈, 55 | * 遇到右括号时将对应栈顶左括号出栈,则遍历完所有括号后 stack 仍然为空。 56 | * 2. 建立哈希表 pairs 构建左右括号对应关系:key左括号,value右括号;这样查询 2 个括号是否对应, 57 | * 只需 O(1) 时间复杂度;建立栈 stack,遍历字符串 s 并按照算法流程一一判断 58 | * 59 | * 算法流程: 60 | * 1. 如果 ch 是 左括号,则入栈 push 61 | * 2. 否则通过哈希表判断括号对应关系,若 stack 栈顶出栈括号 stack.top() 与当前遍历括号 ch 不对应,则提前返回 false 62 | * 63 | * 复杂度分析: 64 | * 时间复杂度:正确的括号组合需要遍历 1 遍 s 65 | * 空间复杂度:哈希表和栈使用线性的空间大小 66 | * 67 | */ 68 | bool Solution::isValid(string s) 69 | { 70 | int n = s.size(); 71 | 72 | if (n % 2 == 1) 73 | { 74 | return false; 75 | } 76 | 77 | unordered_map pairs = { 78 | {')', '('}, 79 | {']', '['}, 80 | {'}', '{'}}; 81 | 82 | stack stk; 83 | 84 | for (char ch : s) 85 | { 86 | if (pairs.count(ch)) 87 | { 88 | if (stk.empty() || stk.top() != pairs[ch]) 89 | { 90 | return false; 91 | } 92 | stk.pop(); 93 | } 94 | else 95 | { 96 | stk.push(ch); 97 | } 98 | } 99 | 100 | return stk.empty(); 101 | } 102 | 103 | int main(int argc, char const *argv[]) 104 | { 105 | 106 | Solution s; 107 | string str = "()[]{}"; 108 | string str1 = "([)]"; 109 | 110 | cout << "()[]{} 是否闭合: " << s.isValid(str) << endl; 111 | cout << "([)] 是否闭合: " << s.isValid(str1) << endl; 112 | 113 | return 0; 114 | } 115 | -------------------------------------------------------------------------------- /leetcode/two_pointers/container_with_most_water: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/two_pointers/container_with_most_water -------------------------------------------------------------------------------- /leetcode/two_pointers/container_with_most_water.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-01 21:20:42 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-11 11:22:49 6 | */ 7 | 8 | /** 9 | * 10 | * 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 11 | * 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。 12 | * 13 | * 输入:height = [1,8,6,2,5,4,8,3,7] 14 | * 输出:49 15 | * 解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。 16 | * 17 | * 示例 2: 18 | * 输入:height = [1,1] 19 | * 输出:1 20 | * 21 | * 提示: 22 | * 1. n == height.length 23 | * 2. 2 <= n <= 10^5 24 | * 3. 0 <= height[i] <= 10^4 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | using namespace std; 33 | 34 | class Solution 35 | { 36 | private: 37 | /* data */ 38 | public: 39 | int maxArea(vector &height); 40 | }; 41 | 42 | /** 43 | * 双指针法 44 | * 设两指针i,j,指向的水槽板高度分别为 h[i],h[j],此状态下水槽面积S(i, j)。 45 | * 由于可容纳水的高度由两板中的 短板 决定,因此可得如下 面积公式 : 46 | * S(i, j) = min(h[i], h[j]) × (j − i) 47 | * 48 | * 在每个状态下,无论长板或短板向中间收窄一格,都会导致水槽 底边宽度 −1 变短: 49 | * 1. 若向内移动短板,水槽的短板 min(h[i], h[j]) 可能变大,因此下个水槽的面积可能增大。 50 | * 2. 若向内移动长板,水槽的短板 min(h[i], h[j]) 不变或变小,因此下个水槽的面积 一定变小。 51 | * 52 | * 因此,初始化双指针分列水槽左右两端,循环每轮将短板向内移动一格,并更新面积最大值,直到两个指针相遇时跳出,即可获得最大面积 53 | * 54 | * 算法步骤: 55 | * 1. 初始化:双指针 i, j 分列水槽左右两端 56 | * 2. 循环收窄:直至双指针相遇时跳出 57 | * a. 更新面积最大值 ans 58 | * b. 选定两板高度中的短板,向中间收窄一格 59 | * 3. 返回面积最大值 ans 即可 60 | * 61 | */ 62 | int Solution::maxArea(vector &height) 63 | { 64 | int i = 0, j = height.size() - 1, ans = 0; 65 | 66 | while (i < j) 67 | { 68 | ans = height[i] < height[j] ? max(ans, (j - i) * height[i++]) : max(ans, (j - i) * height[j--]); 69 | } 70 | 71 | return ans; 72 | }; 73 | 74 | int main(int argc, char const *argv[]) 75 | { 76 | Solution s; 77 | 78 | vector height = {1, 8, 6, 2, 5, 4, 8, 3, 7}; 79 | vector height1 = {1, 1}; 80 | 81 | cout 82 | << "输入:[1,8,6,2,5,4,8,3,7] 输出:" << s.maxArea(height) << endl; 83 | cout 84 | << "输入:[1, 1] 输出:" << s.maxArea(height1) << endl; 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /leetcode/two_pointers/container_with_most_water.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/two_pointers/container_with_most_water.png -------------------------------------------------------------------------------- /leetcode/two_pointers/remove_element: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/two_pointers/remove_element -------------------------------------------------------------------------------- /leetcode/two_pointers/remove_element.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-15 15:30:56 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-15 21:37:20 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/problems/remove-element/ 10 | * 11 | * 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 12 | * 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 13 | * 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 14 | * 15 | * 示例 1: 16 | * 输入:nums = [3,2,2,3], val = 3 17 | * 输出:2, nums = [2,2] 18 | * 解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。 19 | * 例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。 20 | * 21 | * 示例 2: 22 | * 输入:nums = [0,1,2,2,3,0,4,2], val = 2 23 | * 输出:5, nums = [0,1,4,0,3] 24 | * 解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。 25 | * 注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。 26 | * 27 | */ 28 | 29 | #include 30 | #include 31 | 32 | using namespace std; 33 | 34 | class Solution 35 | { 36 | public: 37 | int removeElement1(vector &nums, int val); 38 | 39 | int removeElement2(vector &nums, int val); 40 | }; 41 | 42 | /** 43 | * 方法一:暴力解法 44 | * 暴力的解法就是两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组。 45 | * 46 | * 时间复杂度:O(n^2) 47 | * 空间复杂度:O(1) 48 | * 49 | */ 50 | int Solution::removeElement1(vector &nums, int val) 51 | { 52 | int size = nums.size(); 53 | 54 | for (int i = 0; i < size; i++) 55 | { 56 | 57 | if (nums[i] == val) 58 | { 59 | // 发现需要移除的元素,就将数组集体向前移动一位 60 | for (int j = i + 1; j < size; j++) 61 | { 62 | nums[j - 1] = nums[j]; 63 | } 64 | i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位 65 | size--; // 此时数组的大小-1 66 | } 67 | } 68 | 69 | return size; 70 | } 71 | 72 | /** 73 | * 方法二:双指针法 74 | * 双指针法(快慢指针法):通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。 75 | * 时间复杂度:O(n) 76 | * 空间复杂度:O(1) 77 | * 78 | */ 79 | int Solution::removeElement2(vector &nums, int val) 80 | { 81 | int i = 0; 82 | 83 | for (int j = 0; j < nums.size(); j++) 84 | { 85 | if (nums[j] != val) 86 | { 87 | nums[i++] = nums[j]; 88 | } 89 | } 90 | return i; 91 | } 92 | 93 | void printVector(vector &vec) 94 | { 95 | for (int i = 0; i < vec.size(); i++) 96 | { 97 | printf("%3d", vec[i]); 98 | } 99 | cout << endl; 100 | } 101 | 102 | int main(int argc, char const *argv[]) 103 | { 104 | Solution s; 105 | int arr[] = {0, 1, 2, 2, 3, 0, 4, 2}; 106 | vector nums(arr, arr + sizeof(arr) / sizeof(int)); 107 | 108 | cout << "Remove element 2, result is " << s.removeElement1(nums, 2) << endl; // Remove element 2, result is 5 109 | 110 | printVector(nums); 111 | 112 | cout << "Remove element 3, result is " << s.removeElement2(nums, 3) << endl; // Remove element 3, result is 7 113 | 114 | printVector(nums); 115 | 116 | return 0; 117 | } 118 | -------------------------------------------------------------------------------- /leetcode/two_pointers/reverse_string: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/two_pointers/reverse_string -------------------------------------------------------------------------------- /leetcode/two_pointers/reverse_string.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-03-16 21:32:58 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-03-16 21:55:48 6 | */ 7 | 8 | /** 9 | * 来源:https://leetcode-cn.com/problems/reverse-string/ 10 | * 11 | * 344. 反转字符串 12 | * 13 | * 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 14 | * 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 15 | * 16 | * 示例 1: 17 | * 输入:s = ["h","e","l","l","o"] 18 | * 输出:["o","l","l","e","h"] 19 | * 20 | * 示例 2: 21 | * 输入:s = ["H","a","n","n","a","h"] 22 | * 输出:["h","a","n","n","a","H"] 23 | * 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | using namespace std; 31 | 32 | class Solution 33 | { 34 | public: 35 | void reverseString(vector &s); 36 | }; 37 | 38 | /** 39 | * 双指针法 40 | */ 41 | void Solution::reverseString(vector &s) 42 | { 43 | for (int i = 0, j = s.size() - 1; i < s.size() / 2; i++, j--) 44 | { 45 | swap(s[i], s[j]); 46 | } 47 | } 48 | 49 | template 50 | void printVector(vector &vec) 51 | { 52 | for (int i = 0; i < vec.size(); i++) 53 | { 54 | cout << vec[i]; 55 | } 56 | 57 | cout << endl; 58 | } 59 | 60 | int main(int argc, char const *argv[]) 61 | { 62 | Solution s; 63 | string arr1[] = {"h", "e", "l", "l", "o"}; 64 | vector str1(arr1, arr1 + sizeof(arr1) / sizeof(string)); 65 | 66 | cout << "字符串:"; 67 | printVector(str1); 68 | cout << endl; 69 | 70 | cout << "反转后:"; 71 | s.reverseString(str1); 72 | printVector(str1); 73 | cout << endl; 74 | 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /leetcode/two_pointers/reverse_words_in_a_string: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chachaxw/data-structure-and-algorithm/9ecf2538167ad8f4033e6848f3539968b30c63d7/leetcode/two_pointers/reverse_words_in_a_string -------------------------------------------------------------------------------- /ts/game.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | input: 4 | - gameBoardWidth: int 5 | - gameBoardHeight: int 6 | - mPosition: ? 7 | - hPosition: ? 8 | 9 | output: 10 | 11 | function render(input: ...): string[] 12 | 13 | [ 14 | "XXXXXXXXXXXXX", 15 | "X.......H...X", 16 | "X...........X", 17 | "X.M.........X", 18 | "X...........X", 19 | "XXXXXXXXXXXXX", 20 | ] 21 | 22 | */ 23 | class Game { 24 | constructor(gameBoardWidth, gameBoardHeight, mPosition, hPosition) { 25 | this.container = []; 26 | this.gameBoardWidth = gameBoardWidth; 27 | this.gameBoardHeight = gameBoardHeight; 28 | this.mPosition = mPosition; 29 | this.hPosition = hPosition; 30 | this.render(); 31 | } 32 | render() { 33 | for (let i = 0; i < this.gameBoardHeight; i++) { 34 | let wall = "X"; 35 | for (let j = 1; j < this.gameBoardWidth; j++) { 36 | if (i === 0 || i === this.gameBoardHeight - 1) { 37 | wall += "X"; 38 | } 39 | else { 40 | if (j === this.gameBoardWidth - 1) { 41 | wall += "X"; 42 | } 43 | else { 44 | if (i === this.mPosition.x && j === this.mPosition.y) { 45 | wall += "M"; 46 | } 47 | else if (i === this.hPosition.x && 48 | j === this.hPosition.y) { 49 | wall += "H"; 50 | } 51 | else { 52 | wall += "."; 53 | } 54 | } 55 | } 56 | } 57 | this.container.push(wall); 58 | } 59 | } 60 | } 61 | const m = { x: 3, y: 2 }; 62 | const h = { x: 1, y: 8 }; 63 | const game = new Game(13, 6, m, h); 64 | console.log(game); 65 | -------------------------------------------------------------------------------- /ts/game.ts: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | input: 4 | - gameBoardWidth: int 5 | - gameBoardHeight: int 6 | - mPosition: ? 7 | - hPosition: ? 8 | 9 | output: 10 | 11 | function render(input: ...): string[] 12 | 13 | [ 14 | "XXXXXXXXXXXXX", 15 | "X.......H...X", 16 | "X...........X", 17 | "X.M.........X", 18 | "X...........X", 19 | "XXXXXXXXXXXXX", 20 | ] 21 | 22 | */ 23 | 24 | interface Position { 25 | x: number; 26 | y: number; 27 | } 28 | 29 | class Game { 30 | public gameBoardWidth: number; 31 | public gameBoardHeight: number; 32 | public mPosition: Position; 33 | public hPosition: Position; 34 | 35 | public container: string[] = []; 36 | 37 | constructor( 38 | gameBoardWidth: number, 39 | gameBoardHeight: number, 40 | mPosition: Position, 41 | hPosition: Position 42 | ) { 43 | this.gameBoardWidth = gameBoardWidth; 44 | this.gameBoardHeight = gameBoardHeight; 45 | this.mPosition = mPosition; 46 | this.hPosition = hPosition; 47 | this.render(); 48 | } 49 | 50 | public render() { 51 | for (let i = 0; i < this.gameBoardHeight; i++) { 52 | let wall: string = "X"; 53 | 54 | for (let j = 1; j < this.gameBoardWidth; j++) { 55 | if (i === 0 || i === this.gameBoardHeight - 1) { 56 | wall += "X"; 57 | } else { 58 | if (j === this.gameBoardWidth - 1) { 59 | wall += "X"; 60 | } else { 61 | if (i === this.mPosition.x && j === this.mPosition.y) { 62 | wall += "M"; 63 | } else if ( 64 | i === this.hPosition.x && 65 | j === this.hPosition.y 66 | ) { 67 | wall += "H"; 68 | } else { 69 | wall += "."; 70 | } 71 | } 72 | } 73 | } 74 | 75 | this.container.push(wall); 76 | } 77 | } 78 | } 79 | 80 | const m: Position = { x: 3, y: 2 }; 81 | const h: Position = { x: 1, y: 8 }; 82 | const game = new Game(13, 6, m, h); 83 | 84 | console.log(game); 85 | -------------------------------------------------------------------------------- /ts/type.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-10 14:35:33 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-10 15:08:36 6 | */ 7 | /** 8 | * Typescript常见类型 9 | * 10 | */ 11 | /** 12 | * Unknown 13 | * 是不可预先定义的类型,在多数情况下,它用于代替 any 的功能同时保留静态检查的能力。 14 | * 在静态编译的时候,unknown 不能调用任何方法,而 any 可以。 15 | * 16 | */ 17 | const num = 10; 18 | num.split(""); // 这里和 any 一样完全用于通过静态检查 19 | const str = "hello world"; 20 | // str.split(" "); // Error: 静态检查不通过报错 21 | // unknown 的一个使用场景,避免使用 any 作为函数的参数类型而导致的静态类型检查 bug 22 | function testUnknown(params) { 23 | if (Array.isArray(params)) { 24 | return params.length; // Pass: 这个代码块中,类型守卫已经将 params 识别为 Array 类型 25 | } 26 | // return params.length; // Error: 这里的 params 为 unknown 类型,静态检查报错,如果入参是 any 类型,则会放弃类型检查,直接成功,带来报错风险。 27 | throw new Error("Params type is unknown"); 28 | } 29 | /** 30 | * Enum 31 | * TypeScript支持数字的和基于字符串的枚举。 32 | * 33 | */ 34 | // 数字枚举 35 | // 如上,我们定义了一个数字枚举, Up使用初始化为 1。 其余的成员会从 1开始自动增长。 36 | // 换句话说, Direction.Up的值为 1, Down为 2, Left为 3, Right为 4。 37 | var Direction; 38 | (function (Direction) { 39 | Direction[Direction["Up"] = 1] = "Up"; 40 | Direction[Direction["Down"] = 2] = "Down"; 41 | Direction[Direction["Left"] = 3] = "Left"; 42 | Direction[Direction["Right"] = 4] = "Right"; 43 | })(Direction || (Direction = {})); 44 | // 字符串枚举 45 | // 在一个字符串枚举里,每个成员都必须用字符串字面量,或另外一个字符串枚举成员进行初始化。 46 | var Direction1; 47 | (function (Direction1) { 48 | Direction1["Up"] = "UP"; 49 | Direction1["Down"] = "DOWN"; 50 | Direction1["Left"] = "LEFT"; 51 | Direction1["Right"] = "RIGHT"; 52 | })(Direction1 || (Direction1 = {})); 53 | // 计算成员和常量成员 54 | var FileAccess; 55 | (function (FileAccess) { 56 | // constant members 57 | FileAccess[FileAccess["None"] = 0] = "None"; 58 | FileAccess[FileAccess["Read"] = 2] = "Read"; 59 | FileAccess[FileAccess["Write"] = 4] = "Write"; 60 | FileAccess[FileAccess["ReadWrite"] = 6] = "ReadWrite"; 61 | // computed member 62 | FileAccess[FileAccess["G"] = "123".length] = "G"; 63 | })(FileAccess || (FileAccess = {})); 64 | /** 65 | * void 66 | * 在 Typescript 中,void 与 undefined 功能很类似,用于在逻辑上避免不经意使用了空指针导致的错误。 67 | * void 和 undefined 类型最大的区别是: undefined 是 void 的子集,当你对函数的返回值并不在意时,使用 void 而不是 undefined。 68 | */ 69 | -------------------------------------------------------------------------------- /ts/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Chacha 3 | * @Date: 2022-04-10 14:35:33 4 | * @Last Modified by: Chacha 5 | * @Last Modified time: 2022-04-10 15:32:05 6 | */ 7 | /** 8 | * Typescript常见类型 9 | * 10 | */ 11 | 12 | /** 13 | * Unknown 14 | * 是不可预先定义的类型,在多数情况下,它用于代替 any 的功能同时保留静态检查的能力。 15 | * 在静态编译的时候,unknown 不能调用任何方法,而 any 可以。 16 | * 17 | */ 18 | const num: number = 10; 19 | (num as unknown as string).split(""); // 这里和 any 一样完全用于通过静态检查 20 | 21 | const str: unknown = "hello world"; 22 | // str.split(" "); // Error: 静态检查不通过报错 23 | 24 | // unknown 的一个使用场景,避免使用 any 作为函数的参数类型而导致的静态类型检查 bug 25 | function testUnknown(params: unknown): number { 26 | if (Array.isArray(params)) { 27 | return params.length; // Pass: 这个代码块中,类型守卫已经将 params 识别为 Array 类型 28 | } 29 | 30 | // return params.length; // Error: 这里的 params 为 unknown 类型,静态检查报错,如果入参是 any 类型,则会放弃类型检查,直接成功,带来报错风险。 31 | throw new Error("Params type is unknown"); 32 | } 33 | /** 34 | * Enum 35 | * TypeScript支持数字的和基于字符串的枚举。 36 | * 37 | */ 38 | 39 | // 数字枚举 40 | // 如上,我们定义了一个数字枚举, Up使用初始化为 1。 其余的成员会从 1开始自动增长。 41 | // 换句话说, Direction.Up的值为 1, Down为 2, Left为 3, Right为 4。 42 | enum Direction { 43 | Up = 1, 44 | Down, 45 | Left, 46 | Right, 47 | } 48 | 49 | // 字符串枚举 50 | // 在一个字符串枚举里,每个成员都必须用字符串字面量,或另外一个字符串枚举成员进行初始化。 51 | enum Direction1 { 52 | Up = "UP", 53 | Down = "DOWN", 54 | Left = "LEFT", 55 | Right = "RIGHT", 56 | } 57 | 58 | // 计算成员和常量成员 59 | enum FileAccess { 60 | // constant members 61 | None, 62 | Read = 1 << 1, 63 | Write = 1 << 2, 64 | ReadWrite = Read | Write, 65 | // computed member 66 | G = "123".length, 67 | } 68 | 69 | /** 70 | * void 71 | * 在 Typescript 中,void 与 undefined 功能很类似,用于在逻辑上避免不经意使用了空指针导致的错误。 72 | * void 和 undefined 类型最大的区别是: undefined 是 void 的子集,当你对函数的返回值并不在意时,使用 void 而不是 undefined。 73 | * 74 | */ 75 | 76 | /** 77 | * Tuple 78 | * 元组(Tuple)表示一个已知数量和类型的数组,可以理解它是一种特殊的数组。 79 | * 80 | */ 81 | const tuple: [string, number] = ["Hello", 1]; 82 | 83 | /** 84 | * never 85 | * never 类型是没法正常结束返回的类型,一个必定会报错或死循环的函数会返回这样的类型。 86 | * 87 | */ 88 | function testNever(): never { 89 | throw new Error("testNever return never type"); 90 | } 91 | function testNever1(): never { 92 | while (true) {} 93 | } 94 | 95 | // 任何类型联合上 never 类型,还是原来的类型 96 | type language = "TS" | never; 97 | --------------------------------------------------------------------------------