min average of mutiple array segments - c++

Given an array A I want to find the first index of a segment where the average of the chosen segment is the minimum among other segments.
Example: A = {1, 1, 3, 4, 5, 6, 7}
segment (1,2) = {1,1} ==> avg = 1+1/2 = 1
segment (1,3) = {1,1,3} ==> avg = 1+1+3/3 = 1.6
etc..
________________________________________________
input: {1, 1, 3, 4, 5, 6, 7}
output: 1
Explanation: the min avg is 1 hence the output should be the first index of that segment (1,2) which is: 1 in this case.
My current code looks like this:
int getIndex(vector<int> A)
{
if (A.size() <= 2) return 0; /*if array is a single segment then index:0 is the answer.*/
vector<int> psums; psums.push_back(A[0]);
for(size_t i =1; i< A.size(); i++)
{
psums.push_back(psums[i-1] + A[i]);
}
float min = 1111111111; /*assuming this is a max possible numb*/
int index;
float avg;
for(size_t i =1; i< psums.size(); i++)
{
for(size_t j = 0; j < i; j++)
{
avg = (float)((psums[i] - psums[j]) / (i-j+1));
if (min > std::min(min, avg))
{
min = std::min(min, avg);
index = j;
}
}
}
return index;
}
This code returns incorrect value. Thoughts?

Ok, I have some time, so here is the code you are hopefully looking for (and hopefully it compiles as well -- I have no chance to test that before I posted it, so give me a few minutes to check afterwards -- ok, compiles now with gcc-4.7.2):
#include<vector>
#include<tuple>
#include<functional>
#include<algorithm>
#include<iostream>
#include <numeric>
size_t getIndex(const std::vector<int>& A) //pass by const ref instead of by value!
{
size_t n=A.size();
//define vector to store the averages and bounds
std::vector<std::tuple<size_t, size_t, double> > store;
for(size_t iend=0;iend<n;++iend)
for(size_t ibegin=0;ibegin<iend;++ibegin) //changed from <= to < as segments need to have length >=2
{
//compute average: sum all elements from ibegin to iend to 0.0, cast to double and divide by the number of elements
double average=static_cast<double>(std::accumulate(A.begin()+ibegin, A.begin()+iend,0.0))/(iend-ibegin+1);
//store the result with bounds
store.push_back(std::make_tuple(ibegin,iend,average));
}
//define lambda which compares the tuple according to the third component
auto compare_third_element=[](const std::tuple<size_t,size_t,double> &t1, const std::tuple<size_t,size_t,double> &t2){return std::get<2>(t1)<std::get<2>(t2);};
//now find the iterator to the minimum element
auto it=std::min_element(store.begin(),store.end(),compare_third_element);
//print range
//std::cout<<"("<<std::get<0>(*it)<<","<<std::get<1>(*it)<<")"<<std::endl;
return std::get<0>(*it);
}
int main()
{
std::vector<int> A={1,1,2,3,4,5,6,7};
std::cout << getIndex(A);
return 0;
}
Caution: there might be more than a single segment which yields the minimum average. For the example above, the function prints the segment (0,0) on the screen, since it contains the minimum element 1. If you want to obtain the range you are looking for, either use std::nth_element to access the next entries, or change the comparison function (e.g. give longer tuples a higher priority).

Both (psums[i] - psums[j]) and (i-j+1) are integers. The division between them is the so called, incomplete division thus you get just the whole part, of the result. Cast one of the elements to float or double, like this:
(float)(psums[i] - psums[j])/(i-j+1)
The type of division in a/b depend on the type of a and b not the variable you put the result in!
Note: std::min(min, avg) is not required, instead of that just use: avg
Edit: psum[i]-psum[j]=A[i]+A[i-1]+...+A[j+1] becouse psum[i]=A[0]+A[1]+A[2]+..+A[i] so
the avg-line should look like this:
avg=(float)(psums[i] - psums[j] + A[j])/(i-j+1)

Related

Duplicates in Array

Given an integer array nums sorted in non-decreasing order, remove some duplicates in-place such that each unique element appears at most twice. The relative order of the elements should be kept the same.
Since it is impossible to change the length of the array in some languages, you must instead have the result be placed in the first part of the array nums. More formally, if there are k elements after removing the duplicates, then the first k elements of nums should hold the final result. It does not matter what you leave beyond the first k elements.
Return k after placing the final result in the first k slots of nums.
What is wrong with my code ??
map<int,int> m;
for(int i = 0 ; i < nums.size() ; i++){
m[nums[i]]++;
if(m[nums[i]] > 2)nums.erase(nums.begin() + i);
}
return nums.size();
From the given text, we can derive the following requirements
Given an integer array nums
sorted in non-decreasing order,
remove some duplicates in-place such that each unique element appears at most twice.
The relative order of the elements should be kept the same.
Since it is impossible to change the length of the array in some languages, you must instead have the result be placed in the first part of the array nums.
More formally, if there are k elements after removing the duplicates, then the first k elements of nums should hold the final result.
It does not matter what you leave beyond the first k elements
Return k after placing the final result in the first k slots of nums.
So, after elicitating the requirements, we know that we have a fixed size array, presumably (because of the simplicity of the task) a C-Style array or a C++ std::array. Because of the shown source code, we assume a std::array.
It will be sorted in increasing order. Their shall be an in-place removal of elements. So, no additional variables. The rest of the requirements already shows the solution.
--> If we find duplicates (more than 2) we will shift the rest of the values one to the left and overwrite one of the duplicates. Then the logical number of elements in the array will be one less. So, the loop must run one step less.
This ends up in a rather simple program:
#include <iostream>
#include <array>
// Array with some test values
constexpr int ArraySize = 25;
std::array<int, ArraySize> nums{ 1,2,2,2,3,3,3,4,4,4,4,4,6,5,5,5,5,5,6,6,6,6,6,6,9,9 };
int main() {
// Currentlogical end of the data in the array. In the beginning, last value in the array
size_t endIndex = nums.size();
// Check allelments from left to tright
for (size_t index = 0; index < endIndex;) {
// Check, if 3 elements are same
if ((index < (endIndex -2)) and nums[index] == nums[index + 1] and nums[index + 1] == nums[index + 2]) {
// Yes, found 3 same elements. We willdelete one, so the endIndex needs to be decremented
--endIndex;
// Now hsift all array elements one to the left
for (size_t shiftIndex = index + 2; shiftIndex < endIndex; ++shiftIndex)
nums[shiftIndex] = nums[shiftIndex + 1];
}
else ++index;
}
// SHow result
std::cout << endIndex << '\n';
}
I can offer the solution of your problem.
#include <iostream>
#include <vector>
#include <set>
using namespace std;
void showContentSet(set<int>& input)
{
for(auto iterator=input.begin(); iterator!=input.end(); ++iterator)
{
cout<<*iterator<<", ";
}
return;
}
void showContentVector(vector<int>& input)
{
for(int i=0; i<input.size(); ++i)
{
cout<<input[i]<<", ";
}
return;
}
void solve()
{
vector<int> numbers={1, 2, 1, 3, 4, 5, 7, 5, 8, 5, 9, 5};
set<int> indicesToDelete;
for(int i=0; i<numbers.size(); ++i)
{
int count=0;
for(int j=0; j<numbers.size(); ++j)
{
if(numbers[i]==numbers[j])
{
++count;
if(count>2)
{
indicesToDelete.insert(j);
}
}
}
}
cout<<"indicesToDelete <- ";
showContentSet(indicesToDelete);
int newOrder=0;
cout<<endl<<"Before, numbers <- ";
showContentVector(numbers);
for(auto iterator=indicesToDelete.begin(); iterator!=indicesToDelete.end(); ++iterator)
{
numbers.erase(numbers.begin()+(*iterator-newOrder));
++newOrder;
}
cout<<endl<<"After, numbers <- ";
showContentVector(numbers);
cout<<endl;
return;
}
int main()
{
solve();
return 0;
}
Here is the result:
indicesToDelete <- 9, 11,
Before, numbers <- 1, 2, 1, 3, 4, 5, 7, 5, 8, 5, 9, 5,
After, numbers <- 1, 2, 1, 3, 4, 5, 7, 5, 8, 9,
I suggest using a frequency array.
frequency array works, That you count how many duplicates of each number while inputting, It's stored usually in an array called freq, Also can be stored in a map<int, int> or unordered_map<int, int>.
And because of input is in non-decreasing order, outputting this solution will be easy.
Note: this solution won't work if input numbers is bigger than 10^5
Solution:
#include <iostream>
const int N = 1e5 + 1; // Maximum size of input array
int n;
int nums[N], freq[N];
int main()
{
// Input
std::cin >> n;
for (int i = 0; i < n; i++)
{
std::cin >> nums[i];
freq[nums[i]]++;
}
// Outputting numbers, Using frequency array of it
for (int i = 0; i < N; i++)
{
if (freq[i] >= 1)
std::cout << i << ' ';
if (freq[i] >= 2)
std::cout << i << ' ';
}
return 0;
}
This is basically a conditional copy operation. Copy the entire range, but skip elements that have been copied twice already.
The following code makes exactly one pass over the entire range. More importantly it avoids erase operations, which will repeatedly shift all elements to the left.
vector<int> nums; // must be sorted already
if (nums.size()<=1)
return; // already done
// basically you copy all elements inside the vector
// but copy them only if the requirement has been met.
// `in` is the source iterator. It increments every time.
// `out` is the destination iterator. It increments only
// after a copy.
auto in=nums.begin();
auto out=nums.begin();
// current is the current 'int' value
int current=*in;
// `count` counts the repeat count of the current value
int count=0;
while (in!=nums.end()) {
if (*in==current) {
// The current value repeats itself, so increment
// the count value
++count;
} else {
// No, this is a new value.
// initialise current and count
current=*in;
count=1;
}
if (count<=2) {
// only if at most two elements of the same value
// copy the current value to `out`
*out=current;
++out;
}
// try next element
++in;
}
// out points to the last valid element + 1

I don't understand how to calculate the sum of the sums of every possible sub-array using nested loops

The question the homework asks is:
Write a function, secondSmallestSum that when passed an int array of any length greater than 1 will calculate the sum of the elements of every possible sub-array and then return the second smallest sum found. It is possible for the smallest and second smallest sums to have the same value.
Sub-arrays are contiguous ranges of elements within an array. For example, if you have an array of length 4, {1,2,3,4}, then the complete set of sub-arrays is:
{1}, {1,2}, {1,2,3}, {1,2,3,4}, {2}, {2,3}, {2,3,4}, {3}, {3,4}, {4}
the sum of each sub-array is then:
1, 3, 6, 10, 2, 5, 9, 3, 7, 4
The main function for this problem must call your readNumbers function, then pass the new array to your secondSmallestSum function, display the second smallest sum found and finally delete the array.
My code so far prints numbers that the user inputs.
#include <iostream>
int *readNumbers(int n)
{
int *a = new int[n];
for (int i = 0; i < n; i++){
std::cin >> a[i];
}
return a;
}
int main()
{
int length = 5;
int *ptr = readNumbers(length);
printNumbers(ptr, length);
return 0;
}
I expect this array (AN EXAMPLE) {4,0,9} to output the sub-arrays of {4}, {4,0}, {4,0,9}, {0}, {0,9} and {9}. The sums for each array would output as: 4,4,13,0,9 and 9. The total sum is 39.
With a first look, it definitely occurs that let's run a double loop till the end of the array for each element and find the sums of element along with it.
That gives you the complexity of O(n2) roughly speaking
Now, do you want to add 3+4 for the 2nd iteration (when you're looping for 2) while you have already calculated for 1st iteration? I wouldn't...
So instead I would save those incremental additions like this:
for (int *i = ptr + l - 2; i >= ptr; i--) {
*i = *i + *(i+1);
}
This would give me {1,2,3,4} -> {10,9,7,4}
Now run the double loop:
for (int *i = ptr; i < ptr + l; i++) {
cout << *i << " ";
for (int *j = i+1; j < ptr + l; j++) {
cout << *i - *j << " ";
}
}
Now you have all the sums. and you can do all the required operations. For your example the second smallest: You can add the following code in that double loop
if (secondsmallest >= x) {
if (smallest >= x) {
secondsmallest = smallest;
smallest = x;
}else{
secondsmallest = x;
}
}
Find the correct place to add it and replace x with suitable notation :)
Cheers...
If you find this answer helpful - consider upvoting :)

C++ Returning a random value from a subset of a Vector

Can someone help me figure out a way to return a value from a vector that has N values in sequential order. And the return value has to be in the upper half of the set.
For example,
If have a vector containing the following integers:
{1, 2, 3. 4, 5, 6}
Return a random integer from {4,5,6}. I'm so stumped!
The end objective is to create a "weighted die" where the value of a roll returns a higher value. My solution is the aforementioned use of vectors.
void LoadedDie::loadedRoll(int numberOfSides)
{
vector<int> diceSides(numberOfSides+1);
for (int index = 1; index < numberOfSides+1; index ++)
{
diceSides[index]=index;
}
for (int index=1; index < numberOfSides+1; index ++)
{
cout << diceSides[index];
}
}
So I have my dice created at this point, but can't figure out how to get a random value from the second half of the vector.
You can generate a random integer within a range, and use the subscript operator to access your vector.
int max = yourVector.size()-1; //-1 to stay in range
int min = max/2;
int randIndex = min + (rand() % (int)(max - min + 1));
yourVector[randIndex]; // this is a random int in your vector
This is slightly biased so you can use the following for an unbaised one:
#include <random>
int max = yourVector.size()-1; //-1 to stay in range
int min = max/2;
std::random_device seed; // initialise a seed once
std::mt19937 numberGen(seed());
std::uniform_int_distribution<int> gen(min,max);
int randIndex = gen(numberGen);
yourVector[randIndex]; // this is a random int in your vector
EDIT
As suggested you can use the .at() function in std::vector to be safe:
yourVector.at(randIndex);

Find order of an array using minimum memory and time

Let's say i have an array of 5 elements. My program knows it's always 5 elements and when sorted it's always 1,2,3,4,5 only.
As per permutations formula i.e n!/(n-r)! we can order it in 120 ways.
In C++ using std::next_permutation I can generate all those 120 orders.
Now, my program/routine accepts an input argument as a number in the range of 1 to 120 and gives the specific order of an array as output.
This works fine for small array sizes as i can repeat std::next_permutation until that matches input parameter.
The real problem is, How can i do it in less time if my array has 25 elements or more? For 25 elements, the number of possible orders are : 15511210043330985984000000.
Is there a technique that I can easily find the order of numbers using a given number as input?
Thanks in advance :)
This is an example c++ implementation of the algorithm mentioned in this link:
#include <vector>
#define ull unsigned long long
ull factorial(int n) {
ull fac = 1;
for (int i = 2; i <= n; i++)
fac *= i;
return fac;
}
std::vector<int> findPermutation(int len, long idx) {
std::vector<int> original = std::vector<int>(len);
std::vector<int> permutation = std::vector<int>();
for (int i = 0; i < len; i++) {
original[i] = i;
}
ull currIdx = idx;
ull fac = factorial(len);
while (original.size() > 0) {
fac /= original.size();
int next = (currIdx - 1) / fac;
permutation.push_back(original[next]);
original.erase(original.begin() + next);
currIdx -= fac * next;
}
return permutation;
}
The findPermutation function accepts the length of the original string and the index of the required permutation, and returns an array that represents that permutation. For example, [0, 1, 2, 3, 4] is the first permutation of any string with length 5, and [4, 3, 2, 1, 0] is the last (120th) permutation.
I have had a similar problem where I was storing lots of row in a Gtk TreeView and did not want to go over all of them every time I want to access a row by its position and not by its reference.
So, I created a map of the positions of the row so I could easily identify them by the parameter I needed.
So, my suggestion to this is you go over all permutations once and map every std::permutation in an array (I used a std::vector), so you can access it by myVector[permutation_id].
Here is my way I have done the mapping:
vector<int> FILECHOOSER_MAP;
void updateFileChooserMap() {
vector<int> map;
TreeModel::Children children = getInterface().getFileChooserModel()->children();
int i = 0;
for(TreeModel::Children::iterator iter = children.begin(); iter != children.end(); iter++) {
i++;
TreeModel::Row row = *iter;
int id = row[getInterface().getFileChooserColumns().id];
if( id >= map.size()) {
for(int x = map.size(); x <= id; x++) {
map.push_back(-1);
}
}
map[id] = i;
}
FILECHOOSER_MAP = map;
}
So in your case you would just iterate over the permutations like this and you can map them in a way that allows you accesing them by their id.
I hope this helps you :D
regards, tagelicht

Non-empty zero-indexed vector V of N integers, returns the minimal positive integer (greater than 0) that does not occur in V

Please help me in optimizing the code. Seems to be working fine for most of the result set, but performance wise its seems to be slow. How can I further optimize the code.
Assuming vector is v{1,3,6,4,1,2};
int solution(vector<int> &v) {
std::vector<int> v2,v3;
sort(begin(v),end(v));
v.erase(unique(begin(v),end(v)),end(v));
std::pair<std::vector<int>::iterator,std::vector<int>::iterator> p1= std::minmax_element(begin(v),end(v));
int last_ = *p1.second;
for(int i=0; i < last_; i++)
v2.push_back(i);
if(v2.size() ==0)
return 1;
set_symmetric_difference(begin(v),end(v),begin(v2),end(v2),std::back_inserter(v3));
auto up=upper_bound(begin(v3),end(v3),0);
return *up;
}
First, you code modifies the original vector which may or not be desirable.
Next as usual, think algorithm before code optimization. Once vector is sorted, find first positive number. If it is not 1, 1 is the solution.
If you have found number 1 in the sorted vector, just move forward:
if next number is number + 1, just iterate
if next number is > number + 1, the solution is number + 1
if you reach end of vector, the solution is last number in vector + 1
Cost: cost of the sort plus N in worst case, average N/2
EDIT: the following code allows to compute the answer in linear time, as opposed algorithms involving sorting. First notice that the answer is less than or equal N+1, where N is a size of V.
So let's create a vector of length N+1 vector<int> count(N+1), and iterate through all values in V, so for v in V such that v<N+1 we increase count[v]++. Finally go through all values in count and return first non zero index greater than 0. If all are more than zero, return N+1.
int solution(vector<int> &V){
int N = V.size();
vector<int> count(N + 1, 0);
for(auto i = V.begin(); i != V.end(); i++){
If (*i <= N) count[*i]++;
}
//now just find minimum value which doesn't occur in V
int answer = 0;
for(int i = 1; i < N + 1; i++){
answer++;
if (count[i] == 0){
break;
}
}
return answer;
}