Find a greedy algorithm for beach and umbrella question - algorithm

A day at the beach. A group of n people are lying on the beach. The beach is represented by the real line R and the location of the i-th person is some integer xi ∈ Z. Your task is to prevent people from getting sunburned by covering them with umbrellas. Each umbrella corresponds to a closed interval I = [a, a + L] of length L ∈ N, and the i-th person is covered by that umbrella if xi ∈ I. Design a greedy algorithm for covering all people with the minimum number of umbrellas. The input consists of the integers x1,...,xn, and L. The output of your algorithm should be the positions of umbrellas.
Forexample,iftheinputisx1 =1,x2 =3,x3 =5,andL=2,thenanoptimumsolutionisthe set of two umbrellas placed at positions 2 and 5, covering intervals [1, 3] and [4, 6]. The running time should be polynomial in n

The main idea is that when we see someone that is not covered yet, we will place the umbrella at position ( uncoveredPersonPosition + L/2 ), and the umbrella reach will be covering the range (uncoveredPersonPosition, uncoveredPersonPosition + L) .
Here is the code for this idea.
#include <vector>
#include <iostream>
#include <algorithm>
int solve(std::vector<double>& people, int umbrellaCoverage) {
std::sort(people.begin(), people.end() );
int answer = 0;
double umbrellaReach;
for(const auto& p : people) {
if(answer == 0) {
answer += 1;
umbrellaReach = p + umbrellaCoverage;
}
else {
if(p < umbrellaReach) continue;
else {
answer++;
umbrellaReach = p + umbrellaCoverage;
}
}
}
return answer;
}
int main() {
std::vector<double> v(10);
for(int i = 0; i < 10; ++i) v[i] = (double) i;
std::cout << solve(v, 3) << std::endl;
return 0;
}

Related

Interview Question: Maximum Profit by Investing in Stocks

Suppose we have M coins and we want to invest it in Stocks. There are N stocks in which he can invest some non-negative integer amount. The profit by stock i is given by a Quadratic function:
AiXi2 + BiXi
where Xi is an integer amount of money invested in stock i. (−1000 ≤ Ai ≤ −1) & (1 ≤ Bi ≤ 1000)
Design a Greedy Algorithm to find the maximum amount of money we can make?
It is not allowed to invest fractional amount of money in a stock. We can invest less than M coins.
A greedy algorithm provides the best solution indeed in such a case.
The point is that, if for a given stock x coins have already be invested, then the expected gain for the next spent is equal to:
next_gain = f(x+1) - f(x) = 2ax + a + b
As a is negative, this gain is always decreasing with x, the number of coins already invested. To be pedantic, the gain function is concave.
Then it can be easily proved that the optimal solution is obtained by spending the coins one by one, looking for the stock with the maximum next_gain. This can be implemented with a max_heap, leading to a complexity O(M logN).
If Mis very large, then other solutions should be foreseen, for example based on a Lagrangian function. More maths would be involved in this case. As you mentioned that you are looking to a greedy solution, I supposed this greedy solution is fast enough.
Here is the code in C++. Should be easy to translate to any code having a max-heap.
Output:
Profit = 16
#include <iostream>
#include <vector>
#include <queue>
struct Stock {
int index;
int n_bought;
int next_gain;
Stock (int i, int n, int gain) : index(i), n_bought(n), next_gain (gain) {};
friend operator< (const Stock& x, const Stock& y) {return x.next_gain < y.next_gain;};
};
long long int profit (std::vector<int>& A, std::vector<int>& B, int M) {
int n = A.size();
if (n != B.size()) exit (1);
std::priority_queue<Stock> candidates;
for (int i = 0; i < n; ++i) {
int gain = A[i] + B[i];
if (gain > 0) candidates.emplace(Stock(i, 0, gain));
}
long long int sum = 0.0;
int coins = 0;
while ((coins < M) &&(!candidates.empty())) {
auto zebest = candidates.top();
candidates.pop();
coins++;
sum += zebest.next_gain;
zebest.n_bought++;
int i = zebest.index;
int gain = 2*A[i]*zebest.n_bought + A[i] + B[i];
if (gain > 0) {
zebest.next_gain = gain;
candidates.push (zebest);
}
}
return sum;
}
int main() {
std::vector<int> A = {-2, -1, -2};
std::vector<int> B = {3, 5, 10};
int M = 3;
auto ans = profit (A, B, M);
std::cout << "Profit = " << ans << std::endl;
return 0;
}
Given function Y = AiXi2 + BiXi is a quadratic function.
For the constraints, (−1000 ≤ Ai ≤ −1) and (1 ≤ Bi ≤ 1000) investments can be represented as a parabolas as,
Notice three things :
These parabolas have their maximum at point given by X'i = -Bi / 2Ai
We should always invest coins Xi such that 0 ≤ Xi ≤ X'i to yield a profit.
For a given number of coins k, it's better to invest them in the investment with larger maxima.
The greedy algorithm is then,
Iterate over all N investments and for each i find it's corresponding Xi = floor(X'i).
Take the all such k investments greedily(investment with maximum Xi first) such that Sum(Xi) ≤ M for all such i taken.
Here's pseudocode to get you started,
FIND_MAX(A, B, N, M):
allProfits = [[]]
for i = 1 to N:
profit = []
X = floor((-B[i]) / (2 * A[i]))
profit.coins = X
profit.index = i
allProfits[i] = profit
Sort(allProfits)
maxProfit = 0
for j = N downto 1:
if(M <= 0):
break
coins = min(allProfits[j].coins, M)
i = allProfits[j].index
maxProfit += (A[i] * coins * coins) + (B[i] * coins)
M -= coins
return maxProfit

Find the maximum K digit number formed by a given number while preserving the order

Given a number, we have to find the maximum 'K' digit number while preserving the order ( 'K' digit number will be a subsequence ).
Input : The number 'n' and number of digits you should pick up to form the answer 'K'
Output : The maximum formed K digit number
Example :
Input : n = 912583, k=3
Output : 983
You don't actually need dynamic programming to solve this problem. The largest K-digit number will always start with the largest possible digit, and it's always best to choose the earliest possible occurrence of the largest possible digit, because that leaves the most options open for the remaining digits.
Similarly, the best second digit is the earliest occurrence of the largest possible second digit, etc., until you're done.
Dynamic programming is used when the locally best choice (like earliest occurrence of the largest possible digit) isn't always the globally best choice.
Here's my solution just so that there is a code answer here (I found the question interesting enough to work it out). Basically I just find the first largest digit that still has enough trailing numbers to fill out the requisite length, and then repeats the problem recursively for the substring after that first largest digit (basically what Matt Timmermans suggested). I tested this a bit so I think it is complete and doesn't have any glaring bugs, but I may definitely have missed an edge case.
I realize that this is probably not the fastest I could make this algorithm since I am doing a lot of variable casting from int to string and back, but since it is a relatively small input size I figured I wouldn't worry about it unless someone wants me to.
Note: It returns 0 in cases where the inputs don't make sense like if the requested length is longer than the input.
private int GetMaximumNumber(int input, int length)
{
input = Math.Abs(input);
var maximumNumber = 0;
var inputString = input.ToString();
if (length > inputString.Length || length < 1)
return maximumNumber;
var indexOfMaxDigit = FindMaximumDigit(input, length);
var maxDigit = int.Parse(inputString.Substring(indexOfMaxDigit, 1));
if (length > 1)
maximumNumber = (maxDigit * (int)(Math.Pow(10.0, (double)length-1))) + GetMaximumNumber(int.Parse(inputString.Substring(indexOfMaxDigit + 1)), length - 1);
else
maximumNumber = maxDigit;
return maximumNumber;
}
private int FindMaximumDigit(int input, int length)
{
var indexOfMaxDigit = -1;
var inputSubstring = input.ToString().Substring(0, input.ToString().Length - length + 1);
for (var i = 9; i > -1; i--)
{
indexOfMaxDigit = inputSubstring.IndexOf(i.ToString(), StringComparison.Ordinal);
if (indexOfMaxDigit != -1)
break;
}
return indexOfMaxDigit;
}
It can be solved by dynamic programming. You need the state dp[i][j], which is the optimal value when you choose j digits from the first i-1 digits. Then you can solve it:
void solve(int n, int k) {
string str = string(n);
int dp[32][32];
memset(dp, 0, sizeof(dp));
for (size_t i = 0; i < str.length(); ++i) {
dp[i + 1][1] = max(dp[i][1], str[i] - '0');
for (size_t j = 2; j <= k; ++j) {
dp[i + 1][j] = max(dp[i][j - 1] * 10 + str[i] - '0', dp[i][j]);
}
}
cout << dp[str.length][k];
}
I stumbled upon this (this forms part of the solution) while solving https://leetcode.com/problems/create-maximum-number/description/ As Matt pointed in his answer, a greedy strategy is good enough. Here is complete C++ program with a driver. n = 78859 and k = 3 outputs 889
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
using namespace std;
template <typename IIT, typename OIT>
void
MaxNumPreservingOrder(IIT first, IIT last, OIT output, int k) {
if (k == 0)
return;
auto N = distance(first, last);
if (N == k) {
copy(first, last, output);
return;
}
auto it = first;
while (k > 0) {
auto maxval = *max_element(it, last - k + 1);
it = find(it, last - k + 1, maxval);
*output = *it;
++output;
++it;
--k;
}
return;
}
int
main(void) {
vector< int > v = {7, 8, 8, 5, 9}, o;
int k = 3;
o.reserve(k);
MaxNumPreservingOrder(begin(v), end(v), back_inserter(o), k);
copy(begin(o), end(o), ostream_iterator< int >(cout, " "));
cout << "\n";
return 0;
}

minimum length window in string1 where string2 is subsequence

Main DNA sequence(a string) is given (let say string1) and another string to search for(let say string2). You have to find the minimum length window in string1 where string2 is subsequence.
string1 = "abcdefababaef"
string2 = "abf"
Approaches that i thought of, but does not seem to be working:
1. Use longest common subsequence(LCS) approach and check if the (length of LCS = length of string2). But this will give me whether string2 is present in string1 as subsequence, but not smallest window.
2. KMP algo, but not sure how to modify it.
3. Prepare a map of {characters: pos of characters} of string1 which are in string2. Like:
{ a : 0,6,8,10
b : 1,7,9
f : 5,12 }
And then some approach to find min window and still maintaining the order of "abf"
I am not sure whether I am thinking in right directions or am I totally off.
Is there a known algorithm for this, or does anyone know any approach? Kindly suggest.
Thanks in advance.
You can do LCS and find all the max subsequences in the String1 of String2 using recursion on the DP table of the LCS result. Then calculate the window length of each of LCS and you can get minimum of it. You can also stop a branch if it already exceeds size of current smallest window found.
check Reading out all LCS :-
http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
Dynamic Programming!
Here is a C implementation
#include <iostream>
#include <vector>
using namespace std;
int main() {
string a, b;
cin >> a >> b;
int m = a.size(), n = b.size();
int inf = 100000000;
vector < vector < int > > dp (n + 1, vector < int > (m + 1, inf)); // length of min string a[j...k] such that b[i...] is a subsequence of a[j...k]
dp[n] = vector < int > (m + 1, 0); // b[n...] = "", so dp[n][i] = 0 for each i
for (int i = n - 1; i >= 0; --i) {
for (int j = m - 1; j >= 0; --j) {
if(b[i] == a[j]) dp[i][j] = 1 + dp[i+1][j+1];
else dp[i][j] = 1 + dp[i][j+1];
}
}
int l, r, min_len = inf;
for (int i = 0; i < m; ++i) {
if(dp[0][i] < min_len) {
min_len = dp[0][i];
l = i, r = i + min_len;
}
}
if(min_len == inf) {
cout << "no solution!\n";
} else {
for (int i = l; i < r; ++i) {
cout << a[i];
}
cout << '\n';
}
return 0;
}
I found a similar interview question on CareerCup , only difference being that its an array of integers instead of characters. I borrowed an idea and made a few changes, let me know if you have any questions after reading this C++ code.
What I am trying to do here is : The for loop in the main function is used to loop over all elements of the given array and find positions where I encounter the first element of the subarray, once found, I call the find_subsequence function where I recursively match the elements of the given array to the subarray at the same time preserving the order of elements. Finally, find_subsequence returns the position and I calculate the size of the subsequence.
Please excuse my English, wish I could explain it better.
#include "stdafx.h"
#include "iostream"
#include "vector"
#include "set"
using namespace std;
class Solution {
public:
int find_subsequence(vector<int> s, vector<int> c, int arrayStart, int subArrayStart) {
if (arrayStart == s.size() || subArrayStart ==c.size()) return -1;
if (subArrayStart==c.size()-1) return arrayStart;
if (s[arrayStart + 1] == c[subArrayStart + 1])
return find_subsequence(s, c, arrayStart + 1, subArrayStart + 1);
else
return find_subsequence(s, c, arrayStart + 1, subArrayStart);
}
};
int main()
{
vector<int> v = { 1,5,3,5,6,7,8,5,6,8,7,8,0,7 };
vector<int> c = { 5,6,8,7 };
Solution s;
int size = INT_MAX;
int j = -1;
for (int i = 0; i <v.size(); i++) {
if(v[i]==c[0]){
int x = s.find_subsequence(v, c, i-1, -1);
if (x > -1) {
if (x - i + 1 < size) {
size = x - i + 1;
j = i;
}
if (size == c.size())
break;
}
}
}
cout << size <<" "<<j;
return 0;
}

Visit all cells in rectangular grid in a zigzag manner

Given a rectangular grid and a point, I need an algorithm for visiting all points in a zigzag manner.
So, I'm looking for a function f that generates the below plot if run like this:
loop:
new_x, new_y = f(x, y, minx, miny, maxx, maxy)
if new_x == x and new_y == y:
end loop
Can someone help me with such an algorithm?
Be warned, I count from 1:
If you are on an odd-numbered row step to the right.
If you are on an even-numbered row step to the left.
If you are at the end of a row step up.
This is a bit fiddly to code but I can't see any particular problems.
Assuming that 0<=X<=L, and 0<=Y, given an index N, you can find the coordinates as follows:
Y = floor(N/L)
X = (Y is even)? N mod L : L - (N mod L) - 1
--Edit--
I Notice that this doesn't comply with your loop structure constraint, but it may be helpful anyway.
Maybe something like this?
#include <iostream>
#include <utility>
std::pair<size_t, size_t>
foo (size_t N, size_t k) {
const auto r = k / N;
const auto c = (r & 1) == 0 ? k % N : N - k % N - 1;
return {r, c};
}
int
main () {
const size_t N = 10;
for (size_t i = 0; i < N * N; ++i) {
auto p = foo (N, i);
std::cout << "(" << p.first << ", " << p.second << ")\n";
}
std::cout << std::endl;
}

Dynamic programming exercise for string cutting

I have been working on the following problem from this book.
A certain string-processing language offers a primitive operation which splits a string into two pieces. Since this operation involves copying the original string, it takes n units of time for a string of length n, regardless of the location of the cut. Suppose, now, that you want to break a string into many pieces. The order in which the breaks are made can affect the total running time. For example, if you want to cut a 20-character string at positions 3 and 10, then making the first cut at position 3 incurs a total cost of 20+17=37, while doing position 10 first has a better cost of 20+10=30.
I need a dynamic programming algorithm that given m cuts, finds the minimum cost of cutting a string into m+1 pieces.
The divide and conquer approach seems to me the best one for this kind of problem. Here is a Java implementation of the algorithm:
Note: the array m should be sorted in ascending order (use Arrays.sort(m);)
public int findMinCutCost(int[] m, int n) {
int cost = n * m.length;
for (int i=0; i<m.length; i++) {
cost = Math.min(findMinCutCostImpl(m, n, i), cost);
}
return cost;
}
private int findMinCutCostImpl(int[] m, int n, int i) {
if (m.length == 1) return n;
int cl = 0, cr = 0;
if (i > 0) {
cl = Integer.MAX_VALUE;
int[] ml = Arrays.copyOfRange(m, 0, i);
int nl = m[i];
for (int j=0; j<ml.length; j++) {
cl = Math.min(findMinCutCostImpl(ml, nl, j), cl);
}
}
if (i < m.length - 1) {
cr = Integer.MAX_VALUE;
int[] mr = Arrays.copyOfRange(m, i + 1, m.length);
int nr = n - m[i];
for (int j=0; j<mr.length; j++) {
mr[j] = mr[j] - m[i];
}
for (int j=0; j<mr.length; j++) {
cr = Math.min(findMinCutCostImpl(mr, nr, j), cr);
}
}
return n + cl + cr;
}
For example :
int n = 20;
int[] m = new int[] { 10, 3 };
System.out.println(findMinCutCost(m, n));
Will print 30
** Edit **
I have implemented two other methods to answer the problem in the question.
1. Median cut approximation
This method cut recursively always the biggest chunks. The results are not always the best solution, but offers a not negligible gain (in the order of +100000% gain from my tests) for a negligible minimal cut loss difference from the best cost.
public int findMinCutCost2(int[] m, int n) {
if (m.length == 0) return 0;
if (m.length == 1) return n;
float half = n/2f;
int bestIndex = 0;
for (int i=1; i<m.length; i++) {
if (Math.abs(half - m[bestIndex]) > Math.abs(half - m[i])) {
bestIndex = i;
}
}
int cl = 0, cr = 0;
if (bestIndex > 0) {
int[] ml = Arrays.copyOfRange(m, 0, bestIndex);
int nl = m[bestIndex];
cl = findMinCutCost2(ml, nl);
}
if (bestIndex < m.length - 1) {
int[] mr = Arrays.copyOfRange(m, bestIndex + 1, m.length);
int nr = n - m[bestIndex];
for (int j=0; j<mr.length; j++) {
mr[j] = mr[j] - m[bestIndex];
}
cr = findMinCutCost2(mr, nr);
}
return n + cl + cr;
}
2. A constant time multi-cut
Instead of calculating the minimal cost, just use different indices and buffers. Since this method executes in a constant time, it always returns n. Plus, the method actually split the string in substrings.
public int findMinCutCost3(int[] m, int n) {
char[][] charArr = new char[m.length+1][];
charArr[0] = new char[m[0]];
for (int i=0, j=0, k=0; j<n; j++) {
//charArr[i][k++] = string[j]; // string is the actual string to split
if (i < m.length && j == m[i]) {
if (++i >= m.length) {
charArr[i] = new char[n - m[i-1]];
} else {
charArr[i] = new char[m[i] - m[i-1]];
}
k=0;
}
}
return n;
}
Note: that this last method could easily be modified to accept a String str argument instead of n and set n = str.length(), and return a String[] array from charArr[][].
For dynamic programming, I claim that all you really need to know is what the state space should be - how to represent partial problems.
Here we are dividing a string up into m+1 pieces by creating new breaks. I claim that a good state space is a set of (a, b) pairs, where a is the location of the start of a substring and b is the location of the end of the same substring, counted as number of breaks in the final broken down string. The cost associated with each pair is the minimum cost of breaking it up. If b <= a + 1, then the cost is 0, because there are no more breaks to put in. If b is larger, then the possible locations for the next break in that substring are the points a+1, a+2,... b-1. The next break is going to cost b-a regardless of where we put it, but if we put it at position k the minimum cost of later breaks is (a, k) + (k, b).
So to solve this with dynamic programming, build up a table (a, b) of minimum costs, where you can work out the cost of breaks on strings with k sections by considering k - 1 possible breaks and then looking up the costs of strings with at most k - 1 sections.
One way to expand on this would be to start by creating a table T[a, b] and setting all entries in that table to infinity. Then go over the table again and where b <= a+1 put T[a,b] = 0. This fills in entries representing sections of the original string which need no further cuts. Now scan through the table and for each T[a,b] with b > a + 1 consider every possible k such that a < k < b and if min_k ((length between breaks a and b) + T[a,k] + T[k,b]) < T[a,b] set T[a,b] to that minimum value. This recognizes where you now know a way to chop up the substrings represented by T[a,k] and T[k,b] cheaply, so this gives you a better way to chop up T[a,b]. If you now repeat this m times you are done - use a standard dynamic programming backtrack to work out the solution. It might help if you save the best value of k for each T[a,b] in a separate table.
python code:
mincost(n, cut_list) =min { n+ mincost(k,left_cut_list) + min(n-k, right_cut_list) }
import sys
def splitstr(n,cut_list):
if len(cut_list) == 0:
return [0,[]]
min_positions = []
min_cost = sys.maxint
for k in cut_list:
left_split = [ x for x in cut_list if x < k]
right_split = [ x-k for x in cut_list if x > k]
#print n,k, left_split, right_split
lcost = splitstr(k,left_split)
rcost = splitstr(n-k,right_split)
cost = n+lcost[0] + rcost[0]
positions = [k] + lcost[1]+ [x+k for x in rcost[1]]
#print "cost:", cost, " min: ", positions
if cost < min_cost:
min_cost = cost
min_positions = positions
return ( min_cost, min_positions)
print splitstr(20,[3,10,16]) # (40, [10, 3, 16])
print splitstr(20,[3,10]) # (30, [10, 3])
print splitstr(5,[1,2,3,4,5]) # (13, [2, 1, 3, 4, 5])
print splitstr(1,[1]) # (1, [1]) # m cuts m+1 substrings
Here is a c++ implementation. Its an O(n^3) Implementation using D.P . Assuming that the cut array is sorted . If it is not it takes O(n^3) time to sort it hence asymptotic time complexity remains same.
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <limits.h>
using namespace std;
int main(){
int i,j,gap,k,l,m,n;
while(scanf("%d%d",&n,&k)!=EOF){
int a[n+1][n+1];
int cut[k];
memset(a,0,sizeof(a));
for(i=0;i<k;i++)
cin >> cut[i];
for(gap=1;gap<=n;gap++){
for(i=0,j=i+gap;j<=n;j++,i++){
if(gap==1)
a[i][j]=0;
else{
int min = INT_MAX;
for(m=0;m<k;m++){
if(cut[m]<j and cut[m] >i){
int cost=(j-i)+a[i][cut[m]]+a[cut[m]][j];
if(cost<min)
min=cost;
}
}
if(min>=INT_MAX)
a[i][j]=0;
else
a[i][j]=min;
}
}
}
cout << a[0][n] << endl;
}
return 0;
}

Resources