├── .gitignore ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── algo ├── .gitignore ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── algo.gemspec ├── bin │ ├── console │ └── setup ├── lib │ ├── algo.rb │ ├── algo │ │ └── version.rb │ ├── bsearch │ │ ├── .DS_Store │ │ ├── bsearch.py │ │ ├── bsearch.rb │ │ ├── test.py │ │ ├── test.rb │ │ └── tests │ │ │ └── sqrt(x).rb │ ├── heap │ │ └── heap.rb │ ├── ordered_set.rb │ ├── quick_sort.rb │ └── trie │ │ ├── trie.rb │ │ └── trie_alternative.rb └── sig │ └── algo.rbs └── templates ├── .gitignore ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin ├── console └── setup ├── lib ├── @@TEMPLATE - Array - Dynamic Programming.rb ├── @@TEMPLATE - BST : Binary Search.rb ├── @@TEMPLATE - Backtracking.rb ├── @@TEMPLATE - Graph - Connected Component.rb ├── @@TEMPLATE - Graph - Topological Sort.rb ├── @@TEMPLATE - Intervals.rb ├── @@TEMPLATE - Kth Smallest.rb ├── @@TEMPLATE - Optimal Path.rb ├── @@TEMPLATE - Shortest Distance : BFS.rb ├── @@TEMPLATE - Sliding Window.rb ├── @@TEMPLATE - Tree.rb ├── @@TEMPLATE - binary search.rb ├── @@TEMPLATE - merge : intersection.rb ├── @@TEMPLATE - trie.rb ├── templates.rb └── templates │ └── version.rb ├── sig └── templates.rbs └── templates.gemspec /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | /.config 4 | /coverage/ 5 | /InstalledFiles 6 | /pkg/ 7 | /spec/reports/ 8 | /spec/examples.txt 9 | /test/tmp/ 10 | /test/version_tmp/ 11 | /tmp/ 12 | 13 | # Used by dotenv library to load environment variables. 14 | # .env 15 | 16 | # Ignore Byebug command history file. 17 | .byebug_history 18 | 19 | ## Specific to RubyMotion: 20 | .dat* 21 | .repl_history 22 | build/ 23 | *.bridgesupport 24 | build-iPhoneOS/ 25 | build-iPhoneSimulator/ 26 | 27 | ## Specific to RubyMotion (use of CocoaPods): 28 | # 29 | # We recommend against adding the Pods directory to your .gitignore. However 30 | # you should judge for yourself, the pros and cons are mentioned at: 31 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 32 | # 33 | # vendor/Pods/ 34 | 35 | ## Documentation cache and generated files: 36 | /.yardoc/ 37 | /_yardoc/ 38 | /doc/ 39 | /rdoc/ 40 | 41 | ## Environment normalization: 42 | /.bundle/ 43 | /vendor/bundle 44 | /lib/bundler/man/ 45 | 46 | # for a library or gem, you might want to ignore these files since the code is 47 | # intended to run in multiple environments; otherwise, check them in: 48 | # Gemfile.lock 49 | # .ruby-version 50 | # .ruby-gemset 51 | 52 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 53 | .rvmrc 54 | 55 | # Used by RuboCop. Remote config files pulled in from inherit_from directive. 56 | # .rubocop-https?--* 57 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | # gem "rails" 6 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | 5 | PLATFORMS 6 | x86_64-darwin-21 7 | 8 | DEPENDENCIES 9 | 10 | BUNDLED WITH 11 | 2.3.7 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 April 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # algorithm-templates 2 | A collection of some generic template question for algorithm interview questions 3 | 4 | 部分topic已经整理收录到博客 https://smilence-yu.gitbook.io/coding/ 中 5 | 6 | ## Subarray 问题 7 | 8 | ## Sliding Window 9 | 10 | > Sliding window 通常用于处理subarray / substring 长度确定,或者window长度受到某个因素制约(越扩张越接近条件)的问题。 11 | 12 | 比如 Longest subarray / Longest substring / pattern match, 用sliding window处理, 并且update global state (max, indices etc) 13 | 14 | ## Array - Dynamic Programming / 递推问题 15 | 16 | 求解满足条件,或者最优的subarray / substring / subsequence / pair 的问题,用dynamic programming。也就是观察:如果需要对以idx为结尾的pair或者subarray得出结论,我们需要从前面的循环中获得什么信息呢?(与divide and conquer的思路相似) 然后再尽可能通过每一步cache的方式,使得这个信息能够被高效地得到 17 | 18 | *通常可以从idx = 1开始遍历,使得第一个元素直接成为初始值,简化处理* 19 | 20 | - e.g. [Maximum Product Array](https://leetcode.com/problems/maximum-product-subarray/) 21 | 22 | *与sliding window的显著区别是,当subarray end_idx在expand时,并不能使得左侧start index收缩* 23 | 24 | ## Array - Intersection / Merge 25 | 26 | 2个或多个array intersect或merge的问题,每次所有array中头部的最小元素,作为当前的candidate,然后移动对应array的index。 27 | 28 | - e.g. [Two Person Meeting Scheduler](https://leetcode.com/problems/meeting-scheduler/) 29 | 30 | 如果两个array有一个特别短,则对短array循环,对长array做binary search查找对应元素 31 | - e.g. [Sparse Vector Dot](https://leetcode.com/discuss/interview-question/124823/dot-product-of-sparse-vector) 32 | 33 | 对于k个array的情况,用heap作为缓存来求当前的最小元素。 34 | - e.g. [Merge K sorted Lists](https://leetcode.com/problems/merge-k-sorted-lists/) 35 | - e.g. [Sorted Iterator Over K Sorted Lists](https://leetcode.com/discuss/interview-question/169334/facebook-phone-screen-sorted-iterator) 36 | 37 | ## Event / Interval 38 | 39 | - 求两个interval的overlap或merge 40 | 41 | ```Ruby 42 | low_a, high_a = intervals_a[idx_a] 43 | low_b, high_b = intervals_b[idx_b] 44 | 45 | # overlap 46 | low = [low_a, low_b].max 47 | high = [high_a, high_b].min 48 | 49 | # merge (assume a.start < b.start) 和overlap反过来 50 | if low_b <= high_a # has overlap 51 | low = [low_a, low_b].min 52 | high = [high_a, high_b].max 53 | end 54 | ``` 55 | 56 | - 一个list内merge interval的问题,用sliding window,然后试图求`window`与当前interval的overlap,当没有overlap时switch window。 57 | 58 | - e.g. [Insert Interval](https://leetcode.com/problems/insert-interval/) 59 | 60 | - 对两个list求interval intersection的问题,用array - intersection的方法,当两者有overlap时添加这个intersection,然后根据两个interval的high来选择哪个list前进 61 | 62 | - 更复杂的问题例如有两人以上或者求满足特定条件的interval问题,统一用`Event`来表示interval的开始和结束,然后sort所有的event依次用sliding window处理,当计数由0变正数时就是window的开始,由正数变0时就是window的结束。 63 | - e.g. [Meeting Rooms II] 64 | - 如果在同一时间可能发生多个事件并且可能有冲突,那么应该按照时间对event归类然后再对这些时间bucket进行sort,每次处理一个bucket而非一个event 65 | - e.g. [Skyline Problem] 66 | 67 | ## Optimal Path - Memoization 68 | 69 | - 如果是最短路径或者最小数量优先考虑用BFS. 如果是从任何点到达某个点或任何点,可以将所有出发点都放入queue然后进行BFS 70 | - e.g. [Jump Game II] 71 | - e.g. [Perfect Squares] 72 | - 注意所有变动参数必须作为memoization的function param, 所以memoization不能使用变动的全局变量,而需要记录visiting的问题无法使用memoization 73 | - 对于coin change或者perfect squares这一类可以重复使用的,优先每次尝试所有选择的办法,这样可以节省空间复杂度 74 | 75 | ## Backtracking 76 | 77 | - 在递归的每一层 需要跳过重复的选择 但是不影响下一层 78 | 79 | - e.g. [Combination Sum II](https://leetcode.com/problems/combination-sum-ii/) 80 | 81 | ## Graph 82 | 83 | ### 无向图 Connected Component 问题: Graph => 多个part (array of array) 84 | 85 | 给出相互之间的联系,把元素归类起来的问题: 86 | 87 | 可以循环所有点出发DFS,用@visiting记录访问过的点 (注意@visiting在DFS时不需要revert),这些点就是connected component。用ordered set @visited记录所有访问过的点 88 | 89 | **connected component关注的是每一个section的访问痕迹,也就是`@visiting`** 90 | 91 | ```Ruby 92 | def traverse() 93 | @visited = Set.new 94 | (0...matrix.length).each do |i| 95 | (0...matrix[0].length).each do |j| 96 | next if @visited.include?([i, j]) 97 | @visiting = Set.new 98 | traverse_from([i, j]) 99 | # here we have @visiting as connected components 100 | end 101 | end 102 | end 103 | 104 | def traverse_from(cell) 105 | return if @visiting.include?(cell) 106 | 107 | @visiting.add(cell) 108 | @vertex_children_map[cell].do |next_cell| 109 | traverse_from(next_cell) 110 | end 111 | @visited.add(cell) 112 | end 113 | ``` 114 | 115 | - e.g. [Friend Circles](https://leetcode.com/problems/friend-circles/)
116 | - e.g. [Shortest Bridge](https://leetcode.com/problems/shortest-bridge/)
117 | - e.g. [Number of Islands](https://leetcode.com/problems/number-of-islands/)
118 | - e.g. [Max area of Island](https://leetcode.com/problems/max-area-of-island/)
119 | - e.g. [Account Merge](https://leetcode.com/problems/accounts-merge/)
120 | 121 | *有向图查找connected components要复杂的多,这里不做探讨* 122 | 123 | 124 | ### 有向图 Topological Sort 问题: Graph => 任意路径 (array) 125 | 126 | 给定一系列先后关系 (parent -> children) ,求一条尊重所有这些先后关系的路径 127 | 从所有点出发DFS,用@visiting防止circle 用ordered hash @visited记录所有访问过的点。最后将@visited反向。 128 | 129 | **topological sort关注的是整个graph的访问而不是每一个section,也就是`@visited`** 130 | 131 | 132 | - e.g. [Alien Dictionary](https://leetcode.com/problems/alien-dictionary/) 133 | - e.g. [Course Schedule] 134 | - e.g. [Course Schedule II] 135 | - e.g. [Dependency Resolver] 136 | 137 | ### 单点出发求满足条件的单条路径问题: 见 # backtracking 138 | 139 | `@visiting`改成hash,找到满足条件的路径时raise error退出,或放入output array 140 | 141 | - 如果edge附带其他信息或者并不与 `[parent, children]` pair 一一对应,那么`visited`应该记录ticket_ids 而不是nodes 142 | - e.g. [Reconstruct Itinerary] 143 | 144 | ## Tree 145 | 146 | - 需要按层访问 => BFS 147 | 148 | - 访问/查找节点,与tree的结构无关 => DFS (preorder, inorder, postorder) 149 | 150 | - 与tree的结构有关的问题 => Divide and Conquer 151 | - 首先identify 需要从subtree获得哪些信息才能够得到题意要求的结论 (e.g. 是不是BST) 152 | - 有些情况下还需要看给subtree什么信息 153 | - 那么当前tree也需要返回这些信息,如何把left tree和right tree的这些信息组合起来 154 | - globally,我们需要更新哪些信息?(e.g. 我们每次递归只关注以当前node为root的tree的结论,需要更新全局结论, 这种情形尤其注意不能early return因为会错过right tree) 155 | 156 | 157 | ## BST 问题 158 | 159 | BST问题总是可以先思考,如果是sorted array,这个问题如何解决?然后有两种解决办法 160 | - 如果对sorted array我们会binary search,那么根据root的大小来决定对left tree或者right tree 进行 traverse, 根据问题需要的输出顺序决定inorder或者preorder traversal (比如range sum 就可以任意选择) 161 | ```Ruby 162 | def search_recursive(node) 163 | return if node.nil? 164 | 165 | traverse(node.left) if @low_bound < node.val 166 | visit(node) 167 | traverse(node.right) if node.val < @high_bound 168 | end 169 | 170 | def search_iterative(node, target) 171 | while node 172 | return node if node.val == target 173 | if target < node.val 174 | node = node.left 175 | else 176 | node = node.right 177 | end 178 | end 179 | end 180 | ``` 181 | - e.g. [Range Sum BST](https://leetcode.com/problems/range-sum-of-bst/) 182 | - e.g. [Inorder Successor in BST](https://leetcode.com/problems/inorder-successor-in-bst/) 183 | - e.g. [Closest Binary Search Tree Value](https://leetcode.com/problems/kth-smallest-element-in-a-bst/) 184 | 185 | 186 | - 如果对sorted array我们会linear search,那么进行inorder traversal. `visit(node)` 访问当前node的部分,可以想象成在array的循环内会写的内容 187 | 188 | - e.g. [kth smallest element in BST]() 189 | - e.g. [Validate Binary Search Tree] 190 | 191 | ## List to Tree 问题 - 线性结构转换成树状结构的问题 192 | 193 | 总是用divide and conquer的思路,将一个element转换成root,一部分转换成left tree,另一部分转换成right tree. 194 | 195 | > 只不过与其在递归的每一层查找分界点,可以在**横向**向右推进cursor,同时在**纵向**往深处递归. 这样的话,每次cursor前进的速度和递归构建root node的速度一样。类似于linkedlist转换成一个array (我们的递归也无非就是一个形式不一样的iterator),因此总是能保证当前cursor指向的element就是我们当前递归深度需要的element. 196 | 197 | 1. [Calculator](https://leetcode.com/problems/basic-calculator-iii/) (计算器的计算本质上是树状结构) 198 | 2. [Serialize and Deserialize BST](https://leetcode.com/problems/serialize-and-deserialize-bst/) 199 | 3. [Serialize and Deserialize Binary Tree](https://leetcode.com/problems/serialize-and-deserialize-binary-tree/) 200 | 4. [Convert Sorted List to a BST](https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/) 201 | 202 | ## 缓存 (buffer) 问题 203 | 204 | 数据的流向: 输出 <= buffer (pool) <= 数据源 205 | 206 | 1. 从pool里拿数据 207 | 2. pool从数据源补充数据 208 | 3. 直到 已经拿够数据,或者pool已掏空,whichever come first 209 | 210 | 这个pool,如果是先进先出,那么用 `queue`, 如果每次需要拿最大或最小,则使用 `Heap` 即 `"Priority Queue"` 211 | 212 | > e.g. https://leetcode.com/problems/read-n-characters-given-read4-ii-call-multiple-times/ 213 | 214 | ## 查找 Kth Element 问题 215 | 216 | 对于 N sorted sequence, 用min heap `O(klgn)` (或binary search) 见:Array - Intersection / Merge section 217 | 218 | > e.g. [Kth Smallest Element in a Sorted Matrix](https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/) 219 | > e.g. [Merge k Sorted Lists](https://leetcode.com/problems/merge-k-sorted-lists/) 220 | 221 | 对于 sorted sequence, 用 binary search 222 | 223 | > e.g. [Missing Element In Sorted Array](https://leetcode.com/problems/missing-element-in-sorted-array/) 224 | 225 | 对于 unsorted collection,用max heap of size k (如果是kth largest 就是minheap), Time Complexity: `O(nlgk)` 226 | 227 | > e.g. [kth Largest Element in an Array](https://leetcode.com/problems/kth-largest-element-in-an-array/) 228 | 229 | 如果value的范围有限, 也可以用bucket来记录value的分布, 进而得到 kth largest or kth smallest 230 | 231 | > e.g. [Top K Frequent Elements](https://leetcode.com/problems/top-k-frequent-elements/) *这里频率最大也就是·`O(n)`* 232 | 233 | ## 抵消问题 (Offset) 234 | 235 | 用stack来记录需要抵消的元素,这个元素需要包含抵消处理时需要的所有信息。 236 | 237 | - e.g. [Asteroid Collision](https://leetcode.com/problems/asteroid-collision/) 238 | 239 | 当需要每次抵消多个相同元素时,用一个 `Struct.new(:value, :frequency)` 来代替原始的元素 240 | 241 | - e.g. [Remove All Adjacent Duplicates in String II](https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string-ii/) 242 | - e.g. [Exclusive Time of Functions](https://leetcode.com/problems/exclusive-time-of-functions/) 243 | 244 | 当只有正反两种元素并且我们只在意他们的数量,而不在意他们的位置是,可以用变量来记录他们的数量(balance) 245 | 246 | - e.g. [Minimum Remove to Make Valid Parentheses](https://leetcode.com/problems/minimum-remove-to-make-valid-parentheses/) 247 | 248 | 对抵消的元素有先后顺序的情况,比如括号,stack里可以存元素的index,这样在抵消时还可以检查先后顺序。 249 | 250 | - e.g. [Longest Valid Parentheses] 251 | 252 | *对于一次遍历时无法做出的选择,比如左括号与右括号如何配对, 可以考虑两次遍历* 253 | - e.g. [Valid Parenthesis String](https://leetcode.com/problems/valid-parenthesis-string/) 254 | 255 | 当offset问题需要优化到 `O(1)` 空间时,因为这类问题后面可以抵消前面的属性,可以考虑从后往前遍历 256 | 257 | - e.g. [Backspace String Compare] 258 | 259 | 260 | ## Palindrome问题 261 | 262 | 1. Expand around center 263 | 2. Dynamic Programming 264 | 265 | ## Binary Search问题 266 | 267 | 具有递增递减趋势的array 或者 有限定范围的整数range 查找符合条件的元素,首先想到用binary search找中间点,然后问题的关键在于如何选择往左还是往右 268 | 269 | 1. 我们知道的信息,无非就是头尾的index,中间的index,以及头尾值和中间值 270 | 2. 通过这些信息来决定往左还是往右查找 271 | 272 | e.g. [Single Element in a Sorted Array](https://leetcode.com/problems/single-element-in-a-sorted-array/) (通过index来判断) 273 | 274 | e.g. [Missing Element in Sorted Array](https://leetcode.com/problems/missing-element-in-sorted-array/) (通过index以及值来判断) 275 | 276 | ## Unique Path 277 | -------------------------------------------------------------------------------- /algo/.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | -------------------------------------------------------------------------------- /algo/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | # Specify your gem's dependencies in algo.gemspec 6 | gemspec 7 | 8 | gem "rake", "~> 13.0" 9 | -------------------------------------------------------------------------------- /algo/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022 TODO: Write your name 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /algo/README.md: -------------------------------------------------------------------------------- 1 | # Algo 2 | 3 | Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/algo`. To experiment with that code, run `bin/console` for an interactive prompt. 4 | 5 | TODO: Delete this and the text above, and describe your gem 6 | 7 | ## Installation 8 | 9 | Add this line to your application's Gemfile: 10 | 11 | ```ruby 12 | gem 'algo' 13 | ``` 14 | 15 | And then execute: 16 | 17 | $ bundle install 18 | 19 | Or install it yourself as: 20 | 21 | $ gem install algo 22 | 23 | ## Usage 24 | 25 | TODO: Write usage instructions here 26 | 27 | ## Development 28 | 29 | After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 30 | 31 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). 32 | 33 | ## Contributing 34 | 35 | Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/algo. 36 | 37 | ## License 38 | 39 | The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). 40 | -------------------------------------------------------------------------------- /algo/Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "bundler/gem_tasks" 4 | task default: %i[] 5 | -------------------------------------------------------------------------------- /algo/algo.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "lib/algo/version" 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = "algo" 7 | spec.version = 0.1 8 | spec.authors = ["April Li"] 9 | spec.email = ["greatday4april@gmail.com"] 10 | 11 | spec.summary = "self explanatory" 12 | spec.description = "self explanatory" 13 | spec.homepage = "https://github.com/greatday4april/algorithm-templates" 14 | spec.license = "MIT" 15 | spec.required_ruby_version = ">= 2.6.0" 16 | 17 | spec.metadata["allowed_push_host"] = "https://github.com/greatday4april/algorithm-templates" 18 | 19 | spec.metadata["homepage_uri"] = spec.homepage 20 | spec.metadata["source_code_uri"] = "https://github.com/greatday4april/algorithm-template." 21 | spec.metadata["changelog_uri"] = "https://github.com/greatday4april/algorithm-templates" 22 | 23 | # Specify which files should be added to the gem when it is released. 24 | # The `git ls-files -z` loads the files in the RubyGem that have been added into git. 25 | spec.files = Dir['README.md', 'lib/**/*', 'lib/*'] 26 | spec.bindir = "exe" 27 | spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } 28 | spec.require_paths = ["lib"] 29 | 30 | # Uncomment to register a new dependency of your gem 31 | # spec.add_dependency "example-gem", "~> 1.0" 32 | 33 | # For more information and examples about making a new gem, check out our 34 | # guide at: https://bundler.io/guides/creating_gem.html 35 | end 36 | -------------------------------------------------------------------------------- /algo/bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require "bundler/setup" 5 | require "algo" 6 | 7 | # You can add fixtures and/or initialization code here to make experimenting 8 | # with your gem easier. You can also use a different console, if you like. 9 | 10 | # (If you use this, don't forget to add pry to your Gemfile!) 11 | # require "pry" 12 | # Pry.start 13 | 14 | require "irb" 15 | IRB.start(__FILE__) 16 | -------------------------------------------------------------------------------- /algo/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /algo/lib/algo.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "algo/version" 4 | 5 | module Algo 6 | class Error < StandardError; end 7 | # Your code goes here... 8 | end 9 | -------------------------------------------------------------------------------- /algo/lib/algo/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Algo 4 | VERSION = "0.1.0" 5 | end 6 | -------------------------------------------------------------------------------- /algo/lib/bsearch/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greatday4april/algorithm-templates/de4dac9690223571d177536f88cbd7ed05fa02f3/algo/lib/bsearch/.DS_Store -------------------------------------------------------------------------------- /algo/lib/bsearch/bsearch.py: -------------------------------------------------------------------------------- 1 | from typing import List, Callable, Optional 2 | 3 | """ 4 | condition should be a function that evaluates as 5 | [False, False ... True, True, True], aka >= target 6 | """ 7 | 8 | 9 | def bsearch_low(arr: List[int], condition: Callable[[int], bool]) -> Optional[int]: 10 | low = 0 11 | high = len(arr) - 1 12 | while low <= high: 13 | mid = (low + high) // 2 14 | smaller = condition(arr[mid]) 15 | if smaller: 16 | high = mid - 1 17 | else: 18 | low = mid + 1 19 | 20 | if low >= len(arr): 21 | return None 22 | 23 | return low 24 | 25 | 26 | """ 27 | condition should be a function that evaluates as 28 | [True, True ... False, False, False], aka <= target 29 | """ 30 | 31 | 32 | def bsearch_high(arr: List[int], condition: Callable[[int], bool]) -> Optional[int]: 33 | low = 0 34 | high = len(arr) - 1 35 | while low <= high: 36 | mid = (low + high) // 2 # closer to high 37 | bigger = condition(arr[mid]) 38 | if bigger: 39 | low = mid + 1 40 | else: 41 | high = mid - 1 42 | 43 | if high < 0: 44 | return None 45 | 46 | return high 47 | 48 | 49 | if __name__ == '__main__': 50 | print(bsearch_low([], lambda ele: ele >= 2)) # None 51 | print(bsearch_high([], lambda ele: ele >= 2)) # None 52 | print(bsearch_low([1], lambda ele: ele >= 2)) # None 53 | print(bsearch_high([1], lambda ele: ele <= 0)) # None 54 | print('--------') 55 | 56 | print(bsearch_low([1], lambda ele: ele >= 1)) # 0 57 | print(bsearch_low([1], lambda ele: ele <= 1)) # 0 58 | print(bsearch_low([1, 3], lambda ele: ele >= 1)) # 0 59 | print(bsearch_high([1, 3], lambda ele: ele <= 1)) # 0 60 | print('--------') 61 | 62 | print(bsearch_low([1, 2, 3, 4, 5, 6], lambda ele: ele >= 4)) # 3 63 | print(bsearch_high([1, 2, 3, 4, 5, 6], lambda ele: ele <= 4)) # 3 64 | print('--------') 65 | 66 | print(bsearch_low([1, 2, 4, 4, 4, 5], lambda ele: ele >= 4)) # 2 67 | print(bsearch_low([1, 2, 4, 4, 4, 5], lambda ele: ele > 5)) # None 68 | print(bsearch_low([1, 2, 4, 4, 4, 5], lambda ele: ele >= 3)) # 2 69 | print('--------') 70 | 71 | print(bsearch_low([1, 2, 4, 4, 4, 5], lambda ele: ele >= 4)) # 2 72 | print(bsearch_high([1, 2, 4, 4, 4, 5], lambda ele: ele <= 4)) # 4 73 | print('--------') 74 | 75 | print(bsearch_low([1, 2, 4, 4, 4, 5], lambda ele: ele <= 0)) # None 76 | print(bsearch_high([1, 2, 4, 4, 4, 5], lambda ele: ele > 5)) # None 77 | -------------------------------------------------------------------------------- /algo/lib/bsearch/bsearch.rb: -------------------------------------------------------------------------------- 1 | class Array 2 | ''" 3 | condition should be a function that evaluates as 4 | [False, False ... True, True, True], aka >= target 5 | "'' 6 | def bsearch_low(&block) 7 | low = 0 8 | high = length - 1 9 | while low <= high 10 | mid = (low + high) / 2 11 | smaller = block.call(self[mid]) 12 | if smaller 13 | high = mid - 1 14 | else 15 | low = mid + 1 16 | end 17 | end 18 | return nil if low >= length 19 | 20 | low 21 | end 22 | 23 | ''" 24 | condition should be a function that evaluates as 25 | [True, True ... False, False, False], aka <= target 26 | "'' 27 | def bsearch_high(&block) 28 | low = 0 29 | high = length - 1 30 | while low <= high 31 | mid = (low + high) / 2 32 | bigger = block.call(self[mid]) 33 | if bigger 34 | low = mid + 1 35 | else 36 | high = mid - 1 37 | end 38 | end 39 | return nil if high < 0 40 | 41 | high 42 | end 43 | end 44 | 45 | if __FILE__ == $PROGRAM_NAME 46 | p [].bsearch_low { |ele| ele >= 2 } # nil 47 | p [].bsearch_high { |ele| ele >= 2 } # nil 48 | p [1].bsearch_low { |ele| ele >= 2 } # nil 49 | p [1].bsearch_high { |ele| ele <= 0 } # nil 50 | 51 | p [1].bsearch_low { |ele| ele >= 1 } # 0 52 | p [1].bsearch_high { |ele| ele <= 1 } # 0 53 | 54 | p [1, 3].bsearch_low { |ele| ele >= 1 } # 0 55 | p [1, 3].bsearch_high { |ele| ele <= 1 } # 0 56 | 57 | p [1, 2, 3, 4, 5, 6].bsearch_low { |ele| ele >= 4 } # 3 58 | p [1, 2, 3, 4, 5, 6].bsearch_high { |ele| ele <= 4 } # 3 59 | 60 | p [1, 2, 4, 4, 4, 5].bsearch_low { |ele| ele >= 4 } # 2 61 | p [1, 2, 4, 4, 4, 5].bsearch_low { |ele| ele > 5 } # nil 62 | p [1, 2, 4, 4, 4, 5].bsearch_low { |ele| ele >= 3 } # 2 63 | 64 | p [1, 2, 4, 4, 4, 5].bsearch_high { |ele| ele <= 4 } # 4 65 | p [1, 2, 4, 4, 4, 5].bsearch_high { |ele| ele <= 0 } # nil 66 | p [1, 2, 4, 4, 4, 5].bsearch_high { |ele| ele < 5 } # 4 67 | 68 | end 69 | -------------------------------------------------------------------------------- /algo/lib/bsearch/test.py: -------------------------------------------------------------------------------- 1 | from bsearch import bsearch_low, bsearch_high 2 | from typing import List 3 | 4 | 5 | def search_range(nums: List[int], target: int) -> List[int]: 6 | lower_bound = bsearch_low(nums, lambda ele: ele >= target) 7 | if lower_bound is None or (nums[lower_bound] != target): 8 | return [-1, -1] 9 | 10 | return [lower_bound, bsearch_high(nums, lambda ele: ele <= target)] 11 | 12 | 13 | nums = [1] 14 | target = 1 15 | print(search_range(nums, target)) # [0, 0] 16 | 17 | 18 | nums = [5, 7, 7, 8, 8, 10] 19 | target = 8 20 | print(search_range(nums, target)) # [3, 4] 21 | 22 | nums = [5, 7, 7, 8, 8, 10] 23 | target = 6 24 | print(search_range(nums, target)) # [-1, -1] 25 | -------------------------------------------------------------------------------- /algo/lib/bsearch/test.rb: -------------------------------------------------------------------------------- 1 | require_relative 'bsearch' 2 | 3 | ''" 4 | Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value. 5 | Your algorithm's runtime complexity must be in the order of O(log n). 6 | If the target is not found in the array, return [-1, -1]. 7 | "'' 8 | 9 | # @param {Integer[]} nums 10 | # @param {Integer} target 11 | # @return {Integer[]} 12 | def search_range(nums, target) 13 | lower_bound = nums.bsearch_low { |ele| ele >= target } 14 | return [-1, -1] if lower_bound.nil? || (nums[lower_bound] != target) 15 | 16 | [lower_bound, nums.bsearch_high { |ele| ele <= target }] 17 | end 18 | 19 | nums = [5, 7, 7, 8, 8, 10] 20 | target = 8 21 | p search_range(nums, target) # [3,4] 22 | 23 | nums = [5, 7, 7, 8, 8, 10] 24 | target = 6 25 | p search_range(nums, target) # [-1, -1] 26 | -------------------------------------------------------------------------------- /algo/lib/bsearch/tests/sqrt(x).rb: -------------------------------------------------------------------------------- 1 | require_relative '../bsearch' 2 | 3 | ''" 4 | Implement int sqrt(int x). 5 | 6 | Compute and return the square root of x, where x is guaranteed to be a non-negative integer. 7 | 8 | Since the return type is an integer, the decimal digits are truncated and only the integer part of the result is returned. 9 | "'' 10 | def my_sqrt(x) 11 | return 0 if x == 0 12 | 13 | low = 1 14 | high = x 15 | while low <= high 16 | mid = (low + high) / 2 17 | bigger = mid * mid <= x 18 | if bigger 19 | low = mid + 1 20 | else 21 | high = mid - 1 22 | end 23 | end 24 | 25 | high 26 | end 27 | 28 | p my_sqrt(4) 29 | p my_sqrt(8) 30 | p my_sqrt(24) 31 | p my_sqrt(36) 32 | -------------------------------------------------------------------------------- /algo/lib/heap/heap.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | class Heap 4 | # Implement a Heap using an array 5 | def initialize(elements=[], &compare_block) 6 | # Initialize arr with nil as first element 7 | # This dummy element makes it where first real element is at index 1 8 | # You can now divide i / 2 to find an element's parent 9 | # Elements' children are at i * 2 && (i * 2) + 1 10 | @compare_block = compare_block 11 | non_leaf_end_idx = (elements.length / 2).to_i 12 | @elements = [nil] + elements 13 | (1..non_leaf_end_idx).reverse_each do |idx| 14 | bubble_down(idx) 15 | end 16 | end 17 | 18 | def push(element) 19 | self << element 20 | end 21 | 22 | def <<(element) 23 | # push item onto end (bottom) of heap 24 | @elements.push(element) 25 | # then bubble it up until it's in the right spot 26 | bubble_up(@elements.length - 1) 27 | end 28 | 29 | def pop 30 | # swap the first and last elements 31 | @elements[1], @elements[@elements.length - 1] = @elements[@elements.length - 1], @elements[1] 32 | # Min element is now at end of arr (bottom of heap) 33 | top = @elements.pop 34 | # Now bubble the top element (previously the bottom element) down until it's in the correct spot 35 | bubble_down(1) 36 | # return the min element 37 | top 38 | end 39 | 40 | def top 41 | @elements[1] 42 | end 43 | 44 | def inspect 45 | "Heap: #{JSON.generate(@elements[1..-1])}" 46 | end 47 | 48 | def to_a 49 | @elements[1..-1] 50 | end 51 | 52 | def size 53 | @elements.size - 1 54 | end 55 | 56 | def empty? 57 | self.size == 0 58 | end 59 | 60 | def to_a 61 | @elements[1..-1] 62 | end 63 | 64 | private 65 | 66 | def bubble_up(index) 67 | parent_i = index / 2 68 | # Done if you reach top element or parent is already larger than child 69 | return if index <= 1 || @compare_block.call(@elements[parent_i], @elements[index]) 70 | 71 | # Otherwise, swap parent & child, then continue bubbling 72 | @elements[parent_i], @elements[index] = @elements[index], @elements[parent_i] 73 | 74 | bubble_up(parent_i) 75 | end 76 | 77 | def bubble_down(index) 78 | child_i = index * 2 79 | return if child_i > size 80 | 81 | # get largest child 82 | not_last = child_i < size 83 | left = @elements[child_i] 84 | right = @elements[child_i + 1] 85 | child_i += 1 if not_last && @compare_block.call(right, left) 86 | 87 | # stop if parent element is already larger than children 88 | return if @compare_block.call(@elements[index], @elements[child_i]) 89 | 90 | # otherwise, swap and continue 91 | @elements[index], @elements[child_i] = @elements[child_i], @elements[index] 92 | bubble_down(child_i) 93 | end 94 | end 95 | 96 | class MaxHeap < Heap 97 | def initialize(elements=[]) 98 | super(elements) {|ele_a, ele_b| (ele_a <=> ele_b) >= 0} 99 | end 100 | end 101 | 102 | class MinHeap < Heap 103 | def initialize(elements=[]) 104 | super(elements) {|ele_a, ele_b| (ele_a <=> ele_b) <= 0} 105 | end 106 | end 107 | 108 | if __FILE__ == $PROGRAM_NAME 109 | p MaxHeap.new([2, 3, 100, 56, 12, 24]) 110 | p MinHeap.new([2, 3, 100, 56, 12, 24]) 111 | end 112 | -------------------------------------------------------------------------------- /algo/lib/ordered_set.rb: -------------------------------------------------------------------------------- 1 | # implement a set that respects insertion order 2 | module Algo 3 | class OrderedSet 4 | def initialize 5 | @hash = {} 6 | end 7 | 8 | def add(element) 9 | @hash[element] = element 10 | end 11 | 12 | def delete(element) 13 | @hash.delete(element) 14 | end 15 | 16 | def include?(element) 17 | @hash.key?(element) 18 | end 19 | 20 | def shift 21 | @hash.shift.first 22 | end 23 | 24 | def first 25 | @hash.first.first 26 | end 27 | 28 | def to_a 29 | @hash.keys 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /algo/lib/quick_sort.rb: -------------------------------------------------------------------------------- 1 | def sort_array(nums) 2 | quick_sort(nums, 0, nums.length-1) 3 | nums 4 | end 5 | 6 | def quick_sort(arr, start_idx, end_idx) 7 | return if start_idx >= end_idx 8 | pivot_index = partition(arr, start_idx, end_idx) 9 | 10 | quick_sort(arr, start_idx, pivot_index - 1) 11 | quick_sort(arr, pivot_index, end_idx) 12 | end 13 | 14 | # left pointer is for 找不符合条件的数字,right pointer 是为了找到符合条件的数字,然后两个人交换。 15 | def partition(arr, start_idx, end_idx) 16 | # pick the last element as pivot 17 | pivot = arr[end_idx] 18 | 19 | left = start_idx 20 | (start_idx...end_idx).each do |right| 21 | if arr[right] <= pivot 22 | # swap with the current left 23 | arr[left], arr[right] = arr[right], arr[left] 24 | left += 1 25 | end 26 | end 27 | 28 | # swap pivot to the right position 29 | arr[left], arr[end_idx] = arr[end_idx], arr[left] 30 | left 31 | end 32 | 33 | class Array 34 | def merge_sort 35 | return clone if length <= 1 36 | 37 | mid = (length - 1) / 2 38 | left_array = self[0..mid].merge_sort 39 | right_array = self[(mid + 1)...length].merge_sort 40 | 41 | merged = [] 42 | left_idx = 0 43 | right_idx = 0 44 | until merged.length == length 45 | if left_idx < left_array.length && (right_idx >= right_array.length || left_array[left_idx] <= right_array[right_idx]) 46 | merged << left_array[left_idx] 47 | left_idx += 1 48 | else 49 | merged << right_array[right_idx] 50 | right_idx += 1 51 | end 52 | end 53 | merged 54 | end 55 | end -------------------------------------------------------------------------------- /algo/lib/trie/trie.rb: -------------------------------------------------------------------------------- 1 | class TrieNode 2 | attr_accessor :children, :word 3 | def initialize 4 | @children = {} 5 | @word = nil 6 | end 7 | end 8 | 9 | class Trie 10 | def initialize(words = []) 11 | @root = TrieNode.new 12 | words.each {|word| insert(word) } 13 | end 14 | 15 | def insert(word) 16 | node = @root 17 | word.each_char do |char| 18 | node.children[char] = TrieNode.new unless node.children.has_key?(char) 19 | node = node.children[char] 20 | end 21 | node.word = word 22 | end 23 | 24 | def search(word) 25 | node = @root 26 | word.each_char do |char| 27 | return false unless node.children.has_key?(char) 28 | 29 | node = node.children[char] 30 | end 31 | !node.word.nil? 32 | end 33 | 34 | def starts_with(prefix) 35 | node = @root 36 | prefix.each_char do |char| 37 | return false unless node.children.has_key?(char) 38 | 39 | node = node.children[char] 40 | end 41 | true 42 | end 43 | end 44 | 45 | if __FILE__ == $PROGRAM_NAME 46 | trie = Trie.new 47 | trie.insert('abc') 48 | p trie.starts_with('ab') 49 | p trie.search('ab') 50 | p trie.search('abc') 51 | 52 | 53 | end 54 | -------------------------------------------------------------------------------- /algo/lib/trie/trie_alternative.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greatday4april/algorithm-templates/de4dac9690223571d177536f88cbd7ed05fa02f3/algo/lib/trie/trie_alternative.rb -------------------------------------------------------------------------------- /algo/sig/algo.rbs: -------------------------------------------------------------------------------- 1 | module Algo 2 | VERSION: String 3 | # See the writing guide of rbs: https://github.com/ruby/rbs#guides 4 | end 5 | -------------------------------------------------------------------------------- /templates/.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | -------------------------------------------------------------------------------- /templates/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | # Specify your gem's dependencies in templates.gemspec 6 | gemspec 7 | 8 | gem "rake", "~> 13.0" 9 | -------------------------------------------------------------------------------- /templates/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022 TODO: Write your name 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /templates/README.md: -------------------------------------------------------------------------------- 1 | # Templates 2 | 3 | Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/templates`. To experiment with that code, run `bin/console` for an interactive prompt. 4 | 5 | TODO: Delete this and the text above, and describe your gem 6 | 7 | ## Installation 8 | 9 | Add this line to your application's Gemfile: 10 | 11 | ```ruby 12 | gem 'templates' 13 | ``` 14 | 15 | And then execute: 16 | 17 | $ bundle install 18 | 19 | Or install it yourself as: 20 | 21 | $ gem install templates 22 | 23 | ## Usage 24 | 25 | TODO: Write usage instructions here 26 | 27 | ## Development 28 | 29 | After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 30 | 31 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). 32 | 33 | ## Contributing 34 | 35 | Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/templates. 36 | 37 | ## License 38 | 39 | The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). 40 | -------------------------------------------------------------------------------- /templates/Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "bundler/gem_tasks" 4 | task default: %i[] 5 | -------------------------------------------------------------------------------- /templates/bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require "bundler/setup" 5 | require "templates" 6 | 7 | # You can add fixtures and/or initialization code here to make experimenting 8 | # with your gem easier. You can also use a different console, if you like. 9 | 10 | # (If you use this, don't forget to add pry to your Gemfile!) 11 | # require "pry" 12 | # Pry.start 13 | 14 | require "irb" 15 | IRB.start(__FILE__) 16 | -------------------------------------------------------------------------------- /templates/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /templates/lib/@@TEMPLATE - Array - Dynamic Programming.rb: -------------------------------------------------------------------------------- 1 | # Array Dynamic Programming 2 | 3 | def optimal_subarray() 4 | return 0 if nums.empty? 5 | 6 | # global 7 | optimal_value = nums.first 8 | 9 | # local state that needed from the smaller subarray 10 | optimal_value_to = nums.first 11 | 12 | (1...nums.length).each do |idx| 13 | num = nums[idx] 14 | 15 | # TODO some form of induction 16 | optimal_value_to = [ 17 | optimal_value_to + num, 18 | num 19 | ].max 20 | 21 | optimal_value = [optimal_value, optimal_value_to].max 22 | end 23 | 24 | return optimal_value 25 | end 26 | 27 | 28 | def optimal_subsequence(nums) 29 | return 0 if nums.empty? 30 | 31 | idx_length_map = {0 => 1} # or length_idx_map, depends on the lookup we want 32 | 33 | (1...nums.length).each do |end_idx| 34 | number = nums[end_idx] 35 | max_length = 1 36 | (0...end_idx).each do |prev_idx| 37 | if nums[prev_idx] < number # matches the subsequence requirement 38 | max_length = [ 39 | idx_length_map[prev_idx] + 1, 40 | max_length 41 | ].max 42 | end 43 | end 44 | 45 | idx_length_map[end_idx] = max_length 46 | end 47 | 48 | return idx_length_map.values.max 49 | end -------------------------------------------------------------------------------- /templates/lib/@@TEMPLATE - BST : Binary Search.rb: -------------------------------------------------------------------------------- 1 | # Range Binary Search in BST 2 | 3 | def search(node) 4 | return if node.nil? 5 | 6 | search(node.left) if @low_bound < node.val 7 | output << node.val 8 | search(node.right) if node.val < @high_bound 9 | end 10 | 11 | # lower bound 12 | 13 | def inorder_successor(root, p) 14 | return if root.nil? 15 | 16 | node = root 17 | candidate = nil 18 | while node 19 | # node is similar to mid in binary search 20 | go_smaller = node.val > @low_bound 21 | 22 | # greedy search to even smaller 23 | if go_smaller 24 | candidate = node # if candidate.nil? || node.val < candidate.val 25 | node = node.left 26 | else 27 | node = node.right 28 | end 29 | end 30 | 31 | return candidate 32 | end 33 | 34 | 35 | def search_iterative(node, target) 36 | while node 37 | return node if node.val == target 38 | if target < node.val 39 | node = node.left 40 | else 41 | node = node.right 42 | end 43 | end 44 | end -------------------------------------------------------------------------------- /templates/lib/@@TEMPLATE - Backtracking.rb: -------------------------------------------------------------------------------- 1 | require 'set' 2 | 3 | def find_words(board, words) 4 | @matrix = board 5 | 6 | @visiting = Set.new 7 | @path = [] 8 | @paths = [] 9 | 10 | (0...@matrix.length).each do |i| 11 | (0...@matrix[0].length).each do |j| 12 | traverse_from([i,j]) 13 | end 14 | end 15 | end 16 | 17 | def in_bound?(pos) 18 | x , y = pos 19 | return false if x < 0 || x >= @matrix.length 20 | return y >= 0 && y < @matrix[0].length 21 | end 22 | 23 | def traverse_from(pos) 24 | return if @visiting.include?(pos) 25 | x, y = pos 26 | @path << @matrix[x][y] 27 | @visiting.add(pos) 28 | 29 | if success 30 | @paths << @path.clone 31 | end 32 | 33 | next_cells = [[x+1, y], [x - 1,y], [x, y+1], [x, y-1]].select do |next_cell| 34 | in_bound?(next_cell) 35 | end 36 | 37 | next_cells.each do |next_cell| 38 | traverse_from(next_cell) 39 | end 40 | 41 | @path.pop 42 | @visiting.delete(id) 43 | end -------------------------------------------------------------------------------- /templates/lib/@@TEMPLATE - Graph - Connected Component.rb: -------------------------------------------------------------------------------- 1 | # helper functions 2 | def init_graph(edges) 3 | @vertex_children_map = Hash.new {|h,k| h[k] = []} 4 | edges.each do |edge| 5 | @vertex_children_map[edge[0]] << edge[1] 6 | @vertex_children_map[edge[1]] << edge[0] 7 | end 8 | end 9 | 10 | def in_bound?(pos) 11 | x , y = pos 12 | return false if x < 0 || x >= @matrix.length 13 | return y >= 0 && y < @matrix[0].length 14 | end 15 | 16 | =begin 17 | CONNECTED COMPONENT (UNDIRECTED GRAPH) 18 | =end 19 | def traverse(matrix) 20 | @matrix = matrix 21 | @visited = Set.new 22 | # (0...n).each do |id| 23 | (0...@matrix.length).each do |i| 24 | (0...@matrix[0].length).each do |j| 25 | next if @visited.include?([i, j]) 26 | 27 | @visiting = Set.new 28 | traverse_from([i, j]) 29 | 30 | @visiting # 这里从@visiting得到结论 31 | end 32 | end 33 | end 34 | 35 | # can be BFS as well 36 | def traverse_from(pos) 37 | return if @visiting.include?(pos) 38 | return if @visited.include?(pos) 39 | # return if other constraint 40 | 41 | @visiting.add(pos) 42 | 43 | x, y = pos 44 | # next_cells.select / next_ids.select 45 | next_cells = [[x + 1, y], [x - 1, y], [x, y + 1], [x, y -1]].select do |next_cell| 46 | in_bound?(next_cell) 47 | end 48 | 49 | # @matrix[x][y] = color # [optional] mark color 50 | next_cells.each do |next_cell| 51 | traverse_from(next_cell) 52 | end 53 | # No need to revert @visiting because it's no longer being used for detecting circle 54 | @visited.add(pos) 55 | end 56 | 57 | DIRECTIONS = [[1, 1], [-1, 1], [-1, -1], [1, -1], [1,0], [-1,0], [0,1], [0,-1]].freeze -------------------------------------------------------------------------------- /templates/lib/@@TEMPLATE - Graph - Topological Sort.rb: -------------------------------------------------------------------------------- 1 | # GRAPH - TOPOLOGICAL SORT 2 | 3 | def topological_sort(edges) 4 | @vertex_children_map = Hash.new {|h, k| h[k] = []} 5 | edges.each do |parent, child| 6 | @vertex_children_map[parent] << child 7 | end 8 | 9 | @visiting = Set.new 10 | @visited = {} 11 | 12 | @ids.each { |id| traverse_from(id) } 13 | @visited.values.reverse.join 14 | end 15 | 16 | def traverse_from(id) 17 | return if @visited.include?(id) 18 | 19 | # dependeing on the question 20 | raise 'has cycle' if @visiting.include?(id) 21 | 22 | @visiting.add(id) 23 | @vertex_children_map[id].each { |child_id| traverse_from(child_id) } 24 | @visiting.delete(id) 25 | @visited[id] = id 26 | end -------------------------------------------------------------------------------- /templates/lib/@@TEMPLATE - Intervals.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # HELPER code 4 | 5 | low_a, high_a = intervals_a[idx_a] 6 | low_b, high_b = intervals_b[idx_b] 7 | 8 | # overlap 9 | low = [low_a, low_b].max 10 | high = [high_a, high_b].min 11 | 12 | # merge (assume sorted) 和overlap反过来 13 | 14 | has_overlap = high_a >= low_b 15 | if has_overlap 16 | low = [low_a, low_b].min 17 | high = [high_a, high_b].max 18 | end 19 | 20 | # MERGE INTERVALS - SLIDING WINDOW 21 | 22 | def merge(intervals) 23 | return [] if intervals.empty? 24 | 25 | intervals.sort! 26 | 27 | merged_intervals = [] 28 | window = intervals[0] 29 | 30 | (1...intervals.length).each do |end_idx| 31 | interval = intervals[end_idx] 32 | if window.last < interval.first # could be >= 33 | merged_intervals << window 34 | window = interval 35 | end 36 | 37 | # we dont need window[0] = [...].min because its sorted 38 | window[1] = [window.last, interval.last].max 39 | end 40 | merged_intervals << window 41 | merged_intervals 42 | end 43 | 44 | # Event / Interval 45 | 46 | Event = Struct.new(:time) 47 | 48 | class BusyTime < Event; end 49 | class FreeTime < Event; end 50 | 51 | def complex_schedule(schedule) 52 | events = [] 53 | 54 | # time_schedules_map = Hash.new {|h,k| h[k] = []} 55 | schedule.each do |intervals| 56 | intervals.each do |interval| 57 | events << BusyTime.new(interval.start) 58 | events << FreeTime.new(interval.end) 59 | end 60 | end 61 | events.sort_by!(&:time) 62 | 63 | free_times = [] # final return an array of intervals 64 | window = [] 65 | busy_count = 0 66 | 67 | # sliding window 68 | events.each do |event| 69 | busy_count += 1 if event.is_a?(BusyTime) 70 | busy_count -= 1 if event.is_a?(FreeTime) 71 | 72 | # window starts: 开始free (如果求busy time则 busy_count > 0) 73 | if busy_count == 0 && window.empty? 74 | window << event.time 75 | elsif busy_count > 0 && window.length == 1 76 | # close window && update free times(新来的event让free window结束了) 77 | window << event.time 78 | free_times << Interval.new(window[0], window[1]) if window[0] != window[1] 79 | window = [] 80 | end 81 | end 82 | free_times 83 | end 84 | 85 | # Intersections 86 | 87 | def interval_intersection(intervals_a, intervals_b) 88 | idx_a = 0 89 | idx_b = 0 90 | intersections = [] 91 | while idx_a < intervals_a.length && idx_b < intervals_b.length 92 | low_a, high_a = intervals_a[idx_a] 93 | low_b, high_b = intervals_b[idx_b] 94 | 95 | low = [low_a, low_b].max 96 | high = [high_a, high_b].min 97 | intersections << [low, high] if low <= high 98 | if high_a < high_b 99 | idx_a += 1 100 | else 101 | idx_b += 1 102 | end 103 | end 104 | intersections 105 | end 106 | -------------------------------------------------------------------------------- /templates/lib/@@TEMPLATE - Kth Smallest.rb: -------------------------------------------------------------------------------- 1 | # Kth Smallest -> MaxHeap 2 | 3 | def kth_largest(elements, k) 4 | if k < elements.length / 2 5 | heap = MaxHeap.new 6 | else 7 | heap = MinHeap.new 8 | k = elements.length - k + 1 # 4个里第2个最小的等同于第3个最大的 9 | end 10 | 11 | elements.each do |ele| 12 | heap.push(ele) 13 | heap.pop if heap.size > k 14 | end 15 | 16 | return heap.top 17 | end 18 | 19 | 20 | def quick_select_large(arr, k) 21 | index = quick_select_index(arr, 0, arr.length - 1, arr.length - k + 1) 22 | arr[index] 23 | end 24 | 25 | def quick_select_index(arr, start_idx, end_idx, k) 26 | return start_idx if start_idx == end_idx 27 | 28 | # use pivot to rearrange the array, small part on left 29 | index = partition(arr, start_idx, end_idx) 30 | left_size = index - start_idx + 1 31 | if left_size == k 32 | index 33 | elsif left_size >= k 34 | quick_select_index(arr, start_idx, index - 1, k) 35 | else 36 | quick_select_index(arr, index + 1, end_idx, k - left_size) 37 | end 38 | end 39 | 40 | def partition(arr, start_idx, end_idx) 41 | # pick the last element as pivot 42 | pivot = arr[end_idx] 43 | 44 | left = start_idx 45 | (start_idx...end_idx).each do |right| 46 | if arr[right] <= pivot 47 | # swap with the current left 48 | arr[left], arr[right] = arr[right], arr[left] 49 | left += 1 50 | end 51 | end 52 | 53 | # swap pivot to the right position 54 | arr[left], arr[end_idx] = arr[end_idx], arr[left] 55 | left 56 | end -------------------------------------------------------------------------------- /templates/lib/@@TEMPLATE - Optimal Path.rb: -------------------------------------------------------------------------------- 1 | # Optimal Path 2 | # INPUT is MATRIX 3 | 4 | def in_bound?(pos) 5 | x , y = pos 6 | return false if x < 0 || x >= @matrix.length 7 | return y >= 0 && y < @matrix[0].length 8 | end 9 | 10 | def optimal_path(grid) 11 | return 0 if grid.empty? || grid[0].empty? 12 | @matrix = grid 13 | @target = [@matrix.length - 1, @matrix[0].length - 1] 14 | 15 | # @visiting = Set.new # 注意加入visiting后cache失效 16 | 17 | @cache = {} 18 | return optimal_path_from([0,0]) 19 | end 20 | 21 | def optimal_path_from(pos) 22 | return @matrix[pos[0]][pos[1]] if pos == @target 23 | return @cache[pos] if @cache.key?(pos) 24 | 25 | x, y = pos 26 | 27 | # @visiting.add(id) # 注意这个加入visiting后cache失效 28 | 29 | next_cells = [[x+1, y], [x, y+1]].select do |next_cell| 30 | in_bound?(next_cell) # && !@visiting.include?(next_cell) 31 | end 32 | 33 | @cache[pos] = @matrix[x][y] + next_cells.map do |next_cell| # or next_cells.any? 34 | optimal_path_from(next_cell) 35 | end.min 36 | 37 | # @visiting.delete(id) 38 | return @cache[pos] 39 | end 40 | 41 | 42 | # INPUT is STRING 43 | # require 'set' 44 | def optimal_path(str) 45 | return [] if str.empty? 46 | @str = str 47 | 48 | @cache = {} 49 | return optimal_path_from(0) 50 | end 51 | 52 | def optimal_path_from(id) # start_id 53 | return [] if id == @str.length # could be 0 or true 54 | return @cache[id] if @cache.key?(id) 55 | 56 | 57 | # @visiting.add(id) 58 | next_ids = # 59 | 60 | # next_ids.select! do |next_id| 61 | # in_bound?(next_id) && !@visiting.include?(next_id) 62 | # end 63 | 64 | @cache[id] = [id] + next_ids.max_by do |next_id| # or next_id.any? 65 | optimal_path_from(next_id) 66 | end 67 | 68 | # @visiting.delete(id) 69 | return @cache[id] 70 | end 71 | -------------------------------------------------------------------------------- /templates/lib/@@TEMPLATE - Shortest Distance : BFS.rb: -------------------------------------------------------------------------------- 1 | # Shortest Distance from one source or multiple sources 2 | def in_bound?(pos) 3 | x, y = pos 4 | return false if x < 0 || x >= @matrix.length 5 | return y >= 0 && y < @matrix[0].length 6 | end 7 | 8 | def bfs(matrix) 9 | queue = [source] # or queue = sources 10 | distance = 0 11 | visiting = Set.new(queue) 12 | 13 | @matrix = matrix 14 | # target = 15 | 16 | while !queue.empty? 17 | children = [] 18 | queue.each do |pos| 19 | x, y = pos 20 | # next if @matrix[x][y] != 0 21 | return distance if pos == target 22 | 23 | [[x+1, y], [x-1, y], [x, y-1], [x, y+1]].each do |next_pos| 24 | next if !in_bound?(next_pos) 25 | next if visiting.include?(next_pos) 26 | 27 | visiting.add(next_pos) 28 | children << next_pos 29 | end 30 | end 31 | queue = children 32 | distance += 1 33 | end 34 | 35 | return distance 36 | end -------------------------------------------------------------------------------- /templates/lib/@@TEMPLATE - Sliding Window.rb: -------------------------------------------------------------------------------- 1 | # SLIDING WINDOW 2 | 3 | 4 | # 在每段段尾换段 5 | def longest_window(str) 6 | return '' if str.empty? 7 | 8 | start_idx = 0 9 | window_counter = Hash.new(0) # could be a hash with idx or count as value 10 | longest = '' # or could be length 11 | 12 | (0...str.length).each do |end_idx| 13 | char = str[end_idx] 14 | window_state = # update window state 15 | 16 | # shrink window until it meets requirement 17 | while window_counter.length 18 | start_char = str[start_idx] 19 | window_counter[start_char] -= 1 20 | window_counter.delete(start_char) if window_counter[start_char] == 0 21 | start_idx += 1 22 | end 23 | 24 | longest = str[start_idx..end_idx] if end_idx - start_idx + 1 > longest.length 25 | end 26 | 27 | return longest 28 | end 29 | 30 | 31 | 32 | # 下一段段首换段 33 | def longest_window(str) 34 | return '' if str.empty? 35 | 36 | start_idx = 0 37 | window_counter = Hash.new(0) # could be a hash with idx or count as value 38 | longest = '' # or could be length 39 | 40 | (0...str.length).each do |end_idx| 41 | char = str[end_idx] 42 | 43 | # conclude window 44 | if window_counter.length 45 | longest = str[start_idx...end_idx] if end_idx - start_idx > longest.length 46 | 47 | # switch window, move start idx to right place 48 | start_idx = 49 | end 50 | 51 | window_state = # update window state 52 | end 53 | 54 | longest = str[start_idx...end_idx] if end_idx - start_idx > longest.length 55 | return longest 56 | end -------------------------------------------------------------------------------- /templates/lib/@@TEMPLATE - Tree.rb: -------------------------------------------------------------------------------- 1 | class Tree 2 | def initialize(root) 3 | @root = root 4 | # option 1 5 | bfs() 6 | 7 | # option 2 8 | @max_value = -2**32 # maybe some instance variable to update 9 | inorder_dfs(root) 10 | 11 | # option 3 12 | res = divide_and_conquer(root) 13 | 14 | # option 4 15 | inorder_dfs_iterative(root) 16 | end 17 | 18 | def bfs() 19 | return if @root.nil? 20 | queue = [@root] 21 | distance = 0 22 | 23 | while !queue.empty? 24 | queue = [] 25 | queue.each do |node| 26 | VISIT(node) # TODO: imagine what you would do in a loop 27 | 28 | children.push(node.left) if node.left 29 | children.push(node.right) if node.right 30 | end 31 | queue = children 32 | distance += 1 33 | end 34 | end 35 | 36 | def inorder_dfs(node) 37 | return if node.nil? 38 | 39 | inorder_dfs(node.left) 40 | 41 | VISIT(node) # TODO: imagine what you would do in a loop 42 | 43 | inorder_dfs(node.right) 44 | end 45 | 46 | # iterative inorder traversal 47 | def inorder_dfs_iterative 48 | # base case, maybe 0 or [] 49 | return [] if @root.nil? 50 | 51 | stack = [] 52 | node = @root 53 | while !stack.empty? || !node.nil? 54 | if !node.nil? 55 | stack.push(node) 56 | node = node.left 57 | else 58 | node = stack.pop 59 | 60 | VISIT(node) # TODO: imagine what you would do in a loop 61 | 62 | node = node.right 63 | end 64 | end 65 | end 66 | end 67 | 68 | 69 | ## DIVIDE and CONQUER 70 | 71 | def outcome(node) 72 | # base case, maybe 0 or [] 73 | return 0 if node.nil? 74 | 75 | left_outcome = outcome(node.left) # height, max, size, min or combinations of them 76 | right_outcome = outcome(node.right) 77 | 78 | @global = # update global variable 79 | 80 | return [ 81 | left_outcome, 82 | right_outcome, 83 | node.val 84 | ].max # or sum, or something else 85 | end -------------------------------------------------------------------------------- /templates/lib/@@TEMPLATE - binary search.rb: -------------------------------------------------------------------------------- 1 | # BINARY SEARCH 2 | 3 | def bsearch_low(nums, target) 4 | return nil if nums.empty? 5 | 6 | low, high = 0, nums.length - 1 7 | while low <= high 8 | mid = (low + high) / 2 9 | # return mid if nums[mid] == target 10 | 11 | go_left = nums[mid] >= target # if we are looking for low bound 12 | 13 | if go_left 14 | high = mid - 1 15 | else 16 | low = mid + 1 17 | end 18 | end 19 | 20 | return low < nums.length ? low : nil 21 | end 22 | 23 | def bsearch_high(nums, target) 24 | return nil if nums.empty? 25 | 26 | low, high = 0, nums.length - 1 27 | while low <= high 28 | mid = (low + high) / 2 29 | go_right = nums[mid] <= target # if we are looking for high bound 30 | 31 | if go_right 32 | low = mid + 1 33 | else 34 | high = mid - 1 35 | end 36 | end 37 | 38 | return high >= 0 ? high : nil 39 | end -------------------------------------------------------------------------------- /templates/lib/@@TEMPLATE - merge : intersection.rb: -------------------------------------------------------------------------------- 1 | # INTERSECTION 2 | 3 | def intersection_of_two_lists(arr_a, arr_b) 4 | idx_a, idx_b = 0, 0 5 | intersection = [] 6 | while idx_a < arr_a.length && idx_b < arr_b.length 7 | if arr_a[idx_a] < arr_b[idx_b] 8 | idx_a += 1 9 | elsif arr_a[idx_a] > arr_b[idx_b] 10 | idx_b += 1 11 | else 12 | # 如果要删除重复: if intersection.last != arr_a[idx_a] 13 | intersection.push(arr_a[idx_a]) 14 | idx_a += 1 15 | idx_b += 1 16 | end 17 | end 18 | intersection 19 | end 20 | 21 | # INTERSECTION - Binary Search 22 | 23 | # arr_a length m; arr_b length n 24 | # O(mlgn) assume n is way longer 25 | def intersection_binary_search(arr_a, arr_b) 26 | start_index = 0 27 | intersection = [] 28 | (0...arr_a.length).each do |a_idx| 29 | number = arr_a[a_idx] 30 | # next if a_idx != 0 && number == arr_a[a_idx-1] 31 | b_index = arr_b.bsearch(number, start_index) 32 | if b_index 33 | start_index = b_index + 1 34 | intersection.push(number) 35 | end 36 | end 37 | intersection 38 | end 39 | 40 | # MERGE 41 | def merge_two_sorted_lists(arr_a, arr_b) 42 | idx_a, idx_b = 0, 0 43 | output = [] 44 | while idx_a < arr_a.length && idx_b < arr_b.length 45 | if arr_a[idx_a] <= arr_b[idx_b] 46 | output << arr_a[idx_a] 47 | idx_a += 1 48 | else 49 | output << arr_b[idx_b] 50 | idx_b += 1 51 | end 52 | end 53 | 54 | return output.concat(arr_a[idx_a..-1]).concat(arr_b[idx_b..-1]) 55 | end 56 | 57 | p merge_two_sorted_lists([1,2,4,5], [3,6]) # [1, 2, 3, 4, 5, 6] 58 | p merge_two_sorted_lists([1,2,4,7,8], [3,6]) # [1, 2, 3, 4, 6, 7, 8] -------------------------------------------------------------------------------- /templates/lib/@@TEMPLATE - trie.rb: -------------------------------------------------------------------------------- 1 | class Trie 2 | attr_accessor :word, :children 3 | def initialize(words=[]) 4 | @children = {} 5 | @word = nil 6 | words.each {|word| self.insert(word)} 7 | end 8 | 9 | def insert(word) 10 | node = self 11 | word.each_char do |char| 12 | node.children[char] = Trie.new if !node.children.key?(char) 13 | node = node.children[char] 14 | end 15 | node.word = word 16 | end 17 | 18 | def search(word) 19 | node = self.find_node(word) 20 | return !node.nil? && node.word == word 21 | end 22 | 23 | def starts_with(prefix) 24 | return !self.find_node(prefix).nil? 25 | end 26 | 27 | protected 28 | def find_node(word) 29 | node = self 30 | word.each_char do |char| 31 | return nil if !node.children.key?(char) 32 | node = node.children[char] 33 | end 34 | return node 35 | end 36 | end 37 | 38 | if __FILE__ == $PROGRAM_NAME 39 | trie = Trie.new 40 | trie.insert('abc') 41 | p trie.starts_with('ab') 42 | p trie.search('ab') 43 | p trie.search('abc') 44 | end -------------------------------------------------------------------------------- /templates/lib/templates.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "templates/version" 4 | 5 | module Templates 6 | class Error < StandardError; end 7 | # Your code goes here... 8 | end 9 | -------------------------------------------------------------------------------- /templates/lib/templates/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Templates 4 | VERSION = "0.1.0" 5 | end 6 | -------------------------------------------------------------------------------- /templates/sig/templates.rbs: -------------------------------------------------------------------------------- 1 | module Templates 2 | VERSION: String 3 | # See the writing guide of rbs: https://github.com/ruby/rbs#guides 4 | end 5 | -------------------------------------------------------------------------------- /templates/templates.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "lib/templates/version" 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = "templates" 7 | spec.version = 0.1 8 | spec.authors = ["April Li"] 9 | spec.email = ["greatday4april@gmail.com"] 10 | 11 | spec.summary = "self explanatory" 12 | spec.description = "self explanatory" 13 | spec.homepage = "https://github.com/greatday4april/algorithm-templates" 14 | spec.license = "MIT" 15 | spec.required_ruby_version = ">= 2.6.0" 16 | 17 | spec.metadata["allowed_push_host"] = "https://github.com/greatday4april/algorithm-templates" 18 | 19 | spec.metadata["homepage_uri"] = spec.homepage 20 | spec.metadata["source_code_uri"] = "https://github.com/greatday4april/algorithm-template." 21 | spec.metadata["changelog_uri"] = "https://github.com/greatday4april/algorithm-templates" 22 | 23 | # Specify which files should be added to the gem when it is released. 24 | # The `git ls-files -z` loads the files in the RubyGem that have been added into git. 25 | spec.files = Dir['README.md', 'lib/**/*', 'lib/*'] 26 | spec.bindir = "exe" 27 | spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } 28 | spec.require_paths = ["lib"] 29 | 30 | # Uncomment to register a new dependency of your gem 31 | # spec.add_dependency "example-gem", "~> 1.0" 32 | 33 | # For more information and examples about making a new gem, check out our 34 | # guide at: https://bundler.io/guides/creating_gem.html 35 | end 36 | --------------------------------------------------------------------------------