There are 100 numbers present in an array and I need to find out the average of top 5 highest numbers among them.
Also in the same way the average of top 5 lowest numbers among them. How could I go about doing it?
Use Hoare's select algorithm (or the median of medians, if you need to be absolutely certain of the computational complexity), then add the top partition (and divide by its size to get the average).
This is somewhat faster than the obvious method of sorting instead of partitioning -- partitioning is (O(N)) where sorting is O(N log(N) ).
Edit: In C++, for real code (i.e., anything except homework where part of the requirement is to do the task entirely on your own) you can use std::nth_element to partition the input into the top 5 and everything else.
Edit2: Here's another quick demo to complement #Nils', but this one in full C++11 regalia (so to speak):
#include <numeric>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
int main(){
std::vector<int> x {1, 101, 2, 102, 3, 103, 4, 104, 5, 105, 6};
auto pos = x.end() - 5;
std::nth_element(x.begin(), pos, x.end());
auto sum = std::accumulate(pos, x.end(), 0);
auto mean = sum / std::distance(pos, x.end());
std::cout << "sum = " << sum << '\n' << "mean = " << mean << "\n";
return 0;
}
Jerry already explained how it works. I just want to add a practical code-example in c++:
#include <algorithm>
int averageTop5 (int list[100])
{
// move top 5 elements to end of list:
std::nth_element (list, list+95, list+100);
// get average (with overflow handling)
int avg = 0;
int rem = 0;
for (int i=95; i<100; i++)
{
avg += list[i]/5;
rem += list[i]%5;
}
return avg + (rem /5);
}
With Jerrys std::accumulate this becomes a two-liner but may fail with integer overflows:
#include <algorithm>
#include <numeric>
int averageTop5 (int list[100])
{
std::nth_element (list, list+95, list+100);
return std::accumulate (list+95, list+100, 0)/5;
}
Sort them in ascending and add the last five numbers
Copy the first 5 numbers into an array. Determine the position of the smallest element in that array. For each of the 95 numbers in the remainder of the list, compare it with that smallest number. If the new number is larger, then replace it and redetermine the position of the new smallest number in your short list.
At the end, sum your array and divide by 5.
Related
I'm new to C++, and I've been searching all day to find a way to randomly select one of two distinct integers.
Everything I've found so far works only for integers within a range (1-10, etc) rather than for (1 or 3).
For ex. code I've been using elsewhere in the program (for a range of numbers) is
int c;
int Min = 1;
int Max = 3;
c = rand() % (Max + 1 - Min) + Min;
which returns a random integer within the range, rather than one or the other integers given.
First of all you shouldn't use C random in C++. Use C++ random.
The way to chose from a set of elements is to randomly generate an index. You can wrap the logic in a class:
#include <random>
#include <iostream>
#include <vector>
#include <initializer_list>
class Random_choice
{
std::random_device rd_{};
public:
template <class T> auto get_choice(std::initializer_list<T> elements) -> T
{
std::uniform_int_distribution<std::size_t> dist{0, elements.size() - 1};
std::size_t i = dist(rd_);
return *(elements.begin() + i);
}
};
int main()
{
Random_choice rc;
std::cout << rc.get_choice({3, 5}) << std::endl;
}
Or without the abstraction:
#include <random>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> choices = {3, 5};
std::random_device rd;
std::mt19937 e{rd()};
std::uniform_int_distribution<std::size_t> dist{0, choices.size() - 1};
std::size_t i = dist(e);
std::cout << choices[i] << std::endl;
}
Randomly choosing one of two integers, a or b:
c = (rand() % 2) ? a : b
Randomly choosing an integer from a list of integers:
std::vector<int> numbers;
c = numbers.at(rand() % numbers.size());
Randomly choosing an integer from two intervals [a, b) and [c, d):
H = (b-a);
L = (b-a) + (d-c);
k = rand() % L;
c = (k < H) ? (a + k) : (c + (k - H));
In case you do C++11 then you may definitely have look into pseudo-random numer generation, like discrete_distribution and uniform_int_distribution.
Update. Removed the claim that we would choose uniformly from the given set. Since rand() chooses from [0, RAND_MAX], this is only true if the divisor of the above modulo operations divides (RAND_MAX+1). (Which is true for the first example in most implementations where RAND_MAX is 32767 or another power-of-two minus 1.) However, the defect from being uniform is roughly of the order of divisor/RAND_MAX. Nevertheless, C++11 uniform_int_distribution is recommended instead. Thanks, Baum mit Augen.
If you have a range of numbers that you don't want numbersin, then you have two ranges that you do want numbers in.
For example, if your range is 1 to 3 (inclusive) then the two ranges you do want numbers in are -∞ to 0, and 4 to ∞.
Infinity is a little tricky on computers, but can easily be emulated for example by std::numeric_limits to get the min and max for the wanted type.
So in your case you want a random number in the range std::numeric_limits<int>::min() to 0, and 4 to std::numeric_limits<int>::max().
Two get two random numbers from a random choice of either range, first pick (randomly) one range, and get a number from that. Then again (randomly) pick a range and get the second number from that.
I understand that this task can be accomplished using the find_if() STL-Algorithm function as follows:
long long int k; //k = key
scanf("%lld",&k);
auto it = find_if(begin(v),end(v),[k](auto e){return e<k;});
However I require the result to be obtained in logarithmic time. Since the vector is already sorted in descending order I'd like to use a binary search approach.
I understand the STL Algorithm function lower_bound and upper_bound guarantee a logarithmic complexity. However I'm unable to figure out how to use these functions to obtain the first element less than a key as opposed to the first element greater than or equal to a key.
For instance:
Suppose my vector contents are: 21 9 8 7 6 4
My key is : 10
I would want the output to be 9, since its the first element in a left to right scan of the vector that is less than 10.
Any help in this regard would be very helpful!
Thanks
You can use the standard algorithm std::upper_bound with the functional object std::greater.
Here is an example how it can be done.
#include <iostream>
#include <iterator>
#include <functional>
#include <algorithm>
int main()
{
int a[] = { 21, 9, 8, 7, 6, 4 };
int key = 10;
auto it = std::upper_bound(std::begin(a), std::end(a),
key, std::greater<int>());
if (it != std::end(a)) std::cout << *it << std::endl;
}
The program output is
9
I have an array with n elements ,i need to calculate all n*n sum of pair of two elements (array[i]+array[j]).All sums are arranged in ascending order.I need to find Kth sum
for example:
array[] = {3,4,5}
all sums: {(3+3),(3+4),(4+3),(3+5),(5+3),(4+4),(4+5),(5+4),(5+5)}
K = 6
I need to find value for Kth sum ( in this case 6th sum is 4+4 ,i will return 8);
Solution might be very optimal
this is my solution; it isn't optimal:
for(i=0;i<n;i++)
fin>>a[i];
qsort(a, n, sizeof(int), int_cmp);
for(i=0;i<n;i++)
for(j=i;j<n;j++)
{
sum[k]=a[i]+a[j];
if(i!=j)
sum[++k]=a[i]+a[j];
k++;
}
qsort(sum, n*n, sizeof(int), int_cmp);
cout<<sum[nrs-1];
I have seen a similar kind of question from google interview question in that they use two sorted array instead of one but the solution works.One optimization which will work in O(klogk) can be given here.
To find the maximum value in such a case it is necessary to have calculated all the values lesser than it,ie let i,j be the maximum values in your case 5,5 to consider 5,5 to be max it is necessary to have evaluated both 4,5and 5,4.that is i-1,j and i,j-1 So a working code will be to use a heap in c++ it is a priority queue. The code is as follows
#include <iostream>
#include <queue>
using namespace std;
for(i=0;i<n;i++)
fin>>a[i];
qsort(a, n, sizeof(int), int_cmp);
std::priority_queue<int > heap;
heap.add(pair(n-1, n-1)); // biggest pair n=array size
// remove max k-1 times
for (int i = 0; i < k - 1; ++i) {
// get max and remove it from the heap
max = heap.pop();
// add next candidates
heap.push(pair(max.i - 1, max.j));
heap.push(pair(max.i, max.j - 1));
}
// get k-th maximum element
max = heap.pop();
maxVal = a[max.i] + a[max.j];
Now this one is optimized upto O(k.logk) there is another one which gives O(k).You can find it here.Kth sum in O(k)
How can I find the smallest value of each column in the given set of vectors efficiently ?
For example, consider the following program:
#include <iostream>
#include <vector>
#include <iterator>
#include <cstdlib>
using namespace std;
typedef vector<double> v_t;
int main(){
v_t v1,v2,v3;
for (int i = 1; i<10; i++){
v1.push_back(rand()%10);
v2.push_back(rand()%10);
v3.push_back(rand()%10);
}
copy(v1.begin(), v1.end(), ostream_iterator<double>(cout, " "));
cout << endl;
copy(v2.begin(), v2.end(), ostream_iterator<double>(cout, " "));
cout << endl;
copy(v3.begin(), v3.end(), ostream_iterator<double>(cout, " "));
cout << endl;
}
Let the output be
3 5 6 1 0 6 2 8 2
6 3 2 2 9 0 6 7 0
7 5 9 7 3 6 1 9 2
In this program I want to find the smallest value of every column (of the 3 given vectors) and put it into a vector. In this program I want to define a vector v_t vfinal that will have the values :
3 3 2 1 0 0 1 7 0
Is there an efficient way to do this ? I mention efficient because my program may have to find the smallest values among very large number of vectors. Thank you.
Update:
I'm trying to use something like this which I used in one of my previous programs
int count = std::inner_product(A, A+5, B, 0, std::plus<int>(), std::less<int>());
This counts the number of minimum elements between two arrays A and B. Wouldn't it be efficient enough if I could loop through and use similar kind of function to find the minimal values ? I'm not claiming it can be done or not. It's just an idea that may be improved upon but I don't know how.
You can use std::transform for this. The loops are still there, they're just hidden inside the algorithm. Each additional vector to process is a call to std::transform.
This does your example problem in two linear passes.
typedef std::vector<double> v_t;
int main()
{
v_t v1,v2,v3,vfinal(9); // note: vfinal sized to accept results
for (int i = 1; i < 10; ++i) {
v1.push_back(rand() % 10);
v2.push_back(rand() % 10);
v3.push_back(rand() % 10);
}
std::transform(v1.begin(), v1.end(), v2.begin(), vfinal.begin(), std::min<double>);
std::transform(v3.begin(), v3.end(), vfinal.begin(), vfinal.begin(), std::min<double>);
}
Note: this works in MSVC++ 2010. I had to provide a min functor for gcc 4.3.
I think that the lower bound of your problem is O(n*m), where n is the number of vectors and m the elements of each vector.
The trivial algorithm (comparing the elements at the same index of the different vectors) is as efficient as it can be, I think.
The easiest way to implement it would be to put all your vectors in some data structure (a simple C-like array, or maybe a vector of vectors).
The bst way to do this would be to use a vector of vectors, and just simple looping.
void find_mins(const std::vector<std::vector<int> >& inputs, std::vector<int>& outputs)
{
// Assuming that each vector is the same size, resize the output vector to
// change the size of the output vector to hold enough.
output.resize(inputs[0].size());
for (std::size_t i = 0; i < inputs.size(); ++i)
{
int min = inputs[i][0];
for (std::size_t j = 1; j < inputs[i].size(); ++j)
if (inputs[i][j] < min) min = inputs[i][j];
outputs[i] = min;
}
}
To find the smallest number in a vector, you simply have to examine each element in turn; there's no quicker way, at least from an algorithmic point-of-view.
In terms of practical performance, cache issues may affect you here. As has been mentioned in a comment, it will probably be more cache-efficient if you could store your vectors column-wise rather than row-wise. Alternatively, you may want to do all min searches in parallel, so as to minimise cache misses. i.e. rather than this:
foreach (col)
{
foreach (row)
{
x_min[col] = std::min(x_min[col], x[col][row]);
}
}
you should probably do this:
foreach (row)
{
foreach (col)
{
x_min[col] = std::min(x_min[col], x[col][row]);
}
}
Note that STL already provides a nice function to do this: min_element().
I need a help in making an algorithm for solving one problem: There is a row with numbers which appear different times in the row, and i need to find the number that appears the most and how many times it's in the row, ex:
1-1-5-1-3-7-2-1-8-9-1-2
That would be 1 and it appears 5 times.
The algorithm should be fast (that's my problem).
Any ideas ?
What you're looking for is called the mode. You can sort the array, then look for the longest repeating sequence.
You could keep hash table and store a count of every element in that structure, like this
h[1] = 5
h[5] = 1
...
You can't get it any faster than in linear time, as you need to at least look at each number once.
If you know that the numbers are in a certain range, you can use an additional array to sum up the occurrences of each number, otherwise you'd need a hashtable, which is slightly slower.
Both of these need additional space though and you need to loop through the counts again in the end to get the result.
Unless you really have a huge amount of numbers and absolutely require O(n) runtime, you could simply sort your array of numbers. Then you can walk once through the numbers and simply keep the count of the current number and the number with the maximum of occurences in two variables. So you save yourself a lot of space, tradeing it off with a little bit of time.
There is an algorithm that solves your problem in linear time (linear in the number of items in the input). The idea is to use a hash table to associate to each value in the input a count indicating the number of times that value has been seen. You will have to profile against your expected input and see if this meets your needs.
Please note that this uses O(n) extra space. If this is not acceptable, you might want to consider sorting the input as others have proposed. That solution will be O(n log n) in time and O(1) in space.
Here's an implementation in C++ using std::tr1::unordered_map:
#include <iostream>
#include <unordered_map>
using namespace std;
using namespace std::tr1;
typedef std::tr1::unordered_map<int, int> map;
int main() {
map m;
int a[12] = {1, 1, 5, 1, 3, 7, 2, 1, 8, 9, 1, 2};
for(int i = 0; i < 12; i++) {
int key = a[i];
map::iterator it = m.find(key);
if(it == m.end()) {
m.insert(map::value_type(key, 1));
}
else {
it->second++;
}
}
int count = 0;
int value;
for(map::iterator it = m.begin(); it != m.end(); it++) {
if(it->second > count) {
count = it->second;
value = it->first;
}
}
cout << "Value: " << value << endl;
cout << "Count: " << count << endl;
}
The algorithm works using the input integers as keys in a hashtable to a count of the number of times each integer appears. Thus the key (pun intended) to the algorithm is building this hash table:
int key = a[i];
map::iterator it = m.find(key);
if(it == m.end()) {
m.insert(map::value_type(key, 1));
}
else {
it->second++;
}
So here we are looking at the ith element in our input list. Then what we do is we look to see if we've already seen it. If we haven't, we add a new value to our hash table containing this new integer, and an initial count of one indicating this is our first time seeing it. Otherwise, we increment the counter associated to this value.
Once we have built this table, it's simply a matter of running through the values to find one that appears the most:
int count = 0;
int value;
for(map::iterator it = m.begin(); it != m.end(); it++) {
if(it->second > count) {
count = it->second;
value = it->first;
}
}
Currently there is no logic to handle the case of two distinct values appearing the same number of times and that number of times being the largest amongst all the values. You can handle that yourself depending on your needs.
Here is a simple one, that is O(n log n):
Sort the vector # O(n log n)
Create vars: int MOST, VAL, CURRENT
for ELEMENT in LIST:
CURRENT += 1
if CURRENT >= MOST:
MOST = CURRENT
VAL = ELEMENT
return (VAL, MOST)
There are few methods:
Universal method is "sort it and find longest subsequence" which is O(nlog n). The fastest sort algorithm is quicksort ( average, the worst is O( n^2 ) ). Also you can use heapsort but it is quite slower in average case but asymptotic complexity is O( n log n ) also in the worst case.
If you have some information about numbers then you can use some tricks. If numbers are from the limited range then you can use part of algorithm for counting sort. It is O( n ).
If this isn't your case, there are some other sort algorithms which can do it in linear time but no one is universal.
The best time complexity you can get here is O(n). You have to look through all elements, because the last element may be the one which determines the mode.
The solution depends on whether time or space is more important.
If space is more important, then you can sort the list then find the longest sequence of consecutive elements.
If time is more important, you can iterate through the list, keeping a count of the number of occurences of each element (e.g. hashing element -> count). While doing this, keep track of the element with max count, switching if necessary.
If you also happen know that the mode is the majority element (i.e. there are more than n/2 elements in the array with this value), then you can get O(n) speed and O(1) space efficiency.
Generic C++ solution:
#include <algorithm>
#include <iterator>
#include <map>
#include <utility>
template<class T, class U>
struct less_second
{
bool operator()(const std::pair<T, U>& x, const std::pair<T, U>& y)
{
return x.second < y.second;
}
};
template<class Iterator>
std::pair<typename std::iterator_traits<Iterator>::value_type, int>
most_frequent(Iterator begin, Iterator end)
{
typedef typename std::iterator_traits<Iterator>::value_type vt;
std::map<vt, int> frequency;
for (; begin != end; ++begin) ++frequency[*begin];
return *std::max_element(frequency.begin(), frequency.end(),
less_second<vt, int>());
}
#include <iostream>
int main()
{
int array[] = {1, 1, 5, 1, 3, 7, 2, 1, 8, 9, 1, 2};
std::pair<int, int> result = most_frequent(array, array + 12);
std::cout << result.first << " appears " << result.second << " times.\n";
}
Haskell solution:
import qualified Data.Map as Map
import Data.List (maximumBy)
import Data.Function (on)
count = foldl step Map.empty where
step frequency x = Map.alter next x frequency
next Nothing = Just 1
next (Just n) = Just (n+1)
most_frequent = maximumBy (compare `on` snd) . Map.toList . count
example = most_frequent [1, 1, 5, 1, 3, 7, 2, 1, 8, 9, 1, 2]
Shorter Haskell solution, with help from stack overflow:
import qualified Data.Map as Map
import Data.List (maximumBy)
import Data.Function (on)
most_frequent = maximumBy (compare `on` snd) . Map.toList .
Map.fromListWith (+) . flip zip (repeat 1)
example = most_frequent [1, 1, 5, 1, 3, 7, 2, 1, 8, 9, 1, 2]
The solution below gives you the count of each number. It is a better approach than using map in terms of time and space. If you need to get the number that appeared most number of times, then this is not better than previous ones.
EDIT: This approach is useful for unsigned numbers only and the numbers starting from 1.
std::string row = "1,1,5,1,3,7,2,1,8,9,1,2";
const unsigned size = row.size();
int* arr = new int[size];
memset(arr, 0, size*sizeof(int));
for (int i = 0; i < size; i++)
{
if (row[i] != ',')
{
int val = row[i] - '0';
arr[val - 1]++;
}
}
for (int i = 0; i < size; i++)
std::cout << i + 1 << "-->" << arr[i] << std::endl;
Since this is homework I think it's OK to supply a solution in a different language.
In Smalltalk something like the following would be a good starting point:
SequenceableCollection>>mode
| aBag maxCount mode |
aBag := Bag new
addAll: self;
yourself.
aBag valuesAndCountsDo: [ :val :count |
(maxCount isNil or: [ count > maxCount ])
ifTrue: [ mode := val.
maxCount := count ]].
^mode
As time is going by, the language evolves.
We have now many more language constructs that make life simpler
namespace aliases
CTAD (Class Template Argument Deduction)
more modern containers like std::unordered_map
range based for loops
the std::ranges library
projections
using statment
structured bindings
more modern algorithms
We could now come up with the following code:
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
namespace rng = std::ranges;
int main() {
// Demo data
std::vector data{ 2, 456, 34, 3456, 2, 435, 2, 456, 2 };
// Count values
using Counter = std::unordered_map<decltype (data)::value_type, std::size_t> ;
Counter counter{}; for (const auto& d : data) counter[d]++;
// Get max
const auto& [value, count] = *rng::max_element(counter, {}, &Counter::value_type::second);
// Show output
std::cout << '\n' << value << " found " << count << " times\n";
}