Reducing Algorithm Time Complexity of Recursive Function - c++

This is the code for function f(T,k) where
f(T,0)=∑(from i=1 to i≤len(T)) T[i], where len(T) is length of array T.
f(T,k)=∑(from i=1 to i≤len(T)) ∑(from j=i to j≤len(T)) f(T[i...j],k-1), for k>0, where len(T) is length
of array T and T[i...j] is sub-array of T with elements form the i-th to the j-th position (T[i],T[i+1],...,T[j])
It is a recursive function and I need to reduce the complexity, but I don't know how.
Can someone help me out?
This is the problem text:
1000000007 players participate in this game and the winner is decided by random selection. To make the selection random, the company has set strict rules for selecting that player. First they number the players with identification numbers from 0 to 1000000006. Then they choose array A with N elements and the number k. They then define the winner as the player who has the identification number f (A, k) mod (100000007)
#include <iostream>
#include <vector>
using namespace std;
int N,k,a;
vector<int>A;
int fja(vector<int>A,int k){
long long suma=0;
if(k==0){// If k==0 calculate the first said function
for(auto it=A.begin();it!=A.end();it++)suma=(suma+(*it))%(1000000007);//Moduo is there because suma is very big
return suma;
}else{//If k>0 calculate the second function
int duzina=A.size();//duzina is length of A (T)
for(int i=0;i<duzina;i++){//Going through the first and second sum of second function
for(int j=i;j<duzina;j++){
vector<int>b(A.begin()+i,A.begin()+j+1);//Creating new vector (array) to pass it into the new function call
suma=(suma+fja(b,k-1))%(1000000007);//Moduo is there because suma is very big
}
}
return suma;
}
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin>>N>>k; //Number of elements and k
for(int i=0;i<N;i++){
cin>>a;
A.push_back(a);//All the elements
}
cout<<fja(A,k);
}

I implemented non-recursive version, only loop-based, but it has O(k * n^4) so for biggest 10^5 values of N and k it will be too slow.
I provided recursive solution for reference, it can solve for N and k up to 10, my non-recursive solution can solve up to N and k of 100.
I'm sure some loops can be removed in my solution by algorithmic optimization. Still I could not figure out how to solve task for very large values of 10^5.
In current main() function N and k both are 10, for testing only, to leave only fast version you may change N and k from 10 to 100 and comment out f_ref() call. f_ref() is reference recursive function, f_fast() is my faster variant.
Try it online!
#include <cstdint>
#include <vector>
#include <iostream>
typedef uint32_t u32;
typedef int64_t i64;
typedef uint64_t u64;
enum { mod = 100000007 };
i64 f_ref(std::vector<i64> const & T, size_t begin, size_t end, size_t k) {
i64 sum = 0;
if (k == 0)
for (size_t i = begin; i < end; ++i)
sum = (sum + T[i]) % mod;
else
for (size_t i = begin; i < end; ++i)
for (size_t j = i; j < end; ++j)
sum = (sum + f_ref(T, i, j + 1, k - 1)) % mod;
return sum;
}
i64 f_fast(std::vector<i64> const & T, size_t k) {
size_t N = T.size();
std::vector<std::vector<i64>> mc, mn;
for (size_t n = 1; n <= N; ++n) {
mc.resize(mc.size() + 1);
for (size_t j = 0; j < n; ++j)
mc.back().push_back(((n + (n - 2 * j)) * (j + 1) / 2) % mod);
}
for (size_t ik = 0; ik + 1 < k; ++ik) {
mn.clear();
mn.resize(N);
for (size_t n = 1; n <= N; ++n) {
mn[n - 1].resize(n);
for (size_t i = 0; i < n; ++i)
for (size_t j = i; j < n; ++j)
for (size_t l = 0; l <= j - i; ++l)
mn[n - 1][i + l] = (mn[n - 1][i + l] + mc[j - i][l]) % mod;
}
mc = mn;
}
i64 sum = 0;
for (size_t i = 0; i < N; ++i)
sum = (sum + mc.back()[i] * (T[i] % mod)) % mod;
return sum;
}
int main() {
std::vector<i64> a;
for (size_t i = 0; i < 10; ++i)
a.push_back(i + 1);
size_t k = 10;
std::cout << f_ref(a, 0, a.size(), k) << " " << f_fast(a, k) << std::endl;
return 0;
}
Output for N = 10 and k = 10:
78689325 78689325
Output for N = 100 and k = 100:
37190121

Related

Leetcode 1588 sum of all ODD length subarrays. C++

I'm practicing myself by doing some leetcode questions, however, I don't know why that's an overflow problem right here. I knew the way I sum the subarray was terrible, any tips for the sum of the subarray?
and the run time for this code would be forever
#include <numeric>
class Solution {
public:
int sumOddLengthSubarrays(vector<int>& arr) {
int size = arr.size();//5
int ans = 0;
int sumAll = 0;
int start = 3;
int tempsum;
for(int i =0; i< size; i++){ //sumitself
sumAll += arr[i];
}
ans = sumAll; //alreayd have the 1 index
if(size%2 == 0){//even number 6
int temp = size-1; //5
if(size == 2)
ans = sumAll;
else{
while(start <= temp){//3 < 5
for(int i = 0; i< size; i++){
for(int k =0; k< start; k++){//3
tempsum += arr[i+k];
if(i+k > temp) //reach 5
break;
}
}
start+=2;
}
}
ans+= tempsum;
}
else{//odd number
if(size == 1)
ans = sumAll;
else{
while(start < size){//3
for(int i = 0; i< size; i++){
for(int k =0; k< start; k++){//3
tempsum += arr[i+k];
if(i+k > size) //reach 5
break;
}
}
start+=2;
}
ans+= tempsum;
ans+= sumAll; //size index
}
}
return ans;
}
};
The problem is with arr[i+k]. The result of i + k can be equal to, or larger, than size. You check it after you have already gone out of bounds.
You should probably modify the inner loop condition so that never happens:
for(int k =0; k < start && (i + k) < size; k++){//3
Now you don't even need the inner check.
You can use prefix sum array technique and then for each index you can calculate the sub-array sum for each odd-length array using prefix sum array. I submitted the below solution in LeetCode and it beats runtime of 100% of submissions and memory usage of 56.95%
class Solution {
public:
int sumOddLengthSubarrays(vector<int>& arr) {
int n = arr.size();
vector<int> prefix(n+1,0);
int sum = 0;
prefix[1] = arr[0];
for(int i=1;i<n;i++)
prefix[i+1]=(arr[i]+prefix[i]);
for(int i=0;i<n;i++)
{
for(int j=i;j<n;j+=2)
sum+=prefix[j+1]-prefix[i];
}
return sum;
}
};
https://leetcode.com/problems/sum-of-all-odd-length-subarrays/discuss/1263893/Java-100-one-pass-O(n)-with-explanation
class Solution {
public int sumOddLengthSubarrays(int[] arr) {
// alt solution: O(n)
//for each i:
// if(n -1 - i) is odd, then arr[i] is counted (n-1-i)/2 + 1 times, each from 0 to i, total ((n-i)/2+1)*(i+1) times
// if(n -1 - i) is even, then arr[i] is counted (n-1-i)/2 + 1 times, if starting subseq index diff with i is even;
// (n-1-i)/2 times, if starting index diff with i s odd, total (n-i)/2 *(i+1) + (i+1)/2
// if i is even i - 1, i - 3, .. 1, total (i -2)/2 + 1 = i / 2 = (i+1) / 2
// if i is odd i-1, i-3, .., 0 total (i-1)/2 + 1 = (i+1) / 2
int total = 0;
int n = arr.length;
for(int i = 0; i < n; i++)
total += (((n - 1 - i) / 2 + 1) * (i + 1) - ((n-i) % 2)*((i+1) / 2)) * arr[i];
return total;
}
}

Simulated annealing: too slow with poor results

I'm trying to solve, thanks to the simulated annealing method, the following problem :
Optimization problem
Where I already got the c_i,j,f values stored in a 1D array, so that
c_i,j,f <=> c[i + j * n + f * n * n]
My simulated annealing function looks like this :
int annealing(int n, int k_max, int c[]){
// Initial point (verifying the constraints )
int x[n * n * n];
for (int i = 0; i < n; i++){
for (int j = 0; j < n; j++){
for (int f = 0; f < n; f++){
if (i == j && j == f && f == i){
x[i + j * n + f * n * n] = 1;
}else{
x[i + j * n + f * n * n] = 0;
}
}
}
}
// Drawing y in the local neighbourhood of x : random permutation by keeping the constraints verified
int k = 0;
double T = 0.01; // initial temperature
double beta = 0.9999999999; // cooling factor
int y[n * n * n];
int permutation_i[n];
int permutation_j[n];
while (k <= k_max){ // k_max = maximum number of iterations allowed
Permutation(permutation_i, n);
Permutation(permutation_j, n);
for (int f = 0; f < n; f++){
for (int i = 0; i < n; i++){
for (int j = 0; j < n; j++){
y[i + j * n + f * n * n] = x[permutation_i[i] + permutation_j[j] * n + f * n * n];
}
}
}
if (f(y, c, n) < f(x, c, n) || rand()/(double)(RAND_MAX) <= pow(M_E, -(f(y, c, n)-f(x, c, n))/T)){
for (int i = 0; i < n; i++){
for (int j = 0; j < n; j++){
for (int f = 0; f < n; f++){
x[i + j * n + f * n * n] = y[i + j * n + f * n * n];
}
}
}
}
T *= beta;
++k;
}
return f(x, c, n);
}
The procedure Permutation(int permutation[], n) fills in the array permutation with a random permutation of [[0,n-1]] (for example, it would transform [0,1,2,3,4] into [3,0,4,2,1]).
The problem is, it takes too much time with 1000000 iterations, and the values of the objective function oscillate between 78 - 79 whilst I should get 0 as a solution.
I was also thinking I could do better when it comes to complexity...
Someone may help me please?
Thanks in advance!
I would use std::vector<int>, instead of arrays (and define a couple of constants):
#include <vector>
#include <algorithm>
#include <random>
int annealing(int n, int k_max, std::vector<int> c) {
const int N2 = n * n;
const int N3 = N2 * n;
std::vector<int> x(N3);
std::vector<int> y(N3);
std::vector<int> permutation_i(n);
std::vector<int> permutation_j(n);
// ...
The initial nested loops boil down to:
for (int i = 0; i < n; i++){
x[(i*N2) + (i + (i * n))] = 1;
}
This should be your Permutation function:
void Permutation(std::vector<int> & x)
{
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(x.begin(), x.end(), g);
}
Initialize vectors before use (0 to n-1):
std::iota(permutation_i.begin(), permutation_i.end(), 0);
std::iota(permutation_j.begin(), permutation_j.end(), 0);
I have no idea what your f function is, but you should edit it to accept std::vector as its first two arguments.

C++ - Maximize sum of two elements in the array and their indexes

How do I solve following programming riddle in O(N)?
Array of integers: Tab[N]
Find max(Tab[K] - K + Tab[L] + L)
where 0 <= K <= L <= N
The only solution I can come up with is O(N^2) where I compare each element and update maximum sum.
int curr_max = INTEGER_MIN;
for(int i = 0; i < N; i++){
for(int j = i; j < N; j++){
curr_max = max(Tab[i]-i + Tab[j] + j,curr_max);
}
}
In general, a possible way to solve such kind of tasks, due to K<=L constraint, is to use pre-calculated running max. (The version below can be optimized, but anyway has O(N) time and space complexity.)
int t[N+1]; // input
int a[N+1]; // running max t[i]-i, left to right
a[0] = t[0]-0;
for (int i = 1; i <= N; ++i)
a[i] = max(a[i-1], t[i]-i);
int b[N+1]; // running max t[i]+i, right to left
b[N] = t[N]+N;
for (int i = N-1; i >= 0; --i)
b[i] = max(b[i+1], t[i]+i);
int mx = a[0] + b[0];
for (int i = 1; i <= N; ++i)
mx = max(mx, a[i] + b[i]);
However, in our case, it can be shown that if K: Tab[K]-K -> max and L: Tab[K]+K -> max then K<=L. In other words, if L and K are indices of the two maxima respectively, the property L<=K holds. Therefore, the naïve approach should work too:
int K = 0, L = 0;
for (int i = 1; i <= N; ++i) {
if (t[i]-i > t[K]-K)
K = i;
if (t[i]+i > t[L]+L)
L = i;
}
assert(K <= L);
int mx = t[K]-K + t[L]+L;
How about:
int L_max = INTEGER_MIN;
int K_max = INTEGER_MIN;
for(int i=0; i<N; i++)
{
K_max = max(Tab[i] -i, K_max);
L_max = max(Tab[i] +i, L_max);
}
curr_max = K_max + L_max;
Note that it does not validate K <= L, neither does the code in the question.

memory issue in using partially initialized array(in 0/1 knapsack)

Given n items with size Ai and value Vi, and a backpack with size m. What's the maximum value can you put into the backpack?
Have you met this question in a real interview? Yes
Example
Given 4 items with size [2, 3, 5, 7] and value [1, 5, 2, 4], and a backpack with size 10. The maximum value is 9.
Note
You cannot divide item into small pieces and the total size of items you choose should smaller or equal to m.
int knapsack(int m, vector<int> A, vector<int> V) {
int dp[m + 1], tmp[m + 1];
for (int n = 1; n <= m; n++) {
//******the problem would disappear if i change n to start with 0
dp[n] = (n < A[0]) ? 0 : V[0] ;
tmp[n] = dp[n];
}
for (int i = 1; i < A.size(); i++) {
for (int n = 1; n <= m; n++) {
tmp[n] = dp[n];
}
for (int j = 1; j <= m; j++) {
if (j >= A[i]) {
dp[j] = max(tmp[j], (V[i] + tmp[j - A[i]]));
}
}
}
return dp[m];
}
I am failing the specific testcase and all other are fine(even larger m values)
m = 10, A = [2,3,5,7], V = [1,5,2,4]
Output: 563858905 (actually random every time) Expected: 9
I know this question is some what trivial but I'm really curious about the memory allocation process in this scenario
I'm guessing that it would be dangerous to use any array that is not initialized at the first memory location, can someone confirm with me?
I tried following code, a simpler version of yours;
#include <iostream>
using namespace std;
int knapsack(int m, int A[], int V[], int size) {
int dp[m+1], tmp[m+1];
for (int n = 1; n <= m; n++) { //*1*
dp[n] = (n < A[0]) ? 0 : V[0] ;
tmp[n] = dp[n];
}
for (int i = 1; i < 4; i++) { //*2*
for (int n = 1; n <= m; n++) { //*3*
tmp[n] = dp[n];
}
for (int j = 1; j <= m; j++) { //*4*
if (j >= A[i]) {
dp[j] = (tmp[j]> (V[i] + tmp[j - A[i]])? //*5*
tmp[j] :
(V[i] + tmp[j - A[i]])
);
}
}
}
cout << "answer:" << dp[m] << endl;
return dp[m];
}
int main(){
int a[] = {2,3,5,7};
int b[] = {1,5,2,4};
knapsack(10, a, b, 4);
return 0;
}
and got 8 as the answer, rather than a random number.
I'm not sure that my code is the correct version of yours, but I luckily noticed that the expression of V[i] + tmp[j-A[i]] at the line marked by "\\*5" accesses tmp[0] when j=2 and i=1, since A[1] == 2 and 2 >= A[1]. Thus it would not be safe without initialization of tmp[0] in this logic.
So, I guess you are right; the uninitialized value of tmp[0] may change the result value, (and in some cases the flow of the logic as well, at the conditional statement of line //*5.)

Fibonacci numbers - dynamic array

I want to write Fibonacci number program, using dynamic array in function. If I want to initialize array in the function, where I must delete this array? Here is code:
#include <iostream>
using namespace std;
int* fibo(int);
int main()
{
int *fibonacci, n;
cout << "Enter how many fibonacci numbers you want to print: ";
cin >> n;
fibonacci = fibo(n);
for (int i = 0; i<n; i++)
cout << fibonacci[i] << " ";
//for (int i = 0; i < n; i++)
//delete w_fibo[i];
//delete[] w_fibo;
return 0;
}
int* fibo(int n)
{
int* w_fibo = new int[n];
if (n >= 0)
w_fibo[0] = 1;
if (n >= 1)
w_fibo[1] = 1;
for (int i = 1; i < n; i++)
w_fibo[i + 1] = w_fibo[i] + w_fibo[i - 1];
return w_fibo;
}
You don't have to initialize the array! a better dynamic Fibonacci presentation could be like this:
int fib2 (int n) {
int i = 1, j = 0;
for (int k = 0; k < n; k++) { // The loop begins to work real after one loop (k == 1). Sounds interesting!
j += i; // Adds the produced number to the last member of the sequence and makes a new sentence.
i = j - i; // Produces the number that should be added to the sequence.
}
return j;
}
and you can get the n-th fib number using this method. It's O(log(n)) so it's so efficient.`
int fib3 (int n) {
int i = 1, j = 0, k = 0, h = 1, t=0;
while (n > 0) {
if (n % 2) { // |
t = j * h; // |
j = i * h + j * k + t;
i = i * k + t;
}
t = h * h;
h = 2 * k * h + t;
k = k * k + t;
n /= 2;
}
return j;
}
If you allocate a std::vector<int> inside fibo() and reserve enough memory, and then return it by value, the memory allocation is taken care for you by the compiler:
#include <iostream>
#include <vector>
using namespace std;
std::vector<int> fibo(int n)
{
std::vector<int> w_fibo;
w_fibo.reserve(n);
if (n >= 0)
w_fibo[0] = 1;
if (n >= 1)
w_fibo[1] = 1;
for (int i = 1; i < n; i++)
w_fibo[i + 1] = w_fibo[i] + w_fibo[i - 1];
return w_fibo;
}
int main()
{
int n = 10;
std::vector<int> fibonacci = fibo(n);
for (int i = 0; i<n; i++)
cout << fibonacci[i] << " ";
}
Live Example.
NOTE: This is guaranteed to avoid needlessly copying in C++11 (move semantics) and is likely to do so in C++98 (copy-elision using the return-value-optimization).
This is an old question, but just in case someone happens to pass by this might be helpful.
If you need a efficient method to get the nth Fibonacci number, we have a O(1) time complexity procedure.
It is based on Binet's formula, which I think our friends over at math.se will be better at proving, so feel free to follow that link.
The formula itself is, given a=1.618 and b=-0.618 (these are approximate values)
the n-th term is (a^n - b^n)/2.236. A good way to round that off(since we are using approximate values) would be adding 0.5 and taking the floor function.
math.floor(((math.pow(1.618,n)-math.pow(-0.618,n))/2.236 + 0.5)