Stuck on recursion algorithm in arrays - c++

I got stuck with the following task:
"Write a recursive function that takes a one-dimensional array of 100 randomly set integers and finds the position at which a sequence of 10 numbers begins with the minimum sum".
I've written 2 functions:
int recursiveArrSum(int mass[], int dim = 10, int sum = 0) {
if (dim == 0) return sum;
sum += mass[dim-1];
return recursiveArrSum(mass, --dim, sum);
}
int recArrMinSum(int mass[], int dim=100, int tempSum=100, int idx=0, int addPar=0){
if (dim == 0) return idx;
mass[dim]=mass[addPar];
if (tempSum >= recursiveArrSum(mass)){
tempSum = recursiveArrSum(mass);
idx = dim-1;
//mass[dim]=mass[addPar];
}return recArrMinSum(mass, --dim, tempSum, idx, ++addPar);
1st one (recursiveArrSum) - works fine, but the second one drives me crazy...
I can't understand how I need to iterate an array during evoking the function on last return statement. I made it using for loop, and it works correctly:
for (int i=0; i<91; i++){
int tempS=0;
for (int j=i; j<=i+9; j++){
tempS += arr[j];
cout << tempS<< endl;
}
if (tempS<tempSum) {
tempSum=tempS;
k=i+1;
}
}
but recursion doesn't...
Could anyone suggest me the way for solving this issue?
Open for any questions.
Thanks in advance.

This is how I would do it:
A function that keeps in its arguments the current position, the current sum, the minimum sum and the starting position of this minimum sum. The function also transports as arguments the array (obviously), its size and the dimension of the sum (10 in your case).
void compute(int mass[], int massSize = 100, int dim = 10, int currentPosition = 0, int currentSum = 0, int minSum = 99999, int minPosition = -1)
{
// Before suming the first dim elements, we keep going adding the element at the current position and we increase the current position.
if (currentPosition < dim)
{
compute(mass, massSize, dim, currentPosition + 1, currentSum + mass[currentPosition], minSum, minPosition);
return;
}
// When reaching the end of the array, we print our best solution.
if (currentPosition > massSize)
{
std::cout << "Min sum of " << dim << " elements is " << minSum << ", starting at position " << minPosition << std::endl;
return;
}
// In all the other cases, we check if the current sum is better than the minimum sum. If yes, we update the minimum sum and its starting position. Then call again the function!
if (currentSum < minSum)
{
minSum = currentSum;
minPosition = currentPosition - dim;
}
compute(mass, massSize, dim, currentPosition + 1, currentSum + mass[currentPosition ] - mass[currentPosition -dim], minSum, minPosition);
}
Calling the function is easy: compute(mass, SIZE, 10); where mass is your array, SIZE is its size and 10 is your dimension.
With a dimension equals to 5 in this array:
8; 8; 4; 10; 9; 9; 6; 3; 3; 5; 3; 8; 3; 7; 9; 10; 10; 5; 6; 4; 1; 4; 1; 5; 2; 8; 6; 1; 7; 9;
Min sum of 5 elements is 13, starting at position 20
When writing a recursive function, the first things to do is to think about the exit case, the init cases (if there are any) and the "classic" case when you're in the middle of your search.
Feel free to ask any question, I added some comments to make it clear enough.

It is unclear how your code is supposed to work. To iterate the array and find the smallest sum you do something like this (pseudo code):
int currentSum = sum of elements 0 till 9
int smallestSum = currentSum
int smallestIndex = 0
for (i = 10; i < 100; ++i) {
currentSum = currentSum - mass[ i -10] + mass[i]
if (currentSum < smallestSum) {
smallestSum = currentSum
smallestIndex = i
}
}
As initial guess it takes the sum of the first 10 elements, ie elements 0 till 9. After that it iterates the array. Sum of elements 1 till 10 is the same as sum of elements 0 till 9 minus first element plus element 10. More general: To get the sum in the next iteration, element at i-10 is subtracted and element at i is added.

Not exactly sure what you're allowed to include from the STL, but there's this solution:
// Or std::pair<int, int*>
struct resultPair {
int first;
int* second;
};
// Or std::accumulate
int sumOf(int* arr, size_t s) {
int sum = 0;
for (size_t i=0; i<s; ++i)
sum += arr[i];
return sum;
}
resultPair minSeqOfN(int* arr, size_t s, size_t N) {
if (s < N) throw; // Or however you want to check pre-conditions
int sum = sumOf(arr, N);
if (s == N) return { sum, arr }; // Base case
auto nextRes = minSeqOfN(arr+1, s-1, N);
if (nextRes.first < sum) return nextRes;
else return resultPair{sum, arr};
}
The function keeps calling itself minus the first element, until the sequence size is equal to the input array size (then there's just 1 possible answer).

Related

Trying to make a simple Array sorter with input numbers

I'm very new to C++ or even coding. I was trying to make a simple array sorter, where the I first input the number of elements that will be in the array and then input the elements. My outcome should be the array sorted in ascending order. I have not thought about the case if elements inserted are same. So I would love to get some help from you folks.
The main error that I'm facing is that only the first unsorted element is sorted while the rest are either interchanged or left the same.
int main(){
int x;
cout<<"Enter no. of elements"<<endl;
cin>>x;
int A[x];
for (int i = 0;i<x;i++){
cin>>A[i];
}
for(int i=0;i<x;i++)
cout<<A[i]<<",";
int count=0;
if(count <= (x-1)){
for (int i=0;i<(x-1);i++){
if(A[i]>A[i+1]){
int a;
a = A[i];
A[i] = A[(i+1)];
A[i+1] = a;
}
else if(A[i]<A[i+1])
count++;
}
}
cout<<"Sorted array:";
for(int i=0;i<x;i++)
cout<<A[i]<<",";
return 0;
}
You declared a variable length array
int x;
cout<<"Enter no. of elements"<<endl;
cin>>x;
int A[x];
because its size is not a compile-time constant.
However variable length arrays are not a standard C++ feature though some compilers have their own language extensions that support variable length arrays,
It is better to use the class template std::vector.
Another problem is that it seems you are trying to use the bubble sort method to sort the array. But this method requires two loops.
Here is a demonstration program that shows how the bubble sort algorithm can be implemented.
#include <iostream>
int main()
{
int a[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
const size_t N = sizeof( a ) / sizeof( *a );
for (const auto &item : a)
{
std::cout << item << ' ';
}
std::cout << '\n';
for (size_t last = N, sorted = N; not ( last < 2 ); last = sorted)
{
for (size_t i = sorted = 1; i < last; i++)
{
if (a[i] < a[i - 1])
{
// std::swap( a[i-1], a[i] );
int tmp = a[i - 1];
a[i - 1] = a[i];
a[i] = tmp;
sorted = i;
}
}
}
for (const auto &item : a)
{
std::cout << item << ' ';
}
std::cout << '\n';
}
The program output is
9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9
Let us try the following method:
find the largest element in the array and move it to the end, by swapping with the last element;
repeat with the array but the last element, and so on.
To find the largest element in A[0..m-1], scan the array and keep an index to the largest so far, let l. This index can be initialized to 0.
// Move the largest to the end
int l= 0;
for (int i= 1; i < m; i++)
{
if (A[i] > A[l]) l= i;
}
// A[l] is the largest in A[0..m-1]
Swap(A[l], A[m-1]);
// A[m-1] is the largest in A[0..m-1]
To sort, repeat with decreasing m. You can stop when the subarray just holds one element:
// Sort
for (int m= n-1; m > 1; m--)
{
// Move the largest to the end
....
}
Writing the Swap operation and assembling the whole code is your task. Also check
correctness of the Move for the limit cases m= 0, 1, 2.
correctness of the Sort for the limit cases n= 1, 2, 3.
how you could instrument the code to verify that the Move does its job.
how you could instrument the code to verify that the Sort does its job.
what happens in case of equal keys.
Your code can be fixed a bit to make it working.
Just replace if (count <= (x - 1)) with while (count < (x - 1)) and also set count = 0; at start of loop, plus replace else if (A[i] < A[i + 1]) with just else. And your code becomes working!
Necessary fixes I did in code below. Also I did formatting (indents and spaces) to make code looks nicer. Rest remains same.
As I see you have a kind of Bubble Sort.
Try it online!
#include <iostream>
using namespace std;
int main() {
int x;
cout << "Enter no. of elements" << endl;
cin >> x;
int A[x];
for (int i = 0; i < x; i++) {
cin >> A[i];
}
for (int i = 0; i < x; i++)
cout << A[i] << ",";
int count = 0;
while (count < (x - 1)) {
count = 0;
for (int i = 0; i < (x - 1); i++) {
if (A[i] > A[i + 1]) {
int a;
a = A[i];
A[i] = A[(i + 1)];
A[i + 1] = a;
} else
count++;
}
}
cout << "Sorted array:";
for (int i = 0; i < x; i++)
cout << A[i] << ",";
return 0;
}
Input:
10
7 3 5 9 1 8 6 0 2 4
Output:
7,3,5,9,1,8,6,0,2,4,Sorted array:0,1,2,3,4,5,6,7,8,9,
If you are taking the size of array as input from user you have to create your array dynamically in c++ like
int *array=new int(x)
and after taking the inputs of the elements just run a nested loop from 0 to size and
the inner loop from 0 to size-1 and check if(A[i]>A[i+1]) if true then swap the values else continue

Recursive function to find if a subset of the numbers in the input array can be added up to a give target value

I am writing a recursive function to find if a subset of the numbers in the input array can be added up to a give target value. However, the result is wrong.
*a is the array given
n is the length of a[]
The solution is stored in array c[]
k is the number of elements in c[]
target is the target number
i is an index, which is 0 when beginning
bool findNumTargetSum(int *a, int n, int *c, int &k, int target, int i)
{
// Recursive function to find if a subset of the numbers in the input array
// can be added up to a give target value.
// Required input parameters include
// - input array of integers and the length of the array
// - array for storing the solution, and length of the result array passed by reference
// - other parameters for the control of recursion
// The input array is sorted in ascending order. This property may help to
// improve the computation efficiency to some exend.
// The function returns ture if a solution is found; otherwise returns false.
c[k] = a[i];
int total = 0;
for (int j = 0; j < k + 1; j++) {
total += c[j];
}
if (i >= n)
return false;
if (total == target) {
k += 1;
return true;
}
else if (total < target) {
i += 1;
k += 1;
findNumTargetSum(a, n, c, k, target, i);
}
else if (total > target) {
k -= 1;
if (k < 0)
return false;
findNumTargetSum(a, n, c, k, target, i);
}
}
void part_2()
{
// Test data: the array is sorted in ascending order.
int a[] = { 8, 12, 20, 35, 36, 41, 55, 64, 72, 81 };
int n = 10;
int c[10]; // array for storing the solution
int k = 0; // k = number of elements in c[]
cout << "\n-----------------------------------------------------------\n";
cout << "Part-2: recursion and backtracking\n";
cout << "Numbers in input list:\n";
printArray(a, n);
int total = sum(a, n);
cout << "sum of the numbers in input list = " << total << endl << endl;
bool success = false;
for (int i = 1; i < 7; i++) // try 6 test cases
{
int target = total * i / 7 + 2;
k = 0;
success = findNumTargetSum(a, n, c, k, target, 0);
if (success)
{
cout << "Numbers in input list that add up to " << target << " :\n";
printArray(c, k);
}
else
cout << "DO NOT find subset of numbers in input list that add up to " << target << endl << endl;
}
}
You have to update your function findNumTargetSum. Logic was incorrect. Logic should be like: adding current element a[i] to the subset c or not adding current element a[i] to the subset c. Code is given below:
bool findNumTargetSum(int *a, int n, int *c, int &k, int target, int i)
{
// Recursive function to find if a subset of the numbers in the input array
// can be added up to a give target value.
// Required input parameters include
// - input array of integers and the length of the array
// - array for storing the solution, and length of the result array passed by reference
// - other parameters for the control of recursion
// The input array is sorted in ascending order. This property may help to
// improve the computation efficiency to some exend.
// The function returns ture if a solution is found; otherwise returns false.
if (i >= n)
return false;
// not taking ar[i] element
bool found = findNumTargetSum(a, n, c, k, target, i+1);
if(found == true) {
return found;
}
// taking ar[i] element
c[k] = a[i];
int total = 0;
for (int j = 0; j < k + 1; j++) {
total += c[j];
}
if (total == target) {
k++;
return true;
}
if (total < target) {
k++;
bool found = findNumTargetSum(a, n, c, k, target, i+1);
if(found == true)
return found;
k--;
}
return false;
}

Find Maximum Strength given number of elements to be skipped on left and right.Please Tell me why my code gives wrong output for certain test cases?

Given an array "s" of "n" items, you have for each item an left value "L[i]" and right value "R[i]" and its strength "S[i]",if you pick an element you can not pick L[i] elements on immediate left of it and R[i] on immediate right of it, find the maximum strength possible.
Example input:
5 //n
1 3 7 3 7 //strength
0 0 2 2 2 //Left Value
3 0 1 0 0 //Right Value
Output:
10
Code:
#include < bits / stdc++.h >
using namespace std;
unsigned long int getMax(int n, int * s, int * l, int * r) {
unsigned long int dyn[n + 1] = {};
dyn[1] = s[1];
for (int i = 2; i <= n; i++) {
dyn[i] = dyn[i - 1];
unsigned long int onInc = s[i];
int left = i - l[i] - 1;
if (left >= 1) {
unsigned int k = left;
while ((k > 0) && ((r[k] + k) >= i)) {
k--;
}
if (k != 0) {
if ((dyn[k] + s[i]) > dyn[i]) {
onInc = dyn[k] + s[i];
}
}
}
dyn[i] = (dyn[i] > onInc) ? dyn[i] : onInc;
}
return dyn[n];
}
int main() {
int n;
cin >> n;
int s[n + 1] = {}, l[n + 1] = {}, r[n + 1] = {};
for (int i = 1; i <= n; i++) {
cin >> s[i];
}
for (int i = 1; i <= n; i++) {
cin >> l[i];
}
for (int i = 1; i <= n; i++) {
cin >> r[i];
}
cout << getMax(n, s, l, r) << endl;
return 0;
}
Problem in your approach:
In your DP table, the information you are storing is about maximum possible so far. The information regarding whether the ith index has been considered is lost. You can consider taking strength at current index to extend previous indices only if any of the previously seen indices is either not in range or it is in range and has not been considered.
Solution:
Reconfigure your DP recurrence. Let DP[i] denote the maximum answer if ith index was considered. Now you will only need to extend those that satisfy range condition. The answer would be maximum value of all DP indices.
Code:
vector<long> DP(n,0);
DP[0]=strength[0]; // base condition
for(int i = 1; i < n ; i++){
DP[i] = strength[i];
for(int j = 0; j < i ; j++){
if(j >= (i-l[i]) || i <= (j+r[j])){ // can't extend
}
else{
DP[i]=max(DP[i],strength[i]+DP[j]); // extend to maximize result
}
}
}
long ans=*max_element(DP.begin(),DP.end());
Time Complexity: O(n^2)
Possible Optimizations:
There are better ways to calculate maximum values which you might want to look into. You can start by looking into Segment tree and Binary Indexed Trees.

least frequent common number from a int array

I have to find least common number from an int array , I have written code but it is not working properly ,
Here is my logic,
1. sort the array
2. get min common counter updated
3. get if all are unique
and the code below,
static int min_loc ; //minimum value location
static int min_cnt ;
int all_uniqFlag = true;
void leastCommon(int data[],int n)
{
int rcount = 0; //Repeated number counter
int mcount = n; // minimum repetetion counter;
// The array is already sorted we need to only find the least common value.
for(int i = 0 ; i < n-1 ; i++)
{
//Case A : 1 1 2 2 2 3 3 3 3 4 5 5 5 5 : result should be 4
//Case B : 1 2 3 4 5 6 7 (All unique number and common values so all values should be printed
// and )
//Case C : 1 1 2 2 3 3 4 4 (all numbers have same frequency so need to display all )
cout << "data[i] : " << data[i] << " data[i+1] : " << data[i+1] << "i = " << i << endl;
if(data[i] != data[i+1])
{
//mcount = 0;
//min_loc = i;
//return;
}
if(data[i] == data[i+1])
{
all_uniqFlag = false;
rcount++;
}
else if(rcount < mcount)
{
mcount = rcount;
min_loc = i ;//data[i];
}
}
min_cnt = mcount;
}
As mentioned in the comment only Case B works and Case A and C is not working could you help me fix the issue ?
scan through the list
compare each element in the list with the last element in the out array
If the element matches, then increment its count by 1
If the element doesn't match then add the new element into out
array and increment index by 1
Once the scan is done, the out array will have all the distinct elementsout[][0] and their frequencies out[][1]
Scan through the frequency list (out[][1]) to find the lowest frequency
Finally do another scan through the element list out[][0] and print elements whose frequency matches with the lowest frequency
.
#include<stdio.h>
#include<stdlib.h>
#define N 8
int main()
{
//int data[N]={1,2,3,4,5,6,7};
int data[N]={1,1,2,2,3,3,4,4};
//int data[N]={1,1,2,2,2,3,3,3,3,4,5,5,5,5};
int out[N][2];
int i=0,index=0;
for(i=0;i<N;i++)
{
out[i][0]=0;
out[i][1]=0;
}
out[0][0] = data[0];
out[0][1]=1;
for(i=1;i<N;i++)
{
if(data[i] != out[index][0])
{
index++;
out[index][0] = data[i];
out[index][1] = 1;
}
else
{
out[index][1]++;
}
}
int min=65536;
for(i=0;i<N;i++)
{
if(out[i][1] == 0)
{
break;
}
if(out[i][1] < min)
{
min = out[i][1];
}
}
for(i=0;i<N;i++)
{
if(out[i][1] == min)
{
printf("%d\t",out[i][0]);
}
}
printf("\n");
}
You can use a map for this:
#include <string>
#include <map>
#include <iostream>
typedef std::map<int, int> Counter;
void leastCommon(int data[],int n) {
Counter counter;
int min = n;
for (int i = 0; i < n; i++)
counter[data[i]]++;
for (Counter::iterator it = counter.begin(); it != counter.end(); it++) {
if (min > it->second) min = it->second;
}
for (int i = 0; i < n; i++) {
if (counter[data[i]] == min) {
std::cout << data[i] << std::endl;
counter[data[i]]++;
}
}
}
int main() {
int data[] = {1, 1,3,4,4,2,4,3,2};
leastCommon(data, 9);
return 0;
}
Approach is-
select 1st element from the sorted array, and while consecutive elements to it are same, store them in output[] until the loop breaks
store the frequency of element in leastFrequency
select next element, check with its consecutive ones and store them in same output[] until the loop breaks
check frequency of this with the leastFrequency
if same, do nothing (let these be added in the output[])
if less, clear output[] and store the element same no. of times
if more, change the effective output[] length to previous length before iterating for this element
similarly iterate for all distinct elements and finally get the result from output[] from 0 to effective length
void leastCommon(int data[], int len) {
if ( len > 0) {
int output[] = new int[len];
int outlen = 0; // stores the size of useful-output array
int leastFrequency = len; // stores the lowest frequency of elements
int i=0;
int now = data[i];
while (i < len) {
int num = now;
int count = 0;
do {
output[outlen] = now;
outlen++;
count++;
if((++i == len)){
break;
}
now = data[i];
} while (num == now); // while now and next are same it adds them to output[]
if (i - count == 0) { // avoids copy of same values to output[] for 1st iteration
leastFrequency = count;
} else if (count < leastFrequency) { // if count for the element is less than the current minimum then re-creates the output[]
leastFrequency = count;
output = new int[len];
outlen = 0;
for (; outlen < leastFrequency; outlen++) {
output[outlen] = num; // populates the output[] with lower frequent element, to its count
}
} else if (count > leastFrequency) {
outlen -= count; // marks outlen to its same frequent numbers, i.e., discarding higher frequency values from output[]
}
}
//for(int j = 0; j < outlen; j++) {
// print output[] to console
//}
}
}
Plz suggest for improvements.

Maximum sum from two sorted arrays

You are given two sorted integer arrays, which have some common integers. Any common integer between the two sequences constitute an intersection point.
You can start traversing from any of the array and switch to the other array or continue with the same array at an intersection point.
The objective is to find a path that produces the maximum sum of the data.
Take for example the following two sequences where intersection points are printed in bold:
First = 3 5 7 9 20 25 30 40 55 56 57 60 62
Second = 1 4 7 11 14 25 44 47 55 57 100
In the above example, the largest possible sum is 450 which is the result of adding
3, 5, 7, 9, 20, 25, 44, 47, 55, 56, 57, 60, and 62
I wrote the following code but it is not compiling, please help:
/* M: size of the array a
N: size of the array b
*/
int i,j,sum1,sum2,sum,m_i,n_j = 0;
void printIntersectionElements(int *a,int M, int *b, int N) {
if (M == 0)
return (b);
if (N ==0)
return(a);
while( i < M && j < N ){
sum1 = sum1 +a[i];
sum2 = sum2 + b[j];
if(a[i] == b[j]) { // found a common element.
if(sum1>= sum2){
for(;m_i<= i; m_i++)
cout<< a[m_i];
sum = sum +sum1;
m_i = i+1;
}
else {
for(;n_j<= j; n_j++)
cout<< b[n_j];
sum = sum+sum2;
n_j = j+1;
}
sum1 = sum2 = 0;
}
i++;
j++;
}
}
You are trying to return a result from a function that is declared with a void return type. That's not valid C++, which is why you are getting a compiler error.
There may be other errors, too. Read the error messages: they will tell you exactly what and where the problem is.
This question can be solved in O(m+n).
You can maintain a cumulative sum array for both arrays.
First find the intersection point in O(m+n).
Then check which array has maximum sum between two intersection point.
Add them in a variable.
Here is the code.
#include <iostream>
#include <vector>
#include <cstdio>
using namespace std;
void print(int a[], int x, int y) {
for(int i = x; i <= y; i++) {
printf("%d ", a[i]);
}
}
int main ()
{
int i, j, x, y, n, m;
int a0[100], a1[100], sum1[100], sum0[100];
vector <int> v0, v1;
cout << "Enter the value of n and m:\n";
cin >> n >> m;
scanf("%d", &a0[0]);
sum0[0] = a0[0];
for(i = 1; i < n; i++) {
scanf("%d", &a0[i]);
sum0[i] = a0[i] + sum0[i-1]; //cumulative sum for first array
}
scanf("%d", &a1[0]);
sum1[0] = a1[0];
for(i = 1; i < m; i++) {
scanf("%d", &a1[i]);
sum1[i] += a1[i] + sum1[i-1]; //cumulative sum for second array
}
i = 0;
j = 0;
while(i < n && j < m) { //loop breaks when either one of the array ends
if(a0[i] == a1[j]) { //if there is a intersection
v0.push_back(i); //store index of both the arrays
v1.push_back(j);
i++;
j++;
}
else if(a0[i] > a1[j]) { //else increase the index of array
j++; //containing small number
}
else if(a0[i] < a1[j]) {
i++;
}
}
i = 0;
j = 0;
int sum = 0;
while(i < v0.size()) {
x = v0[i];
y = v1[i];
if(i == 0) {
if(sum0[x] > sum1[y]) { //check which array has greater sum
sum += sum0[x]; //first intersection
print(a0, 0, x);
}
else {
sum += sum1[y];
print(a1, 0, y);
}
i++;
}
else {
if(sum0[x]-sum0[v0[i-1]] > sum1[y]-sum1[v1[i-1]]) {
sum += sum0[x]-sum0[v0[i-1]]; //checks which array has greater sum
print(a0, v0[i-1]+1, x); //between two intersectio
}
else {
sum += sum1[y]-sum1[v1[i-1]];
print(a1, v1[i-1]+1, y);
}
i++;
}
}
if(sum0[n-1]-sum0[x] > sum1[m-1]-sum1[y]) {
sum += sum0[n-1]-sum0[x]; //check which array has greater sum
print(a0, x+1, n-1); //at last intersection
}
else {
sum += sum1[m-1]-sum1[y];
print(a1, y+1, m-1);
}
cout << endl << "sum = " << sum << endl;
return 0;
}
Your code has several problems:
First of it doesn't compile, since your function is declared to return void, but you try to return int*. Change your return statements to return;
However even if you fix that your function doesn't solve the problem you have described.
Your summation stops when you reach the end of the smaller of the two arrays. However from your example you should actually go till the end of both arrays.
Furthermore you only detect intersection points when both arrays contain the same number at the same position, however from your text I would think that you should detect points as intersections, even if they are at different positions in the array (I might be wrong though, depending on the exact formulation of your exercise). To do that the easiest way would be to handle only the smaller value of a[i] and b[j] each iteration (and increase only either i or j (or both if its an intersection).