Maximum uniqueness in pairs of numbers with a slight constraint - algorithm

Here's an algorithmic challenge for you,
I have a list of [0..100] pairs of numbers and I need to find the maximum number of unique "left number" while making sure there is no more than 3 of the "right number".
Here's an example
(1, 1)
(2, 1)
(3, 1)
(4, 1)
(5, 1)
(6, 1)
(7, 1)
(1, 2)
(4, 2)
(1, 3)
(2, 3)
(5, 4)
And the result would be: 7. We would take: (3, 1), (6, 1), (7, 1), (1, 2), (4, 2), (2, 3) and (5, 4).
For whatever reason I can't seem to find any other way than brute forcing it...
Any help is greatly appreciated :)

You can express this problem as a maximum flow problem:
Make edges of capacity 1 from a source node to each of your left numbers.
Make edges of capacity 3 from each of your right numbers to a sink node.
Make edges of capacity 1 from left number a to right number b for each pair of the form (a, b).
Compute the maximum flow in this network from source to sink.

If anyone is interested in the implementation, here's a ruby version of the push–relabel maximum flow algorithm with relabel-to-front selection rule.
def relabel_to_front(capacities, source, sink)
n = capacities.length
flow = Array.new(n) { Array.new(n, 0) }
height = Array.new(n, 0)
excess = Array.new(n, 0)
seen = Array.new(n, 0)
queue = (0...n).select { |i| i != source && i != sink }.to_a
height[source] = n - 1
excess[source] = Float::INFINITY
(0...n).each { |v| push(source, v, capacities, flow, excess) }
p = 0
while p < queue.length
u = queue[p]
h = height[u]
discharge(u, capacities, flow, excess, seen, height, n)
if height[u] > h
queue.unshift(queue.delete_at(p))
p = 0
else
p += 1
end
end
flow[source].reduce(:+)
end
def push(u, v, capacities, flow, excess)
residual_capacity = capacities[u][v] - flow[u][v]
send = [excess[u], residual_capacity].min
flow[u][v] += send
flow[v][u] -= send
excess[u] -= send
excess[v] += send
end
def discharge(u, capacities, flow, excess, seen, height, n)
while excess[u] > 0
if seen[u] < n
v = seen[u]
if capacities[u][v] - flow[u][v] > 0 && height[u] > height[v]
push(u, v, capacities, flow, excess)
else
seen[u] += 1
end
else
relabel(u, capacities, flow, height, n)
seen[u] = 0
end
end
end
def relabel(u, capacities, flow, height, n)
min_height = Float::INFINITY
(0...n).each do |v|
if capacities[u][v] - flow[u][v] > 0
min_height = [min_height, height[v]].min
height[u] = min_height + 1
end
end
end
And here's the code to transform the pairs of numbers into the capacities array of array
user_ids = Set.new
post_ids = Set.new
pairs.each do |p|
user_ids << p[:user_id]
post_ids << p[:post_id]
end
index_of_user_id = {}
index_of_post_id = {}
user_ids.each_with_index { |user_id, index| index_of_user_id[user_id] = 1 + index }
post_ids.each_with_index { |post_id, index| index_of_post_id[post_id] = 1 + index + user_ids.count }
source = 0
sink = user_ids.count + post_ids.count + 1
n = sink + 1
capacities = Array.new(n) { Array.new(n, 0) }
# source -> user_ids = 1
index_of_user_id.values.each { |i| capacities[source][i] = 1 }
# user_ids -> post_ids = 1
pairs.each { |p| capacities[index_of_user_id[p[:user_id]]][index_of_post_id[p[:post_id]]] = 1 }
# post_ids -> sink = 3
index_of_post_id.values.each { |i| capacities[i][sink] = 3 }

Related

stdout can print correct result but not output in ruby although i have return the values

def two_sum(nums, target)
for i in 0..3 - 1
for j in 0..3 - 1
if nums[i] + nums[j] == target && i < j && i != j
puts '[' + (i - 1).to_s + ',' + (j - 1).to_s + ']'
end
end
end
return (i - 1), (j - 1)
end
def main()
nums = Array.new()
target = gets().to_i
nums = gets().to_i
two_sum(nums, target)
end
main()
The requirement of the exercise is to print out numbers whose sum is equal to a target number. You need to get an array of integers and the target number at first.
Can anyone debug it for me? Thank you.
I will leave it others to debug your code. Instead I would like to suggest another way that calculation could be made relatively efficiently.
def two_sum(nums, target)
h = nums.each_with_index.with_object(Hash.new { |h,k| h[k] = [] }) do |(n,i),h|
h[n] << i
end
n,i = nums.each_with_index.find { |n,_i| h.key?(target-n) }
return nil if n.nil?
indices = h[target-n]
return [i,indices.first] unless n == target/2
return nil if indices.size == 1
[i, indices.find { |j| j !=i }]
end
​
two_sum([2,7,11,15], 9) #=> [0, 1]
two_sum([2,7,11,15], 10) #=> nil
two_sum([2,7,11,15], 4) #=> nil
two_sum([2,7,11,2,15], 4) #=> [0, 3]
two_sum([2,11,7,11,2,15,11], 22) #=> [1, 3]
In the last example
h #=> {2=>[0, 4], 11=>[1, 3, 6], 7=>[2], 15=>[5]}
Note that key lookups in hashes are very fast, specifically, the execution of the line
indices = h[target-n]
Building h has a computational complexity of O(n), where n = num.size and the remainder is very close to O(n) ("very close" because key lookups are close to constant-time), the overall computational complexity is close to O(n), whereas a brute-force approach considering each pair of values in num is O(n^2).
If a hash is defined
h = Hash.new { |h,k| h[k] = [] }
executing h[k] when h has no key k causes
h[k] = []
to be executed. For example, if
h #=> { 2=>[0] }
then
h[11] << 1
causes
h[11] = []
to be executed (since h does not have a key 11), after which
h[11] << 1
is executed, resulting in
h #=> { 2=>[0], 11=>[1] }
By contrast, if then
h[2] << 3
is executed we obtain
h #=> { 2=>[0,3], 11=>[1] }
without h[2] = [] being executed because h already has a key 2. See Hash::new.
Expressing block variables as
|(n,i),h|
is a form of array decomposition.

The Number of the Smallest Unoccupied Chair solution in ruby

I am learning ruby and have started practicing problems from leetcode, yesterday I have a problem which I am not able to solve since yesterday.
I tried hard doing that in ruby, but not able to do yet.
I tried this
def give_chair(a)
u = a.uniq
d = []
u.each do |i|
d << i if a.count(i) == 1
end
d
end
def smallest_chair(times, target_friend)
friend = times[target_friend]
sorted_arrival_times = times.sort
leave_time_chair = {}
chair = 0
chairs_array = []
uniq_chars_array = []
sorted_arrival_times.each do |i|
if leave_time_chair.keys.select { |k| i[0] > k }.empty?
leave_time_chair[i[1]] = chair
chair+=1
else
all_keys = leave_time_chair.keys.select { |k| k <= i[0] }
chairs_array = leave_time_chair.values
p chairs_array
if give_chair(chairs_array).empty?
leave_time_chair[i[1]] = chairs_array.sort.first
else
leave_time_chair[i[1]] = give_chair(chairs_array).sort.first
end
end
if i == friend
p leave_time_chair
return leave_time_chair[i[1]]
end
end
end
# a = [[33889,98676],[80071,89737],[44118,52565],[52992,84310],[78492,88209],[21695,67063],[84622,95452],[98048,98856],[98411,99433],[55333,56548],[65375,88566],[55011,62821],[48548,48656],[87396,94825],[55273,81868],[75629,91467]]
# b = 6
# p smallest_chair(a, b)
but it is failing for some test cases.
I am not able to create an algorithm for it.
Question = https://leetcode.com/problems/the-number-of-the-smallest-unoccupied-chair
My approach:
First I sort the times array according to arrival times.
Then I iterate over each array element
Now if the arrival time is greater than all the previous leaving time (I am creating key, value pair of leaving time and chair given) then I add a new key=> value pair in leave_time_chair (which is hash) and where key is the leaving time of current array and value is the chair given to it.
Then I increment the chair (chair+=1)
Else I get all those leaving time which are equal or less than the current arrival time (all_keys = leave_time_chair.keys.select { |k| k <= i[0] })
Then I get all the chairs of those times
Now I have all the chairs like this => [0, 0, 1, 2] so I wrote one function [ give_chair(a) ] which gives me those elements which are not repeated. like this => [1, 2] and then I assign the shortest number (chair) to the leaving time of current array. and so on...
Then if my current array is equal to the friend I return the chair of it. by extracting it from a hash (leave_time_chair) return leave_time_chair[i[1]]
my naive solution (not optimize yet), basically my idea that i flat-map the input array into an array with each element is a pair [time arrive/leave, friend index], then i will sort that array base on time (don't care arrive or leave), if both pair have same time, then i'll compare the arrive time of fiend index. Finally i loop through the sorted array and evaluate minimum free chair index each step, whenever i meet the targetFriend i return that minimum free chair index.
# #param {Integer[][]} times
# #param {Integer} target_friend
# #return {Integer}
def smallest_chair(times, target_friend)
# times = [[1,2],[4,7],[2,4]]
# targetFriend = 1
sit_times = times.each_with_index.inject([]) { |combi, (time, index)|
combi += [[time.first, index], [time.last, index]]
}
# [[1, 0], [2, 0], [4, 1], [7, 1], [2, 2], [4, 2]]
sit_times.sort! {|x, y|
c = x[0] <=> y[0]
# [[1, 0], [2, 0], [2, 2], [4, 1], [4, 2], [7, 1]]
c = times[x[1]][0] <=> times[y[1]][0] if c == 0
# [[1, 0], [2, 0], [2, 2], [4, 2], [4, 1], [7, 1]]
c
}
chairs = {} # to mark time of friend
occupied = Array.new(times.size, 0) # occupied chair: 1, otherwise: 0
min_free = 0 # current minimum not occupied chair
sit_times.each do |time, friend_index|
if target_friend == friend_index # check
return min_free
end
sit = chairs[friend_index]
if sit # leave
occupied[sit] = 0
chairs[friend_index] = nil
min_free = sit if min_free > sit
else # arrive
chairs[friend_index] = min_free
occupied[min_free] = 1
min_free += 1 until occupied[min_free] == 0 # re-calculate
end
end
end
Note: the code pass test cases on leetcode but the performance is not good.
update
here is the better version, using 3 priority queues, one for arrive times, one for leave times and the last for chair.
PriorityQueue class
class PriorityQueue
attr_reader :length
def initialize(opts={}, &comparator)
order_opt = opts.fetch(:order, :asc)
#order = order_opt == :asc ? -1 : 1
#comparator = comparator
#items = [nil]
#length = 0
end
def push(item)
#items << item
#length += 1
swim(#length)
true
end
def pop
return nil if empty?
swap(1, #length) if #length > 1
#length -= 1
sink(1) if #length > 0
#items.pop
end
def empty?
#length == 0
end
def swap(i, j)
temp = #items[i]
#items[i] = #items[j]
#items[j] = temp
end
def in_order?(i, j)
x = #items[i]
y = #items[j]
order = #comparator.nil? ? (x <=> y) : #comparator.call(x, y)
order == #order
end
def swim(from)
while (up = from / 2) >= 1
break if in_order?(up, from)
swap(up, from)
from = up
end
end
def sink(from)
while (down = from * 2) <= #length
down += 1 if down < #length && in_order?(down + 1, down)
break if in_order?(from, down)
swap(down, from)
from = down
end
end
end
smallest_chair with priority queues (note that i found using sort is faster than a queue for arrive times, but basically the idea is same)
def smallest_chair_pq(times, target_friend)
# a_pq = PriorityQueue.new { |x, y|
# x[0] <=> y[0]
# }
#
# times.each do |t|
# a_pq.push(t)
# end
# sort arrive times is faster than a priority queue
a_pq = times.sort_by(&:first).reverse
# leave times queue
l_pq = PriorityQueue.new { |x, y|
c = x[0] <=> y[0]
c = x[1] <=> y[1] if c == 0
c
}
# chair-indexes queue
# consider case a friend come in at arrive-time at1
# and there's a range chairs with leave times in range lm <= at1 <= ln
# that mean that friend could pick one of those chairs
# and according this problem requirement, should pick the minimun chair index
c_pq = PriorityQueue.new
target_time = times[target_friend][0]
last_chair_index = 0
until a_pq.empty?
a_top = a_pq.pop
arrive_time = a_top.first
if l_pq.empty?
return 0 if arrive_time == target_time
l_pq.push([a_top.last, 0])
else
l_top = l_pq.pop
if l_top.first <= arrive_time
c_pq.push(l_top.last)
until (l_ntop = l_pq.pop).nil? || arrive_time < l_ntop.first
c_pq.push(l_ntop.last)
end
l_pq.push(l_ntop) unless l_ntop.nil?
min_chair_index = c_pq.pop
return min_chair_index if arrive_time == target_time
l_pq.push([a_top.last, min_chair_index])
else
unless c_pq.empty?
chair_index = c_pq.pop
return chair_index if arrive_time == target_time
l_pq.push([a_top.last, chair_index])
else
last_chair_index += 1
return last_chair_index if arrive_time == target_time
l_pq.push([a_top.last, last_chair_index])
end
l_pq.push(l_top)
end
end
end
end

Decompose string to form a valid expression

I am given a string S (of integers) and a number N. I want to insert arbitrary number of '+' in S so that the sum becomes equal to N.
Ex:<br>
S = 15112 and N = 28<br>
Ans is : 15+11+2<br>
S = 120012 and N = 33<br>
Ans is : 1+20+012<br>
S = 123 and N = 123<br>
Ans is : 123
given : |S| <= 120 and N <= 10^6
It is guarenteed that S and N are given such that it is always possible to form valid expression. Is there any algorithm which can solve this? I tried to think on it but couldn't come up with solution.
There may be more efficient ways to do this, but since you have nothing so far…
You can simply find all combinations of a boolean array that indicates whether a plus should exist between the numbers or not.
For example: with an input of 112134, 1 + 12 + 13 + 4 can be represented with the boolean array [true, false, true, false, true] indicating that there is a plus after the 1st, 3rd, and 5th numbers. The problem then reduces to finding which combinations add to your number. There are lot of ways to find combinations. Recursive backtracking is a classic.
In javascript/node this might look like this:
function splitOnIndexes(arr, a) {
// split the array into numbers based on the booleans
let current = "" + arr[0]
let output = []
for (let i = 0; i < a.length; i++) {
if (!a[i]) {
current += arr[i + 1]
} else {
output.push(current)
current = "" + arr[i + 1]
}
}
output.push(current)
return output
}
function findSum(input, total) {
function backtrack(n, k = 0, a = []) {
const sum = (arr) => arr.reduce((a, c) => a + parseInt(c), 0)
if (k === n) {
let ans = splitOnIndexes(input, a)
if (sum(ans) === total) {
console.log(ans.join(' + '))
}
} else {
k = k + 1
let c = [true, false]
for (let i = 0; i < 2; i++) {
a[k - 1] = c[i]
backtrack(n, k, a)
}
}
}
backtrack(input.length - 1)
}
findSum('15112', 28)
findSum('120012', 33)
findSum('123', 123)
As you can see, more than one answer is possible. Your first example is solved with both 15+1+12 and 15+11+2. If you only need one, you can of course stop early.
The idea is to use dynamic programming, you only care about sums between 0 and 10^6 and only have 120 possible indexes. if dp[i][j] = x, it means that from index x of the string, we went to index i (so we added a + before i) and we got a sum of j. This leads to a O(|S| * N) solution:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string s;
long n;
long dp[123][1000001];
void solve (int index, long sum) {//index = what index of s still remains to scan. sum = the sum we have accumulated till now
if (sum >= n or index >= s.length()) return;
if (dp[index][sum] != -1) return;
if (index == n and sum == n) return;
long num = 0;
for (int i = 0; i < 7 && index + i < s.length(); i++) { //N has 6 digits at most
num = stoi(s.substr(index, i + 1));
solve(index + i + 1, sum + num);
if (sum + num <= n) {
dp[index + i + 1][sum + num] = index;
}
}
}
int main () {
cin >> s;
cin >> n;
for (int i = 0; i < 121; i++) {
for (int j = 0; j < 1000001; j++) {
dp[i][j] = -1;
}
}
solve(0, 0);
int sum = n;
int idx = s.length();
vector<string> nums;
//reconstruct solution
while (idx != 0) {
nums.push_back(s.substr(dp[idx][sum], idx - dp[idx][sum]));
idx = dp[idx][sum];
sum -= stoi(nums[nums.size() - 1]);
}
for (int i = nums.size() -1; i >= 0; i--) {
cout << nums[i];
if (i != 0) cout << "+";
}
}
This is a Ruby version with step by step explanation of the algorithm, so you can easily code in C++ (or I'll try later).
# Let's consider that we extracted the values from text, so we already have the string of int and the result as integer:
string_of_int = "15112"
result = 28
# The basic idea is to find a map (array) that tells how to group digits, for example
sum_map = [2, 1, 2]
# This means that string_of_int is mapped into the following numbers
# 15, 1, 12
# then sum the numbers, in this case 15+1+12 = 28
# For finding a the solution we need to map
# all the possible combinations of addition given the n digits of the string_of_int then check if the sum is equal to the result
# We call k the number of digits of string_of_int
# in ruby we can build an array called sum_maps
# containing all the possible permutations like this:
k = string_of_int.length # => 5
sum_maps = []
k.times do |length|
(1..k).to_a.repeated_permutation(length).each {|e| sum_maps << e if e.inject(:+) == k}
end
sum_maps
# => [[1, 5], [2, 4], [3, 3], [4, 2], [5, 1], [1, 1, 4], [1, 2, 3], [1, 3, 2], [1, 4, 1], [2, 1, 3], [2, 2, 2], [2, 3, 1], [3, 1, 2], [3, 2, 1], [4, 1, 1]]
# Now must check which of of the sum_map is giving us the required result.
#
# First, to keep the code short and DRY,
# better to define a couple of useful methods for the String class to use then:
class String
def group_digits_by(sum_map)
string_of_int_splitted = self.split("")
grouped_digits = []
sum_map.each { |n| grouped_digits << string_of_int_splitted.shift(n).join.to_i}
grouped_digits.reject { |element| element == 0 }
end
def sum_grouped_of_digits_by(sum_map)
group_digits_by(sum_map).inject(:+)
end
end
# So we can call the methods directly on the string
# for example, in ruby:
string_of_int.group_digits_by sum_map #=> [15, 1, 12]
string_of_int.sum_grouped_of_digits_by sum_map #=> 28
# Now that we have this metods, we just iterate through the sum_maps array
# and apply it for printing out the sm_map if the sum of grouped digits is equal to the result
# coded in ruby it is:
combinations = []
sum_maps.each { |sum_map| combinations << string_of_int.group_digits_by(sum_map) if string_of_int.sum_grouped_of_digits_by(sum_map) == result }
p combinations.uniq
# => [[15, 1, 12], [15, 11, 2]]
In short, written as a Ruby module it becomes:
module GuessAddition
class ::String
def group_digits_by(sum_map)
string_of_int_splitted = self.split("")
grouped_digits = []
sum_map.each { |n| grouped_digits << string_of_int_splitted.shift(n).join.to_i}
grouped_digits.reject { |element| element == 0 }
end
def sum_grouped_of_digits_by(sum_map)
group_digits_by(sum_map).inject(:+)
end
end
def self.guess_this(string_of_int, result)
k = string_of_int.length
sum_maps = []
k.times { |length| (1..k).to_a.repeated_permutation(length).each {|e| sum_maps << e if e.inject(:+) == k} }
combinations = []
sum_maps.each { |sum_map| combinations << string_of_int.group_digits_by(sum_map) if string_of_int.sum_grouped_of_digits_by(sum_map) == result }
combinations.uniq
end
end
p GuessAddition::guess_this("15112", 28) # => [[15, 1, 12], [15, 11, 2]]

Binary Search stuck in infinite loop

I am trying to test a binary search algorithm. The logic seems right, however, I'm running into some issues.
There are two different methods, case and if. If one method fails, the other is right.
1.
arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
def search(arr, value)
if arr.nil?
return "value not in array"
end
l = 0
u = (arr.length - 1)
t = value
if l > u
puts "array is wrong!"
return
end
while l < u
m = (l + u) / 2
case m
when m < t
l = (m + 1)
when m == t
puts "hello world"
when m > t
u = (m - 1)
end
end
end
search(arr, 5)
2.
def search(arr, value)
if arr.nil?
return "value not in array"
end
l = 0
u = (arr.length - 1)
t = value
if l > u
puts "array is wrong!"
return
end
while l < u
m = (l + u) / 2
if m < t
l = (m + 1)
elsif m == t
puts "hello world"
break
elsif m > t
u = (m - 1)
end
end
end
I thought my code would work, but something is causing my while loop to go on infinitely. What am I doing to cause an infinite loop?

Partial Fibonacci Sum, how to improve performance?

I need to improve the performance of this algorithm. I believe the answer lies in the application of the pisano period.
This algorithm must return the last digit of the sum of fib numbers from f(m) to f(n).
Here is what I have so far:
def fib(n)
a = []
a << 0 << 1
(n+1).times do |i|
a << a[-1] + a[-2]
end
a[n]
end
def fib_partial_sum(m, n)
if n == m
fib(m) % 10
else
m = fib(m + 1) - 1
n = fib(n + 2) - 1
(n - m) % 10
end
end
if __FILE__ == $0
m, n = gets.split().map(&:to_i)
puts "#{fib_partial_sum(m, n)}"
end
The last digit of any fib num repeats every 60 numbers. Therefore, we can do this, n, m = n % 60, m % 60. An improvement, but not quite there yet, fails on input 567717153638 567717153638):
def fib(n)
a = []
a << 0 << 1
(n+1).times do |i|
a << a[-1] + a[-2]
end
a[n]
end
def fib_partial_sum(m, n)
if n == m
fib(m)
else
m = m % 60
n = n % 60
m = fib(m + 1) - 1
n = fib(n + 2) - 1
(n - m) % 10
end
end
if __FILE__ == $0
m, n = gets.split().map(&:to_i)
puts "#{fib_partial_sum(m, n)}"
end
Here is a nice solution to the problem, it passes all time and memory constraints.
This way you never have to calculate a fib num greater that f(60). It can handle very large inputs efficiently.
def fib(n)
a, b = 0, 1
(n-1).times do
a, b = b, (a + b) % 10
end
b
end
def fib_partial_sum(m, n)
if n == m
fib(m % 60)
else
m = m % 60
n = n % 60
m = fib(m + 1) - 1
n = fib(n + 2) - 1
(n - m) % 10
end
end
if __FILE__ == $0
m, n = gets.split().map(&:to_i)
puts "#{fib_partial_sum(m, n)}"
end
(Max time used: 0.05/5.00, max memory used: 8699904/536870912.)
The following requires only a single pass of the numbers between zero and at most [n,m+60].min, where m..n is the range of interest, and has a minimal memory requirement. It makes use of #nloveladyallen's observation that the last digit of Fibonacci numbers has a periodicity of 60.
Code
def fib_last(m,n)
n -= 60*((n-m)/60)
fib_sum(m,n) % 10
end
def fib_sum(m,n)
return nil if m < 0 || m > n
return n if n < 2
next_to_last, last = fib(m-1)
(m..n).reduce(0) do |tot,_|
current = next_to_last + last
next_to_last = last
last = current
tot + current
end
end
def fib(m)
next_to_last, last = -1, 1
0.upto(m).each do |n|
current = next_to_last + last
next_to_last, last = last, current
end
[next_to_last, last]
end
Example
m, n = 6, 12
(n+1).times { |i| puts "#{i}: #{fib(i)}" }
0: [0, 0]
1: [0, 1]
2: [1, 1]
3: [1, 2]
4: [2, 3]
5: [3, 5]
6: [5, 8]
7: [8, 13]
8: [13, 21]
9: [21, 34]
10: [34, 55]
11: [55, 89]
12: [89, 144]
fib_last(6,12) #=> 4 (fib_sum(6,12) #=> 8 + 13 + 21 + 34 + 55 + 89 + 144 = 364)
fib_last(1,2) #=> 2 (fib_sum(1,2) #=> 1 + 1 = 2)
fib_last(1,3) #=> 4 (fib_sum(1,3) #=> 1 + 1 + 2 = 4)
fib_last(1,4) #=> 7 (fib_sum(1,4) #=> 1 + 1 + 2 + 3 = 7)
fib_last(2,3) #=> 3 (fib_sum(2,3) #=> 1 + 2 = 3)

Resources