About using a boolean array for memoization in a DP - algorithm

I have a working recursive solution to a DP problem. I wish to memoize it.
Currently it depends on two states: the index i and a boolean variable true or false.
Could someone please point out how I could memoize it? Specifically, how I could initialize the memoization table (dp)?
I am confused because if I initialize the second state with false, I wouldn't be able to differentiate between the false that is due to initialization, versus the one where it is actually the value of the state.
Could someone please provide some advise?
Thanks.
To clarify further: This is how I declare the dp table right now:
vector<vector < bool > > dp;
How do I initialize the inner vector<bool>? I don't think I can set it to either true or false since I wouldn't be able to distinguish later if that is the value generated while executing (solving the problem) or the initialization value.
Edit: Adding the code:
class Solution {
public:
unordered_map<int, int> m1, m2;
vector<int> n1, n2;
vector<vector<int>> v;
int helper(int i, bool parsingNums1) {
if((parsingNums1 && i>=n1.size()) || (!parsingNums1 && i>=n2.size())) return v[i][parsingNums1]=0;
if(v[i][parsingNums1]!=-1) return v[i][parsingNums1];
int ans=0;
if(parsingNums1) {
//we are traversing path 1
//see if we can switch to path 2
if(m2.find(n1[i])!=m2.end())
ans=n1[i] + helper(m2[n1[i]]+1, false);
ans=max(ans, n1[i] + helper(i+1, true));
}
if(!parsingNums1) {
//we are traversing path 2
//see if we can switch to path 1
if(m1.find(n2[i])!=m1.end())
ans=n2[i] + helper(m1[n2[i]]+1, true);
ans=max(ans, n2[i] + helper(i+1, false));
}
return v[i][parsingNums1]=ans;
}
int maxSum(vector<int>& nums1, vector<int>& nums2) {
for(int i=0; i<nums1.size(); i++)
m1[nums1[i]]=i;
for(int i=0; i<nums2.size(); i++)
m2[nums2[i]]=i;
n1=nums1;
n2=nums2;
v.resize((nums1.size()>nums2.size()?nums1.size()+1:nums2.size()+1), vector<int>(2,-1));
return max(helper(0, true), helper(0, false))%(int)(1e9+7);
}
};
I am solving this LeetCode question: https://leetcode.com/problems/get-the-maximum-score/

There are 2 easy methods for handling this.
Declare another vector<vector < bool > > is_stored which is initialised as 0 and when dp[i][j] is calculated, mark is_stored[i][j] as 1. So when you are checking wether the particular state is being memorized, you can look into the is_stored.
Use vector< vector < int > > instead of vector< vector < bool > > and initialise -1 to every state to mark as not memorised.

Another way to store values is using
Map<String, Boolean> map = new HashMap<String, Boolean>(); // just a java version
then you can create key by appending i & j and store respective boolean value to that key. for example
String key = i + ',' + j;
// To validate if we calculated data before
if(map.containsKeys(key)) return map.get(key);
// To store/memoize values
boolean result = someDPmethod(); map.put(key, result);

In C# you can use nullable value types.
A nullable value type T? represents all values of its underlying value type T and an additional null value. For example, you can assign any of the following three values to a bool? variable: true, false, or null. An underlying value type T cannot be a nullable value type itself.
You can use null for indication of unvisited or unprocessed dp states.
you can simulate this in C++ by Initializing your dp memo to
vector<vector<bool*>> dp( m, vector<bool*>(n, nullptr) );
now you can use nullptr as an indicator for unprocessed dp states.

Related

Make unique array with minimal sum

It is a interview question. Given an array, e.g., [3,2,1,2,7], we want to make all elements in this array unique by incrementing duplicate elements and we require the sum of the refined array is minimal. For example the answer for [3,2,1,2,7] is [3,2,1,4,7] and its sum is 17. Any ideas?
It's not quite as simple as my earlier comment suggested, but it's not terrifically complicated.
First, sort the input array. If it matters to be able to recover the original order of the elements then record the permutation used for the sort.
Second, scan the sorted array from left to right (ie from low to high). If an element is less than or equal to the element to its left, set it to be one greater than that element.
Pseudocode
sar = sort(input_array)
for index = 2:size(sar) ! I count from 1
if sar(index)<=sar(index-1) sar(index) = sar(index-1)+1
forend
Is the sum of the result minimal ? I've convinced myself that it is through some head-scratching and trials but I haven't got a formal proof.
If you only need to find ONE of the best solution, here's the algorythm with some explainations.
The idea of this problem is to find an optimal solution, which can be found only by testing all existing solutions (well, they're infinite, let's stick with the reasonable ones).
I wrote a program in C, because I'm familiar with it, but you can port it to any language you want.
The program does this: it tries to increment one value to the max possible (I'll explain how to find it in the comments under the code sections), than if the solution is not found, decreases this value and goes on with the next one and so on.
It's an exponential algorythm, so it will be very slow on large values of duplicated data (yet, it assures you the best solution is found).
I tested this code with your example, and it worked; not sure if there's any bug left, but the code (in C) is this.
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef int BOOL; //just to ease meanings of values
#define TRUE 1
#define FALSE 0
Just to ease comprehension, I did some typedefs. Don't worry.
typedef struct duplicate { //used to fasten the algorythm; it uses some more memory just to assure it's ok
int value;
BOOL duplicate;
} duplicate_t;
int maxInArrayExcept(int *array, int arraySize, int index); //find the max value in array except the value at the index given
//the result is the max value in the array, not counting th index
int *findDuplicateSum(int *array, int arraySize);
BOOL findDuplicateSum_R(duplicate_t *array, int arraySize, int *tempSolution, int *solution, int *totalSum, int currentSum); //resursive function used to find solution
BOOL check(int *array, int arraySize); //checks if there's any repeated value in the solution
These are all the functions we'll need. All split up for comprehension purpose.
First, we have a struct. This struct is used to avoid checking, for every iteration, if the value on a given index was originally duplicated. We don't want to modify any value not duplicated originally.
Then, we have a couple functions: first, we need to see the worst case scenario: every value after the duplicated ones is already occupied: then we need to increment the duplicated value up to the maximum value reached + 1.
Then, there are the main Function we'll discute later about.
The check Function only checks if there's any duplicated value in a temporary solution.
int main() { //testing purpose
int i;
int testArray[] = { 3,2,1,2,7 }; //test array
int nTestArraySize = 5; //test array size
int *solutionArray; //needed if you want to use the solution later
solutionArray = findDuplicateSum(testArray, nTestArraySize);
for (i = 0; i < nTestArraySize; ++i) {
printf("%d ", solutionArray[i]);
}
return 0;
}
This is the main Function: I used it to test everything.
int * findDuplicateSum(int * array, int arraySize)
{
int *solution = malloc(sizeof(int) * arraySize);
int *tempSolution = malloc(sizeof(int) * arraySize);
duplicate_t *duplicate = calloc(arraySize, sizeof(duplicate_t));
int i, j, currentSum = 0, totalSum = INT_MAX;
for (i = 0; i < arraySize; ++i) {
tempSolution[i] = solution[i] = duplicate[i].value = array[i];
currentSum += array[i];
for (j = 0; j < i; ++j) { //to find ALL the best solutions, we should also put the first found value as true; it's just a line more
//yet, it saves the algorythm half of the duplicated numbers (best/this case scenario)
if (array[j] == duplicate[i].value) {
duplicate[i].duplicate = TRUE;
}
}
}
if (findDuplicateSum_R(duplicate, arraySize, tempSolution, solution, &totalSum, currentSum));
else {
printf("No solution found\n");
}
free(tempSolution);
free(duplicate);
return solution;
}
This Function does a lot of things: first, it sets up the solution array, then it initializes both the solution values and the duplicate array, that is the one used to check for duplicated values at startup. Then, we find the current sum and we set the maximum available sum to the maximum integer possible.
Then, the recursive Function is called; this one gives us the info about having found the solution (that should be Always), then we return the solution as an array.
int findDuplicateSum_R(duplicate_t * array, int arraySize, int * tempSolution, int * solution, int * totalSum, int currentSum)
{
int i;
if (check(tempSolution, arraySize)) {
if (currentSum < *totalSum) { //optimal solution checking
for (i = 0; i < arraySize; ++i) {
solution[i] = tempSolution[i];
}
*totalSum = currentSum;
}
return TRUE; //just to ensure a solution is found
}
for (i = 0; i < arraySize; ++i) {
if (array[i].duplicate == TRUE) {
if (array[i].duplicate <= maxInArrayExcept(solution, arraySize, i)) { //worst case scenario, you need it to stop the recursion on that value
tempSolution[i]++;
return findDuplicateSum_R(array, arraySize, tempSolution, solution, totalSum, currentSum + 1);
tempSolution[i]--; //backtracking
}
}
}
return FALSE; //just in case the solution is not found, but we won't need it
}
This is the recursive Function. It first checks if the solution is ok and if it is the best one found until now. Then, if everything is correct, it updates the actual solution with the temporary values, and updates the optimal condition.
Then, we iterate on every repeated value (the if excludes other indexes) and we progress in the recursion until (if unlucky) we reach the worst case scenario: the check condition not satisfied above the maximum value.
Then we have to backtrack and continue with the iteration, that will go on with other values.
PS: an optimization is possible here, if we move the optimal condition from the check into the for: if the solution is already not optimal, we can't expect to find a better one just adding things.
The hard code has ended, and there are the supporting functions:
int maxInArrayExcept(int *array, int arraySize, int index) {
int i, max = 0;
for (i = 0; i < arraySize; ++i) {
if (i != index) {
if (array[i] > max) {
max = array[i];
}
}
}
return max;
}
BOOL check(int *array, int arraySize) {
int i, j;
for (i = 0; i < arraySize; ++i) {
for (j = 0; j < i; ++j) {
if (array[i] == array[j]) return FALSE;
}
}
return TRUE;
}
I hope this was useful.
Write if anything is unclear.
Well, I got the same question in one of my interviews.
Not sure if you still need it. But here's how I did it. And it worked well.
num_list1 = [2,8,3,6,3,5,3,5,9,4]
def UniqueMinSumArray(num_list):
max=min(num_list)
for i,V in enumerate(num_list):
while (num_list.count(num_list[i])>1):
if (max > num_list[i]+1) :
num_list[i] = max + 1
else:
num_list[i]+=1
max = num_list[i]
i+=1
return num_list
print (sum(UniqueMinSumArray(num_list1)))
You can try with your list of numbers and I am sure it will give you the correct unique minimum sum.
I got the same interview question too. But my answer is in JS in case anyone is interested.
For sure it can be improved to get rid of for loop.
function getMinimumUniqueSum(arr) {
// [1,1,2] => [1,2,3] = 6
// [1,2,2,3,3] = [1,2,3,4,5] = 15
if (arr.length > 1) {
var sortedArr = [...arr].sort((a, b) => a - b);
var current = sortedArr[0];
var res = [current];
for (var i = 1; i + 1 <= arr.length; i++) {
// check current equals to the rest array starting from index 1.
if (sortedArr[i] > current) {
res.push(sortedArr[i]);
current = sortedArr[i];
} else if (sortedArr[i] == current) {
current = sortedArr[i] + 1;
// sortedArr[i]++;
res.push(current);
} else {
current++;
res.push(current);
}
}
return res.reduce((a,b) => a + b, 0);
} else {
return 0;
}
}

Find kth min node in AVL tree

I now have built a AVL tree, Here is a function to find kth min node in AVL tree
(k started from 0)
Code:
int kthMin(int k)
{
int input=k+1;
int count=0;
return KthElement(root,count,input);
}
int KthElement( IAVLTreeNode * root, int count, int k)
{
if( root)
{
KthElement(root->getLeft(), count,k);
count ++;
if( count == k)
return root->getKey();
KthElement(root->getRight(),count,k);
}
return NULL;
}
It can find some of right nodes, but some may fail, anyone can help me debug this>
THanks
From the root, after recursing left, count will be 1, regardless of how many nodes are on the left.
You need to change count in the recursive calls, so change count to be passed by reference (assuming this is C++).
int KthElement( IAVLTreeNode * root, int &count, int k)
(I don't think any other code changes are required to get pass by reference to work here).
And beyond that you need to actually return the value generated in the recursive call, i.e. change:
KthElement(root->getLeft(), count, k);
to:
int val = KthElement(root->getLeft(), count, k);
if (val != 0)
return val;
And similarly for getRight.
Note I used 0, not NULL. NULL is typically used to refer to a null pointer, and it converts to a 0 int (the latter is preferred when using int).
This of course assumes that 0 isn't a valid node in your tree (otherwise your code won't work). If it is, you'll need to find another value to use, or a pointer to the node instead (in which case you can use NULL to indicate not found).
Here is simple algorithm for Kth smallest node in any tree in general:-
count=0, found=false;
kthElement(Node p,int k) {
if(p==NULL)
return -1
else {
value = kthElement(p.left)
if(found)
return value
count++
if(count==k) {
found = true
return p.value
}
value = kthElement(p.right)
return value
}
}
Note:- Use of global variables is the key.

Type conversion on multidimensional map iterator

struggling a bit with getting ahold of map keys. I am wanting this method to modify a vector of edges where the index is the dest node and the value at that index is the weight. The vector "edges" is already initialized large enough to hold the edges. The compiler is complaining that it cannot convert iterator type to int. Anyone have any advice or thoughts on how to handle this conversion if it is even possible? Thanks. This is part of an assignment I am working on implementing Dijkstra's shortest path for a MOOC.
void CompleteGraph::GetNodeEdges(int Node, std::vector<int> &edges){
// Modifies a vector of edges given the source node sorted by edge weight
// Iterate over a map. Grab all edges that have the given start node(map's 1st key)
typedef std::map<int, std::map<int, int> >::iterator iter;
for(iter i = Graph.begin(); i != Graph.end(); i++){
if (i->first == Node){
edges[i->second.begin()] = i->second.end();
}
}
// Sort vector here: will do this next
}
Your problem is obviously on this line:
edges[i->second.begin()] = i->second.end();
The type of the key of edges is int, but i->second.begin() is returning an iterator, because i->second returns a map. I guess you need something like:
edges[i->second.begin()->first] = i->second.end();
Depending on what information from Graph you want to use, as you haven't told us about what the Graph represents.
I suspect you are looking for something like this:
iter i = Graph.find(Node);
if (i != Graph.end()) {
map<int, int>& edges_map = i->second;
for (map<int, int>::iterator m = edges_map.begin();
m != edges_map.end(); ++m) {
if (edges.size() <= m->first) {
edges.resize(m->first + 1);
}
edges[m->first] = m->second;
}
}

Can a redblack tree cope with this comparison function?

I was thinking to use a RedBlack tree that does not support multiple insertion of the same key using a comparison function similar to this one:
int compare(MyObject A, MyObject B)
{
if (A.error > B.error) return 1;
if (A.error < B.error) return -1;
if (A.name == B.name) return 0;
return 1;
}
this trick would be useful to have multiple items with the same error, but different "name". If two items with the same error are found, but the value does not coincide, the comparing item is just treated as "bigger".
I am pretty sure that this trick would work with a normal BST...but I am having troubles with a redblack tree. I do not know the redblack tree algorithm, I am using an implementation, so I wonder if there is any reason why this should not work.
P.S.: name does not have a comparison relationship...so the only thing I can do is to check if they are the same.
P.P.S.: assuming that this does not work and knowing that I cannot have a order relation between the "name" values, what other possibilities do I have? I could use a data structure that allow to insert multiple values with the same key, but that won't work for me, because when I delete a value, I must be sure that I am deleting the value I am actually passing (basically for me the key and the value hare the same thing, I need a sort of ordered multiset data structure!)
Your binary search trees expect your comparison function to obey the usual rules for a total ordering over the elements you are going to insert into the tree. Your current comparison function doesn't obey this because if you have objects A and B with the same error key but different value keys then according to compare you both A < B and B < A are valid.
I think it should all work correctly if you change your comparison function to
int compare(MyObject A, MyObject B)
{
if (A.error > B.error) return 1;
if (A.error < B.error) return -1;
if (A.value > B.value) return 1;
if (A.value < B.value) return -1;
return 0;
}
You did not define an order relation.
In your case, your objects are two-dimensional. I understand from your question that the priority in ordering should be given to the error field. Thus, an order relation (using lexicographic order) should be :
struct my_object {
int error;
int value;
};
int compare(struct my_object *a, struct my_object *b)
{
int ret;
if (!a) {
return 1;
}
else if (!b) {
return -1;
}
ret = a->error - b->error;
if (!ret) {
ret = a->value - b->value;
}
return ret;
}

What would be the datastructure in following scenario? (Stack with maximum)

Please note that there is no limitation of memory.
I need to insert int from 1 to 1000.
I can do the each of the following operations in constant order of time:
push():adds to the top
pop():removes the top element
getMax(): returns the max element
Please suggest me appropriate datastructure.
Since there is no limitation of memory, I will use 2 vectors - one for the actual data on the stack, and the other to keep track of the max at every state of the stack.
For simplicity sake I'm assuming this stack holds only +ve ints.
I know this doesn't have any error checking. But I am just providing the data structure idea here, not the full-fledged solution.
class StackWithMax
{
public:
StackWithMax() : top(-1), currentMax(0) { }
void push(int x);
int pop();
int getMax() { return m[top]; }
private:
vector<int> v; // to store the actual elements
vector<int> m; // to store the max element at each state
int top;
int currentMax;
};
void StackWithMax::push(int x)
{
v[++top] = x;
m[top] = max(x, currentMax);
}
int StackWithMax::pop()
{
int x = v[top--];
currentMax = m[top];
return x;
}
Use normal stack structure and additional array for counters
int c[1..1000] and variable int maxVal=0.
In code add actions after stack operations:
On push(x) -> c[x]++ ; maxVal = max(x,maxVal)
On pop():x -> c[x]-- ; if (c[x] == 0) { j=x; while(c[--j] == 0); maxVal = j; }
maxVal should have always maximum value.
Maybe I am wrong, this should have amortized computational complexity O(1).
It has been a long time since I have been analysing algorithms.

Resources