Skip to content

Commit b5b8e7e

Browse files
author
Aman Kumar
committed
add dp
1 parent 78c73c6 commit b5b8e7e

14 files changed

+443
-68
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@ example: `ruby longest_consecutive_subsequence.rb` will print:
1818

1919
# Contribute
2020
Did you find a bug? any way to do it better? please feel free to pull-request it :)
21+
22+

arrays/is_subsequence.rb

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# https://leetcode.com/problems/is-subsequence/
2+
# Given two strings s and t, check if s is a subsequence of t.
3+
4+
# A subsequence of a string is a new string that is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (i.e., "ace" is a subsequence of "abcde" while "aec" is not).
5+
6+
# Example 1:
7+
8+
# Input: s = "abc", t = "ahbgdc"
9+
# Output: true
10+
11+
def is_subsequence(s, t)
12+
t_id = 0
13+
s_id = 0
14+
while t_id < t.length && s_id < s.length
15+
s_id += 1 if t[t_id] == s[s_id]
16+
t_id += 1
17+
end
18+
s_id == s.length
19+
end
20+
21+
# solution 2
22+
def is_subsequence(s, t)
23+
s_index = 0
24+
t.each_char do |c|
25+
s_index += 1 if c == s[s_index]
26+
break if s_index == s.length
27+
end
28+
s_index == s.length
29+
end

arrays/pair_whose_sum_equals_number.rb

+12
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ def findPairUsingHash(ar, sum)
2828
pairs.to_s
2929
end
3030

31+
# Leetcode solution
32+
def two_sum(nums, target)
33+
return if nums.empty?
34+
35+
hash = {}
36+
nums.each_with_index do |num, i|
37+
return [i, hash[target - num]] if hash.key?(target - num)
38+
39+
hash[num] = i
40+
end
41+
end
42+
3143
ar = [0, 14, 0, 4, 7, 8, 3, 5, 7]
3244
sum = 11
3345
# puts findPairBrutforce(ar, sum)

dp/01_knapsack.rb

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
def knapsack_rec(weights, values, capacity, length)
2+
return 0 if length.zero? || capacity.zero?
3+
4+
# if weight is more than the capacity, so can't be included
5+
return knapsack_rec(weights, values, capacity, length - 1) if weights[length - 1] > capacity
6+
7+
remaining_cap = capacity - weights[length - 1]
8+
9+
# Max of if we include the item or don't include
10+
# If we include, we will add value also
11+
[
12+
values[length - 1] + knapsack_rec(weights, values, remaining_cap, length - 1),
13+
knapsack_rec(weights, values, capacity, length - 1)
14+
].max
15+
end
16+
17+
def knapsack_dp(weights, values, capacity)
18+
return 0 if weights.empty? || capacity.zero?
19+
20+
length = weights.length
21+
dp = Array.new(length + 1) { |_i| Array.new(capacity + 1, 0) }
22+
23+
(1..length).each do |item|
24+
weight = weights[item - 1]
25+
value = values[item - 1]
26+
(1..capacity).each do |cap|
27+
dp[item][cap] = if weight > cap
28+
dp[item - 1][cap]
29+
else
30+
[dp[item - 1][cap], dp[item - 1][cap - weight] + value].max
31+
end
32+
end
33+
end
34+
# puts dp.to_s
35+
dp[-1][-1]
36+
end
37+
values = [60, 100, 120]
38+
weights = [10, 20, 30]
39+
capacity = 50
40+
41+
# puts knapsack_rec(weights, values, capacity, weights.length) #output 220
42+
43+
puts knapsack_dp(weights, values, capacity) # output 220
44+
45+
puts knapsack_dp(weights, values, capacity) # output 220
46+
47+
weights = [[1, 2, 3, 4, 5], [1, 3, 4, 6, 9], [1, 2, 3, 5], [3, 5]]
48+
values = [[3, 5, 4, 8, 10], [5, 10, 4, 6, 8], [1, 19, 80, 100], [80, 100]]
49+
capacities = [5, 10, 6, 2]
50+
51+
(0..3).each do |i|
52+
puts "[DP] 0-1 Knapsack max value : #{knapsack_dp(weights[i], values[i], capacities[i])}"
53+
puts "[Recursive] 0-1 Knapsack max value : #{knapsack_rec(weights[i], values[i], capacities[i], weights[i].length)}"
54+
end

dp/coin_change.rb

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.
2+
3+
# Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
4+
5+
# You may assume that you have an infinite number of each kind of coin.
6+
7+
def coin_change(coins, amount)
8+
return 0 if amount.zero?
9+
10+
dp = Array.new(amount + 1, Float::INFINITY)
11+
12+
# To make 0 denomination, 0 coins needed
13+
dp[0] = 0
14+
coins.each do |coin|
15+
# We cant make smaller amount with larger coin
16+
# Example if coin value is 5, min amt possible is also 5
17+
(coin..amount).each do |amt|
18+
# Minimum of current value and 1 + value at remaining balance index
19+
dp[amt] = [dp[amt], 1 + dp[amt - coin]].min
20+
end
21+
end
22+
23+
dp[amount] == Float::INFINITY ? -1 : dp[amount]
24+
end
25+
26+
puts coin_change([1, 2, 5], 11)

dp/edit_distance.rb

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Given two strings word1 and word2, return the minimum number of operations required to convert word1 to word2.
2+
3+
# You have the following three operations permitted on a word:
4+
5+
# Insert a character
6+
# Delete a character
7+
# Replace a character
8+
# Input: word1 = "horse", word2 = "ros"
9+
# Output: 3
10+
11+
# horse -> rorse (replace 'h' with 'r')
12+
# rorse -> rose (remove 'r')
13+
# rose -> ros (remove 'e')
14+
# Let f(m, n) denote number of operations required to convert X(m) to Y(n) (X and Y are strings with m and n chars)
15+
16+
# f(m, n) = f(m - 1, n - 1) if X[m - 1] == Y[n - 1] # Last character is already equal, that reduces the problem
17+
# else
18+
# f(m, n) = 1 + min of the three operations:
19+
# = f(m - 1, n - 1) # Substituted last character of X with last character of Y
20+
# = f(m - 1, n) # Deleted last character of X
21+
# = f(m, n - 1) # Inserted last character of Y in end of X (now they have same last char)
22+
23+
# Base Cases:
24+
# f(0, 0) = 0 # No operations required to convert empty string to empty string
25+
# f(0, j) = j # It'll take j insertions to convert empty string to string of size j
26+
# f(i, 0) = i # It'll take i deletions to convert string of i size to empty string
27+
28+
def min_distance(word1, word2)
29+
dp = Array.new(word1.size + 1) { Array.new(word2.size + 1) }
30+
31+
# increment values in 1st row and col
32+
(0...dp.size).each do |i|
33+
dp[i][0] = i
34+
end
35+
(0...dp[0].size).each do |j|
36+
dp[0][j] = j
37+
end
38+
39+
(1...dp.size).each do |i|
40+
(1...dp[0].size).each do |j|
41+
dp[i][j] = if word1[i - 1] == word2[j - 1]
42+
# if chars are same, value will be from diagonal upward
43+
dp[i - 1][j - 1]
44+
else
45+
[
46+
dp[i - 1][j - 1],
47+
dp[i][j - 1],
48+
dp[i - 1][j]
49+
].min + 1
50+
end
51+
end
52+
end
53+
dp[-1][-1]
54+
end
55+
56+
puts min_distance('horse', 'ros')
57+
puts min_distance('intention', 'execution')

dp/fibonacci.rb

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
def fibonacci_recursive(num)
2+
return num if num < 2
3+
4+
fibonacci_recursive(num - 1) + fibonacci_recursive(num - 2)
5+
end
6+
7+
def fibonacci_with_memoization(num, dp = [])
8+
return num if num < 2
9+
return dp[num] if dp[num]
10+
11+
dp[num] = fibonacci_with_memoization(num - 1) + fibonacci_with_memoization(num - 2)
12+
end
13+
14+
def fibonacci_tabular(num)
15+
dp = [0, 1]
16+
(2..num).each do |i|
17+
dp[i] = dp[i - 1] + dp[i - 2]
18+
end
19+
dp[num]
20+
end
21+
22+
puts 'Fibonacci with recursive solution'
23+
puts fibonacci_recursive(7)
24+
# puts fibonacci_recursive(20)
25+
26+
puts 'Fibonacci with DP - Memoization'
27+
puts fibonacci_with_memoization(5)
28+
puts fibonacci_with_memoization(6)
29+
puts fibonacci_with_memoization(7)
30+
puts fibonacci_with_memoization(20)
31+
32+
puts 'Fibonacci with DP - Tabular'
33+
puts fibonacci_tabular(5)
34+
puts fibonacci_tabular(6)
35+
puts fibonacci_tabular(7)
36+
puts fibonacci_tabular(20)

dp/job_scheduling_max_profit.rb

+25-25
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,34 @@
44
# @return {Integer}
55
Job = Struct.new(:start, :end, :profit, :pos)
66
def job_scheduling(start_time, end_time, profit)
7-
return if start_time.length.zero?
8-
return profit[0] if start_time.length == 1
7+
return if start_time.length.zero?
8+
return profit[0] if start_time.length == 1
99

10-
jobs = []
11-
for i in (0...start_time.length)
12-
jobs << Job.new(start_time[i], end_time[i], profit[i], i+1)
13-
end
14-
jobs.sort_by!(&:profit).reverse!
15-
schedule = Array.new(end_time.max)
16-
17-
profit = 0
10+
jobs = []
11+
(0...start_time.length).each do |i|
12+
jobs << Job.new(start_time[i], end_time[i], profit[i], i + 1)
13+
end
14+
jobs.sort_by!(&:profit).reverse!
15+
schedule = Array.new(end_time.max)
1816

19-
for i in (0...jobs.length)
20-
available = true
21-
current_job = jobs[i]
22-
for j in (jobs[i].start...jobs[i].end)
23-
if schedule[j]
24-
available = false
25-
break
26-
end
27-
end
28-
next unless available
29-
for j in (jobs[i].start...jobs[i].end)
30-
schedule[j] = true
31-
end
17+
profit = 0
3218

33-
profit += jobs[i].profit
19+
(0...jobs.length).each do |i|
20+
available = true
21+
current_job = jobs[i]
22+
(jobs[i].start...jobs[i].end).each do |j|
23+
if schedule[j]
24+
available = false
25+
break
26+
end
27+
end
28+
next unless available
3429

30+
(jobs[i].start...jobs[i].end).each do |j|
31+
schedule[j] = true
3532
end
36-
profit
33+
34+
profit += jobs[i].profit
35+
end
36+
profit
3737
end

dp/max_sum_non_adjacent.rb

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Given an array of integers, find the maximum sum of non-adjacent elements.
2+
# Consider the array 1,0,3,9,2 . The maximum sum would be (1+9)=10
3+
# Again, consider the array 2,4,6,2,5. The maximum should be (2+6+5)=13
4+
5+
def max_sum_non_adjacent(arr)
6+
return 0 if arr.empty?
7+
return arr[0] if arr.length == 1
8+
9+
# base case, 1st element will be as it is
10+
sums = [arr[0]]
11+
12+
# 2nd element will be max of 1st two numbers
13+
sums[1] = arr[0..1].max
14+
15+
(2...arr.length).each do |i|
16+
# max of previous element and (current array element + 2nd previous element)
17+
sums[i] = [sums[i - 1], arr[i] + sums[i - 2]].max
18+
end
19+
20+
sums[-1]
21+
end
22+
23+
puts max_sum_non_adjacent([75, 105, 120, 75, 90, 135])
24+
puts max_sum_non_adjacent([5, 5, 10, 100, 10, 5])
25+
puts max_sum_non_adjacent([1, 2, 3])
26+
puts max_sum_non_adjacent([1, 20, 3])

dp/ways_to_make_coin_change.rb

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# You are given an integer array of coins representing coins of different denominations and an integer amount representing a total amount of money.
2+
# Return the number of combinations that make up that amount. If that amount of money cannot be made up by any combination of the coins, return 0.
3+
# You may assume that you have an infinite number of each kind of coin.
4+
# Input: amount = 5, coins = [1,2,5]
5+
# Output: 4
6+
# Explanation: there are 4 ways
7+
# 5=5
8+
# 5=2+2+1
9+
# 5=2+1+1+1
10+
# 5=1+1+1+1+1
11+
12+
# Input: amount = 3, coins = [2]
13+
# Output: 0
14+
# Explanation: the amount of 3 cannot be made up just with coins of 2.
15+
#
16+
17+
def change(amount, coins)
18+
return 0 if coins.empty?
19+
20+
# TO make zero, there is one way. Dont give anything.
21+
ways = Array.new(amount + 1, 0)
22+
ways[0] = 1
23+
coins.each do |coin|
24+
(coin..amount).each do |amt|
25+
ways[amt] += ways[amt - coin]
26+
end
27+
end
28+
ways[-1]
29+
end
30+
31+
puts change(5, [1, 2, 5])

graph/dfs.rb

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
class Vertice
2+
def initialize(name)
3+
@children = []
4+
@name = name
5+
end
6+
7+
def add_child(name)
8+
@children << Node.new(name)
9+
end
10+
end
11+
12+
class Graph
13+
def initialize()
14+
@vertices = []
15+
end
16+
17+
def add_edge(node_a, node_b)
18+
node_a.adjacents << node_b
19+
node_b.adjacents << node_a
20+
end
21+
end

graph/graph.rb

Whitespace-only changes.

0 commit comments

Comments
 (0)