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