How does memoization help here? - c++

I just solved the subset sum problem:
Given an integer array nums of size N. You are also given an integer B, you need to find whether there exists a subset in nums whose sum is B. If there exist a subset then return 1 else return 0.
Constraints are: 1 <= N <= 100; 1 <= nums[i] <= 100; 1 <= B <= 10^5;
The way I solved this problem is as below (0/1 knapsack):
vector<int> n;
int t;
unordered_map<string, long long> m;
int helper(int i, int sum) {
if(i>=n.size()) return sum==t;
string str=to_string(i)+"-"+to_string(sum);
if(m.count(str)) return m[str];
int val=helper(i+1, sum+n[i]);
val=max(val, helper(i+1, sum));
return m[str]=val;
}
int Solution::solve(vector<int> &nums, int B) {
n=nums;
t=B;
m.clear();
return helper(0,0);
}
This gets "Accepted". However, note that all the values in nums are positive; so IMO sum will only remain the same/go on increasing. i goes on increasing, too. So, we will never encounter a value previously stored in the memoization table.
But, if I remove memoization, it results in Wrong Answer for some large test case. What am I missing? Will any recursive call ever encounter a previous state?

You call helper twice, the second time with the lower sum than the first. Therefore a later call to helper could indeed have the same sum as an earlier call.
#user3386109 already gave a concrete set of num that demonstrates this. As for how often, consider the case where nums = [1, 1, ..., 1] 100 times. Then without memoization you'll call helper(100, 50) 100 choose 50 = 100,891,344,545,564,193,334,812,497,256 times. Over 100 octillion calls..takes a while.

Related

Sum of infinite array fails one test case

Problem Statement:
Given an array “A” of N integers and you have also defined the new
array “B” as a concatenation of array “A” for an infinite number of
times. For example, if the given array “A” is [1,2,3] then, infinite
array “B” is [1,2,3,1,2,3,1,2,3,.......]. Now you are given Q queries,
each query consists of two integers “L“ and “R”. Your task is to find
the sum of the subarray from index “L” to “R” (both inclusive) in the
infinite array “B” for each query.
vector<int> sumInRanges(vector<int> &arr, int n, vector<vector<long long>> &queries, int q) {
vector<int> ans;
for(int i=0; i<q; i++){
int l = queries[i][0];
int r = queries[i][1];
int sum = 0;
for(int j=l-1; j<r; j++){
sum += arr[j%n];
}
ans.push_back(sum);
}
return ans;
}
One test case is failing. Could someone suggest the edit required?
Good I've found link to your actual problem.
Take a look on note:
Sum Of Infinite Array
Note :
The value of the sum can be very large, return the answer as modulus 10^9+7.
....
Constraints :
1 <= T <= 100
1 <= N <= 10^4
1 <= A[i] <= 10^9
1 <= Q <= 10^4
1 <= L <= R <= 10^18
Time Limit: 1sec
So basically your code have problem with integer overflow.
Your implementation is to simple. You have to leverage fact that this infinitive array has a period otherwise your code never meets time requirement. You do not have to calculate sum of the all indexes, you can skip a lot and calculate correction using multiplication (modulo).
Your solution takes time proportional to l - r because it tries every number.
But this is unnecessary, as there are n identical periods that you can sum in a single go. So the running time can be made proportional to the length of A instead. (Find the multiple of the length just above or on l and the multiple just below r.)
E.g. to sum from 10 to 27 inclusive, use
1231231231|231231231231231231|23123123... = 1231231231|23+4x123+1|23123123...

Ways to go from a number to 0 the fastest way

So, I have a homework like this:
Given two number n and k that can reach the long long limit, we do such operation:
assign n = n / k if n is divisible by k
reduce n by 1 if n is not divisible by k
Find the smallest number of operations to go from n to 0.
This is my solution
#define ll long long
ll smallestSteps(ll n, ll k) {
int steps = 0;
if (n < k) return n;
else if (n == k) return 2;
else {
while (n != 0) {
if (n % k == 0) {
n /= k;
steps++;
}
else {
n--;
steps++;
}
}
return (ll)steps;
}
}
This solution is O(n/k) I think?
But I think that n and k could be extremely big, and thus the program could exceed the time limit of 1s. Is there any better way to do this?
Edit 1: I use ll for it to be shorter
The algorithm can be improved given these observations:
If n<k then k|(n-m) will never hold for any positive m. So the answer is n steps.
If (k|n) does not hold then the biggest number m, m<n for which it does is n - (n%k). So it takes n%k steps until (k|m) holds again.
Actually all that you need is to keep doing division with remainder using std::div (or rely on compiler to optimize) and increase steps by remainder+1.
steps=0
while(n>0)
mod = n%k
n = n/k
steps+=mod + 1
return steps
This can be done with an even simpler main program.
Convert n to base k. Let d be the number of digits in this number.
To get to 0, you will divide by k (d-1) times.
The number of times you subtract 1 is the digital sum of this number.
For instance, consider n=314, k=3.
314 in base 3 is 102122. This has 6 digits; the digital sum is 8.
You will have 6-1+8 steps ... 13 steps to 0.
Use your C++ packages to convert to the new base, convert the digits to integers, and do the array sum. This pushes all the shift-count work into module methods.
Granted this won't work for weird values of k, but you can also steal available conversion packages instead of writing your own.

Huge fibonacci modulo m C++

I'm trying to calculate Fn mod m, where Fn is the nth Fibonacci number. n may be really huge, so its really not efficient to calculate Fn in a straightforward way (matrix exponentiation would work, though). The problem statement asks us to do this without calculating Fn, using the distributive property of the modulo:
(a+b)mod m = [a mod m + b mod m] mod m
(Before anyone asks me, I looked up answers to this same problem. I'd like an answer to my specific question, however, since I'm not asking about the algorithm to solve this problem)
Using this and the fact that the nth Fibonacci number is just the sum of the previous two, I don't need to store Fibonacci numbers, but rather only the results of calculating successive modulo operations. In that sense, I should have an array F of size n which has in it stored the results of iteratively calculating Fn mod m using the above property. I have managed to solve this problem using the following code. However, upon reviewing it, I stumbled upon something that rather confused me.
long long get_fibonacci_huge_mod(long long n, long long m) {
long long Fib[3] = {0, 1, 1};
long long result;
long long index;
long long period;
long long F[n+1];
F[0] = 0;
F[1] = 1;
F[2] = 1;
for (long long i = 3; i <= n; i++) {
F[i] = (F[i-2] + F[i-1]) % m;
if (F[i] == 0 && F[i+1] == 1 && F[i+2] == 1) {
period = i;
break;
}
}
index = n % period;
result = F[index];
return result;
}
This solution outputs correct results for any n and m, even if they are quite large. It might get a little bit slow when n is huge, but I'm not worried about that right now. I'm interested in specifically solving the problem this way. I'll try solving it using matrix exponentiation or any other much faster algorithm later.
So my question is as follows. At the beginning of the code, I create an array F of size n+1. Then I iterate through this array calculating Fn mod m using the distributive property. One thing that confused me after writing this loop was the fact that, since F was initialized to all zeros, how is it correctly using F[i+2], F[i+1], if they haven't been calculated yet? I assume that they are being correctly used since the algorithm outputs correct results every time. Perhaps this assumption is wrong?
My question isn't about the algorithm per se, I'm asking about what's going on inside the loop.
Thank you
This is a faulty implementation of a correct algorithm. Let us look at the corrected version first.
long long get_fibonacci_huge_mod(long long n, long long m) {
long long result;
long long index;
long long period = n+1;
long long sz = min (n+1,m*m+1); // Bound for period
long long *F = new long long[sz];
F[0] = 0;
F[1] = 1;
F[2] = 1;
for (long long i = 3; i < sz; i++) {
F[i] = (F[i-2] + F[i-1]) % m;
if (F[i] == 1 && F[i-1] == 0) { // we have got back to where we started
period = i-1;
break;
}
}
index = n % period;
result = F[index];
delete[]F;
return result;
}
So why does the original code work? Because you got lucky. The checks for i+1 and i+2 never evaluated to true because of the lucky garbage the array was initialized to. As a result this reduced to the naive evaluation of F(n) without incorporating periodicity at all.

Having trouble reading the output of my code

So the question was to return the difference between the maximum number and the smallest. My first code written was.
public int bigDiff(int[] nums) {
int max = 0;
int min = 0;
for(int i = 0; i < nums.length; i++){
if(Math.max(max, nums[i]) == nums[i])
max = nums[i];
else if (Math.min(min, nums[i]) == nums[i])
min = nums[i];
}
return max-min;
}
but this only outputs the largest number in the list.
Although, when I was just playing around and changed
int max = nums[0];
int min = nums[0];
it worked?, but I have no idea why. If anyone could understand how I would appreciate an explanation :D
Imagine array of values: 1,2,3. The proper minumum is 1. But, you have initialized min to 0. No value from this array is less than 0, so, min remains 0. Whoops, the answer is wrong. The similar case: array of -1, -2, -3, and maximum inited to 0 - again, wrong result.
I know three standard approaches to fix this:
Maximum and minimum are inited to the first value of sequence (array, in your case). That is exactly how you fixed it - by setting to nums[0]. OTOH you needn't start with index 0 - 1 is good also (very minor optimization but worth noting).
Maximum is inited with a smallest value ever possible for this type (for int, it's INT_MIN from <limits.h>), and minumum - to possible maximal one (INT_MAX, respectively). Most likely both will be immediately updated with nums[0].
A boolean variable with meaning "no values yet" is tested, and direct assignment instead of comparing is used when it is set (in your case, with i == 0 and immediately reset to false. It's a definitely overkill for a directly available integer array, but is good for cumbersome situations when comparing is inside of a callback instantiated through a template calling sequence, or another too-many-abstraction-levels design...
You have already warned that else is wrong, but, mathematically, it's allowed for my variants 1 and 3 (but not for variant 2! let you find out the fail proof by itself).
When you was just playing around and changed int max = nums[0]; int min = nums[0]; it worked.
Because, if you want to get the max num, you have to let variable max smaller than all of the member of arrary, then the function max() will make the max be the current maximum number。
So,the variable min must be larger then each member of the array!

How to trace error with counter in do while loop in C++?

I am trying to get i to read array with numbers and get the smaller number, store it in variable and then compare it with another variable that is again from two other numbers (like 2,-3).
There is something wrong in the way I implement the do while loop. I need the counter 'i' to be updated twice so it goes through I have 2 new variables from 4 compared numbers. When I hard code it n-1,n-2 it works but with the loop it gets stuck at one value.
int i=0;
int closestDistance=0;
int distance=0;
int nextDistance=0;
do
{
distance = std::min(values[n],values[n-i]); //returns the largest
distance=abs(distance);
i++;
nextDistance=std::min(values[n],values[n-i]);
nextDistance=abs(closestDistance); //make it positive then comp
if(distance<nextDistance)
closestDistance=distance;//+temp;
else
closestDistance=nextDistance;
i++;
}
while(i<n);
return closestDistance;
Maybe this:
int i = 0;
int m = 0;
do{
int lMin = std::min(values[i],values[i + 1]);
i += 2;
int rMin = std::min(values[i], values[i + 1]);
m = std::min(lMin,rMin);
i += 2;
}while(i < n);
return m;
I didn't understand what you meant, but this compares values in values 4 at a time to find the minimal. Is that all you needed?
Note that if n is the size of values, this would go out of bounds. n would have to be the size minus 4, leading to odd exceptional cases.
The issue with your may be in the call to abs. Are all the values positive? Are you trying to find the smallest absolute value?
Also, note that using i += 2 twice ensures that you do not repeat any values. This means that you will go over 4 unique values. Your code goes through 3 in each iteration of the loop.
I hope this clarified.
What are you trying to do in following lines.
nextDistance=std::min(values[n],values[n-i]);
nextDistance=abs(closestDistance); //make it positive , then computed