The Question:
Given an array A of N distinct integers and an array B of integers(need not be distinct). Find the min no. of numbers that need to be added to B to make A a subsequence of it.
My Strategy:
Quite simple- find the longest common subsequence, lcs and so the answer is sizeof(A) - lcs.
My Code:
int lcs(vector<int>A, vector<int>B, int n, int m)
{
int L[m + 1][n + 1];
int i, j;
/* Following steps build L[m+1][n+1] in
bottom up fashion. Note that L[i][j]
contains length of LCS of X[0..i-1]
and Y[0..j-1] */
for (i = 0; i <= m; i++)
{
for (j = 0; j <= n; j++)
{
if (i == 0 || j == 0)
L[i][j] = 0;
else if (B[i - 1] == A[j - 1])
L[i][j] = L[i - 1][j - 1] + 1;
else
L[i][j] = max(L[i - 1][j], L[i][j - 1]);
}
}
/* L[m][n] contains length of LCS
for A[0..n-1] and B[0..m-1] */
return (n - L[m][n]);
}
My output:
I am getting wrong output. (Differing mostly by 1.) I was also getting TLE for some test cases.
can someone locate where i am going wrong in logic or in code?
If A == [1, 2, 3, 4, 5] and B == [1, 2, 4, 5] then longest common sequence is 2 and your answer is 3, but you only need to add a single number 3 to B to meet the requirements. So the overall logic seems incorrect
Related
I came across an article that has the following statement:
maxSubArray(A, i) = maxSubArray(A, i - 1) > 0 ? maxSubArray(A, i - 1) : 0 + A[i];
My question is, would maxSubArray(A, i - 1) be evaluated (called) twice (if its value is greater than 0)? Does it increase the time complexity of the code? I think so, since we would end up calling the recursive function twice (if its value is greater than 0).
Edit: Here's the code:
public int maxSubArray(int[] A) {
int n = A.length;
int[] dp = new int[n];//dp[i] means the maximum subarray ending with A[i];
dp[0] = A[0];
int max = dp[0];
for(int i = 1; i < n; i++){
dp[i] = A[i] + (dp[i - 1] > 0 ? dp[i - 1] : 0);
max = Math.max(max, dp[i]);
}
return max;
}
and here is the related link. The above code is not directly related, since the one in my original question is from top-down DP approach, while the one added later on is from a bottom-up DP approach.
This:
maxSubArray(A, i) = maxSubArray(A, i - 1) > 0 ? maxSubArray(A, i - 1) : 0 + A[i];
is just a pseudo code notation of the relation between maxSubArray(A, i - 1) and maxSubArray(A, i). It just tells us how to compute the result for i when we do know the result for i-1. Read it like maths notation. Similar as
y = 5 * x
describes
int foo(int x) { return x*5; }
In the actual implementation the above recurrence relation is realized via:
dp[i] = A[i] + (dp[i - 1] > 0 ? dp[i - 1] : 0);
Here dp[i - 1] is merely accessing an element of an array. Accessing the same array element twice has no impact on complexity. Given that dp[i-1] is not modified in that line, a compiler might optimize it to access dp[i-1] only once.
In the presence of recursion, unnecessarily calling a function twice can have an impact on complexity. Consider this example (stolen from Jarod42):
int f(int n) {
if (n == 0) return 1;
return 2 * f(n - 1);
}
int f(int n) {
if (n == 0) return 1;
return f(n - 1) + f(n - 1);
}
Both yield the same result, but the first has linear complexity while the second is exponential.
Question:
So the question goes like this: I have N numbers. For each number X in the array of length N, I can perform 3 operations: 1. If X is a multiple of 2, divide X by 2. 2. If X is a multiple of 3, divide it by 3. 3. Subtract 1 from X. Find the minimum number of operations to make X = 0. This code is meant to be done using dynamic programming...
Input:
line 1: N line 2: Array X of N numbers
Output:
line 1: Number of operations to reduce X1 to 0. ... line N: Number of operations to reduce XN to 0.
So how should I go about doing this?
Code:
#include <bits/stdc++.h>
using namespace std;
int main(){
int N;
cin >> N;
for (int i = 0; i < N; i++){
int A, count = 0;
cin >> A;
while (A > 0){
if (A%2 == 0){
A /= 2;
count++;
}
else if (A%3 == 0){
A /= 3;
count++;
}
else{
A--;
count++;
}
}
cout << count << "\n";
}
}
This code which I currently have in mind does not work for some cases(meaning I do not output the desired solution, and that the code is a working code), say Xi = 10. My code does 10/2, then -1, then /2, then /2 then -1, so it is 5 operations. However, the optimal is 10 -1, /3, /3 again, then -1, which is 4 operations. Anyone has any idea how I should code my solution to this problem? Thanks! Any help is appreciated!
You said dynamic programming:
std::vector<int> v{0};
for (int i = 1; i != N + 1; ++i) {
v.push_back(v.back() + 1);
if (i % 2 == 0) {
v.back() = std::min(v.back(), v[i / 2] + 1);
}
if (i % 3 == 0) {
v.back() = std::min(v.back(), v[i / 3] + 1);
}
}
return v.back();
I have an exercise with an input N and it wants me to find a sequence of consecutive numbers which's multiple is equal to N. Example
Input | Output
60 | 3 5
3*4*5=60
What i have tried
cin>>b;
for (int i = 2; i <=b; ++i)
{
c=1;
for (int j = i; j <=b; ++j)
{
c*=j;
if(c==b){
cout<<i<<" "<<j<<endl;
return 0;
}else if(c>b){
j=b;
}
}
}
Here is a working solution in Python (see end of the post for C++ version):
def seq_with_product(n):
"""Return a sequence of consecutive numbers whose product is n."""
i, curr_prod = 1, 1
max_j = int(n**0.5) + 1 # n**0.5 is square root of n
for j in range(2, max_j + 1):
curr_prod *= j
while curr_prod > n and i < j-1:
curr_prod /= i
i += 1
if curr_prod == n:
return range(i, j+1)
return []
Let i and j be the start and end number in the current sequence. You start from the sequence with the smallest product [1, 2], and check if it is smaller than the given target n. If it is, you want to increase the product, so you include the next number by increasing j. As soon as you get to a product which is larger, you start removing numbers from the product, starting from the smallest (the while loop). If you get the exact product, your answer are the numbers between i and j. So for example, this is how you reach the answer to 60:
[1, 2] # too small, include the next number
[1, 2, 3] # too small, include the next number
[1, 2, 3, 4] # too small, include the next number
[1, 2, 3, 4, 5] # too big, remove the first number
[2, 3, 4, 5] # too big, remove the first number
[3, 4, 5] # found
Note that you don't need to consider numbers greater than the square root of the target number plus one, so you can stop at max_j.
In C++, it would be something like:
int i = 1, curr_prod = 1;
int max_j = sqrt(n) + 1;
for (int j = 2; j <= max_j; j++) {
curr_prod *= j;
while (curr_prod > n && i < j - 1) {
curr_prod /= i;
i += 1;
}
if (curr_prod == n) cout << i << " " << j << endl;
}
Because of this assignment, the inner loop will never terminate if no sequence with the given starting value i is found:
else if (c > b) {
j = b;
}
Instead you should do this:
else if (c > b) {
break;
}
This will terminate the inner loop and check for a sequence with the next start value i+1.
You should also consider the (very common) case that the only sequence contains only one element which is the number N itself.
I have a problem:
You are given a sequence, in the form of a string with characters ‘0’, ‘1’, and ‘?’ only. Suppose there are k ‘?’s. Then there are 2^k ways to replace each ‘?’ by a ‘0’ or a ‘1’, giving 2^k different 0-1 sequences (0-1 sequences are sequences with only zeroes and ones).
For each 0-1 sequence, define its number of inversions as the minimum number of adjacent swaps required to sort the sequence in non-decreasing order. In this problem, the sequence is sorted in non-decreasing order precisely when all the zeroes occur before all the ones. For example, the sequence 11010 has 5 inversions. We can sort it by the following moves: 11010 →→ 11001 →→ 10101 →→ 01101 →→ 01011 →→ 00111.
Find the sum of the number of inversions of the 2^k sequences, modulo 1000000007 (10^9+7).
For example:
Input: ??01
-> Output: 5
Input: ?0?
-> Output: 3
Here's my code:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <math.h>
using namespace std;
void ProcessSequences(char *input)
{
int c = 0;
/* Count the number of '?' in input sequence
* 1??0 -> 2
*/
for(int i=0;i<strlen(input);i++)
{
if(*(input+i) == '?')
{
c++;
}
}
/* Get all possible combination of '?'
* 1??0
* -> ??
* -> 00, 01, 10, 11
*/
int seqLength = pow(2,c);
// Initialize 2D array of integer
int **sequencelist, **allSequences;
sequencelist = new int*[seqLength];
allSequences = new int*[seqLength];
for(int i=0; i<seqLength; i++){
sequencelist[i] = new int[c];
allSequences[i] = new int[500000];
}
//end initialize
for(int count = 0; count < seqLength; count++)
{
int n = 0;
for(int offset = c-1; offset >= 0; offset--)
{
sequencelist[count][n] = ((count & (1 << offset)) >> offset);
// cout << sequencelist[count][n];
n++;
}
// cout << std::endl;
}
/* Change '?' in former sequence into all possible bits
* 1??0
* ?? -> 00, 01, 10, 11
* -> 1000, 1010, 1100, 1110
*/
for(int d = 0; d<seqLength; d++)
{
int seqCount = 0;
for(int e = 0; e<strlen(input); e++)
{
if(*(input+e) == '1')
{
allSequences[d][e] = 1;
}
else if(*(input+e) == '0')
{
allSequences[d][e] = 0;
}
else
{
allSequences[d][e] = sequencelist[d][seqCount];
seqCount++;
}
}
}
/*
* Sort each sequences to increasing mode
*
*/
// cout<<endl;
int totalNum[seqLength];
for(int i=0; i<seqLength; i++){
int num = 0;
for(int j=0; j<strlen(input); j++){
if(j==strlen(input)-1){
break;
}
if(allSequences[i][j] > allSequences[i][j+1]){
int temp = allSequences[i][j];
allSequences[i][j] = allSequences[i][j+1];
allSequences[i][j+1] = temp;
num++;
j = -1;
}//endif
}//endfor
totalNum[i] = num;
}//endfor
/*
* Sum of all Num of Inversions
*/
int sum = 0;
for(int i=0;i<seqLength;i++){
sum = sum + totalNum[i];
}
// cout<<"Output: "<<endl;
int out = sum%1000000007;
cout<< out <<endl;
} //end of ProcessSequences method
int main()
{
// Get Input
char seq[500000];
// cout << "Input: "<<endl;
cin >> seq;
char *p = &seq[0];
ProcessSequences(p);
return 0;
}
the results were right for small size input, but for bigger size input I got time CPU time limit > 1 second. I also got exceeded memory size. How to make it faster and optimal memory use? What algorithm should I use and what better data structure should I use?, Thank you.
Dynamic programming is the way to go. Imagine You are adding the last character to all sequences.
If it is 1 then You get XXXXXX1. Number of swaps is obviously the same as it was for every sequence so far.
If it is 0 then You need to know number of ones already in every sequence. Number of swaps would increase by the amount of ones for every sequence.
If it is ? You just add two previous cases together
You need to calculate how many sequences are there. For every length and for every number of ones (number of ones in the sequence can not be greater than length of the sequence, naturally). You start with length 1, which is trivial, and continue with longer. You can get really big numbers, so You should calculate modulo 1000000007 all the time. The program is not in C++, but should be easy to rewrite (array should be initialized to 0, int is 32bit, long in 64bit).
long Mod(long x)
{
return x % 1000000007;
}
long Calc(string s)
{
int len = s.Length;
long[,] nums = new long[len + 1, len + 1];
long sum = 0;
nums[0, 0] = 1;
for (int i = 0; i < len; ++i)
{
if(s[i] == '?')
{
sum = Mod(sum * 2);
}
for (int j = 0; j <= i; ++j)
{
if (s[i] == '0' || s[i] == '?')
{
nums[i + 1, j] = Mod(nums[i + 1, j] + nums[i, j]);
sum = Mod(sum + j * nums[i, j]);
}
if (s[i] == '1' || s[i] == '?')
{
nums[i + 1, j + 1] = nums[i, j];
}
}
}
return sum;
}
Optimalization
The code above is written to be as clear as possible and to show dynamic programming approach. You do not actually need array [len+1, len+1]. You calculate column i+1 from column i and never go back, so two columns are enough - old and new. If You dig more into it, You find out that row j of new column depends only on row j and j-1 of the old column. So You can go with one column if You actualize the values in the right direction (and do not overwrite values You would need).
The code above uses 64bit integers. You really need that only in j * nums[i, j]. The nums array contain numbers less than 1000000007 and 32bit integer is enough. Even 2*1000000007 can fit into 32bit signed int, we can make use of it.
We can optimize the code by nesting loop into conditions instead of conditions in the loop. Maybe it is even more natural approach, the only downside is repeating the code.
The % operator is, as every dividing, quite expensive. j * nums[i, j] is typically far smaller that capacity of 64bit integer, so we do not have to do modulo in every step. Just watch the actual value and apply when needed. The Mod(nums[i + 1, j] + nums[i, j]) can also be optimized, as nums[i + 1, j] + nums[i, j] would always be smaller than 2*1000000007.
And finally the optimized code. I switched to C++, I realized there are differences what int and long means, so rather make it clear:
long CalcOpt(string s)
{
long len = s.length();
vector<long> nums(len + 1);
long long sum = 0;
nums[0] = 1;
const long mod = 1000000007;
for (long i = 0; i < len; ++i)
{
if (s[i] == '1')
{
for (long j = i + 1; j > 0; --j)
{
nums[j] = nums[j - 1];
}
nums[0] = 0;
}
else if (s[i] == '0')
{
for (long j = 1; j <= i; ++j)
{
sum += (long long)j * nums[j];
if (sum > std::numeric_limits<long long>::max() / 2) { sum %= mod; }
}
}
else
{
sum *= 2;
if (sum > std::numeric_limits<long long>::max() / 2) { sum %= mod; }
for (long j = i + 1; j > 0; --j)
{
sum += (long long)j * nums[j];
if (sum > std::numeric_limits<long long>::max() / 2) { sum %= mod; }
long add = nums[j] + nums[j - 1];
if (add >= mod) { add -= mod; }
nums[j] = add;
}
}
}
return (long)(sum % mod);
}
Simplification
Time limit still exceeded? There is probably better way to do it. You can either
get back to the beginning and find out mathematically different way to calculate the result
or simplify actual solution using math
I went the second way. What we are doing in the loop is in fact convolution of two sequences, for example:
0, 0, 0, 1, 4, 6, 4, 1, 0, 0,... and 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,...
0*0 + 0*1 + 0*2 + 1*3 + 4*4 + 6*5 + 4*6 + 1*7 + 0*8...= 80
The first sequence is symmetric and the second is linear. It this case, the sum of convolution can be calculated from sum of the first sequence which is = 16 (numSum) and number from second sequence corresponding to the center of the first sequence, which is 5 (numMult). numSum*numMult = 16*5 = 80. We replace the whole loop with one multiplication if we are able to update those numbers in each step, which fortulately seems the case.
If s[i] == '0' then numSum does not change and numMult does not change.
If s[i] == '1' then numSum does not change, only numMult increments by 1, as we shift the whole sequence by one position.
If s[i] == '?' we add original and shiftet sequence together. numSum is multiplied by 2 and numMult increments by 0.5.
The 0.5 means a bit problem, as it is not the whole number. But we know, that the result would be whole number. Fortunately in modular arithmetics in this case exists inversion of two (=1/2) as a whole number. It is h = (mod+1)/2. As a reminder, inversion of 2 is such a number, that h*2=1 modulo mod. Implementation wisely it is easier to multiply numMult by 2 and divide numSum by 2, but it is just a detail, we would need 0.5 anyway. The code:
long CalcOptSimpl(string s)
{
long len = s.length();
long long sum = 0;
const long mod = 1000000007;
long numSum = (mod + 1) / 2;
long long numMult = 0;
for (long i = 0; i < len; ++i)
{
if (s[i] == '1')
{
numMult += 2;
}
else if (s[i] == '0')
{
sum += numSum * numMult;
if (sum > std::numeric_limits<long long>::max() / 4) { sum %= mod; }
}
else
{
sum = sum * 2 + numSum * numMult;
if (sum > std::numeric_limits<long long>::max() / 4) { sum %= mod; }
numSum = (numSum * 2) % mod;
numMult++;
}
}
return (long)(sum % mod);
}
I am pretty sure there exists some simple way to get this code, yet I am still unable to see it. But sometimes path is the goal :-)
If a sequence has N zeros with indexes zero[0], zero[1], ... zero[N - 1], the number of inversions for it would be (zero[0] + zero[1] + ... + zero[N - 1]) - (N - 1) * N / 2. (you should be able to prove it)
For example, 11010 has two zeros with indexes 2 and 4, so the number of inversions would be 2 + 4 - 1 * 2 / 2 = 5.
For all 2^k sequences, you can calculate the sum of two parts separately and then add them up.
1) The first part is zero[0] + zero[1] + ... + zero[N - 1]. Each 0 in the the given sequence contributes index * 2^k and each ? contributes index * 2^(k-1)
2) The second part is (N - 1) * N / 2. You can calculate this using a dynamic programming (maybe you should google and learn this first). In short, use f[i][j] to present the number of sequence with j zeros using the first i characters of the given sequence.
I want to count the number of combinations we can prouduce of a given number.
For Example M= No. of digits and N=4 Length of a number
M= 3 ({3,7,5}) and N=4
Possible combinations:(The given 3 numbers must be there in the combination)
3577, 3557, 7353 and 5735 and other (32 possible combination)
I found this code on the net. This code is giving me correct output but I can't understand what logic it is using.
Please explain the code below and what its time complexity is.
Thanks in advance.
#define LL long long int
#define sd(x) scanf("%d", &x)
#define MOD 1000000007
#define D double
#define LD long double
#define N 200
LL dp[N][N];
inline void solve(){
int n, m, i, j;
sd(m); sd(n);
memset(dp, 0, sizeof dp);
dp[1][1] = m;
for(i = 1; i < n; i++){
for(j = 1; j <= i && j <= m; j++){
(dp[i + 1][j] += j * dp[i][j]) %= MOD;
(dp[i + 1][j + 1] += (m - j) * dp[i][j]) %= MOD;
}
}
cout<<dp[n][m]<<endl;
}
The dp in the code represent dynamic programming. In many programming contest platforms it stands from state.
Here in the problem:
dp[i][j] represents the number of ways to use j different digits in M to form a number whose length is i. Some requirements: j <= i and j <= M.
So let's assume, we already know a dp[i][j].
Then we can simply calculate dp[i + 1][j] = j * dp[i][j] (one more slot).
As for dp[i + 1][j + 1], it means we have one more slot and M - j choices can be fit in the slot. So dp[i + 1][j + 1] = (M - j) * dp[i][j].
Why M - j? Recall that
j different digits in M
Finally, with these two transition formulas and dp[1][1], we can calculate any dp[i][j] where i <= N and j <= M and j <= i.
Update: example
N = 4, M = 3.
We start by calculating dp[1][1], which is apparently dp[1][1] = 3. There is only one slot and we have M choices. (recall definition of dp)
Then we enter the loop: start from dp[1][1]:
To calculate dp[1 + 1][1]: It means we have two slot and one digits. We have only 1 choice here - use the same digit again. So dp[1 + 1][1] = 1 * dp[1][1] = 3. In your example, dp[2][1] represents {3, 3} {5, 5} {7, 7};
To calculate dp[1 + 1][1 + 1]: it means we have two slots and two different digits, so we have M - 1 choices. So it equals to dp[2][2] = 2 * dp[1][1] = 6. In your example, dp[2][2] represents {3, 5}, {3, 7}, {5, 3}, {5, 7}, {7, 3}, {7, 5}.
Then just follow the loop, we will get to dp[4][3] and it's the answer.