Cyclical vector - Finding the least possible 'cost' (From CodeChef) - c++

This is a question from Codechef but please bear with me.
https://www.codechef.com/ZCOPRAC/problems/ZCO12004
The contest is for the preparation of the Zonal Computing Olympiad held in India, so its not a competitive contest from which I'd earn something as such. Just need a little help to see what is wrong with my code, because I have a feeling I've overlooked something big and stupid. :P
The problem basically states:
Imagine there is a vector or array such that the last element is
linked to the first one. Find the lowest possible sum from adding at
least one of each adjacent pairs of elements. (refer to link please)
So answer for {1,2,1,2,2} output would be 4 by adding 1+1+2.
Here is my solution:
Basically what it does is that it iterates backwards, from the end of the vector to the beginning, and stores the lowest possible sum that can be achieved from that vector onwards, in vector M. Done using dynamic programming, basically.
The first two elements of M are the possible answers. Then I do some checks to see which is possible. If M[1] is less than M[0] then the last element of the array/vector should have been included in the sum calculated in M[1].
#include <algorithm>
#include <iostream>
#include <vector>
#define print(arr) for(auto pos = arr.begin(); pos != arr.end(); ++pos) cout << *pos << " "; cout << endl;
typedef long long int ll;
using namespace std;
int main() {
int N;
ll x;
cin >> N;
vector <ll> A;
vector <ll> M(N+2);
fill(M.begin(),M.end(),0);
for (int i = 0; i < N; i++) {
cin >> x;
A.push_back(x);
}
for (int i = N-1; i >= 0; i--) {
M[i] = A[i]+*min_element(M.begin()+i+1, M.begin()+i+3);
}
if (M[0] <= M[1]) cout << M[0] << endl;
else if (M[1] < M[0]) {
if (M[N-1] <= (M[N-2])) cout << M[1] << endl;
else cout << M[0] << endl;
}
}
However, I could not pass 2 of the test cases in subtask 2. I think the last part of my code is incorrect. Any idea what I could be doing wrong? Either that, or I have misunderstood the question. The term "adjacent pairs" is sort of ambiguous. So if there are 4 numbers 3,4,5,6 does adjacent pairs mean adjacent pairs to be {(3,4) (4,5) (5,6) (6,3)} or {either (3,4) and (5,6) or (4,5) and (6,3)}? My code considers the former.
EDIT:
Thanks a lot #User_Targaryen cleared some doubts about this question! Basically my implementation was the same as yours as my idea behind using dynamic programming was the same. Only that in this case my M (your dp) was the reverse of yours. Anyway I got AC! :) (I had left some silly debugging statements and was wondering for 15 mins what went wrong xD) Updated solution:
#include <algorithm>
#include <iostream>
#include <vector>
#define print(arr) for(auto pos = arr.begin(); pos != arr.end(); ++pos) cout << *pos << " "; cout << endl;
typedef long long int ll;
using namespace std;
int main() {
int N;
ll x, sum = 0;
cin >> N;
vector <ll> A;
vector <ll> M(N+2);
fill(M.begin(),M.end(),0);
for (int i = 0; i < N; i++) {
cin >> x;
A.push_back(x);
}
for (int i = N-1; i >= 0; i--) {
M[i] = A[i]+*min_element(M.begin()+i+1, M.begin()+i+3);
}
//print(M);
reverse(A.begin(), A.end());
vector <ll> M2(N+2);
fill(M2.begin(),M2.end(),0);
for (int i = N-1; i >= 0; i--) {
M2[i] = A[i]+*min_element(M2.begin()+i+1, M2.begin()+i+3);
}
//print(M2);
cout << min(M[0], M2[0]) << endl;
}

I am attaching my accepted solution here:
#include<iostream>
using namespace std;
int main()
{
int i,j,k,n;
cin>>n;
int a[n],dp1[n],dp2[n];
int ans;
for(i=0;i<n;i++)
{
cin>>a[i];
dp1[i]=0;
dp2[i]=0;
}
if(n <= 2)
cout<< min(a[0],a[1]);
else{
i = 2;
dp1[0] = a[0];
dp1[1] = a[1];
while (i < n){
dp1[i] = a[i] + min(dp1[i-1],dp1[i-2]);
i = i + 1;
}
dp2[0] = a[n-1];
dp2[1] = a[n-2];
i = n-3;
j = 2;
while(i >= 0){
dp2[j] = a[i] + min(dp2[j-1],dp2[j-2]);
i = i - 1;
j = j + 1;
}
ans = min(dp1[n-1], dp2[n-1]);
cout<<ans;
}
return 0;
}
dp1[i] means the most optimal solution till now by including the i-th element in the solution
dp2[i] means the most optimal solution till now by including the i-th element in the solution
dp1[] is calculated from left to right, while dp2[] is calculated from right to left
The minimum of dp1[n-1] and dp2[n-1] is the final answer.
I did your homework!
Edit: #Alex: Dynamic Programming is something that is very difficult to teach. It is something that comes naturally with some practice. Let us consider my solution (forget about your solution for some time):
dp1[n-1] means that I included the last element definitely in the solution, and the constraint that at least one of any 2 adjacent elements need to picked, is satisfied because it always follows:
dp1[i] = a[i] + min(dp1[i-1],dp1[i-2]);
dp2[n-1] means that I included the first element definitely in the solution, and the constraint that at least one of any 2 adjacent elements need to picked, is satisfied also.
So, the minimum of the above two, will give me the final result.

The idea in your M[i] array is "the minimum cost for a solution, assuming the index i is included in it".
The condition if (M[0] <= M[1]) means "if including index 0 is better than not including it, done".
If this condition doesn't hold, then, first of all, the check if (M[1] < M[0]) is superfluous - remove it. It won't fix any bugs, but will at least reduce confusion.
If the condition is false, you should output M[1], but only if it corresponds to a valid solution. That is, since index 0 is not chosen, the last index should be chosen. However, with your data structure it's impossible to know whether M[1] corresponds to a solution that chose last index - this information is lost.
To fix this, consider building two arrays - add e.g. an array L whose meaning is "the minimum cost for a solution, assuming the index i is included in it, and also index N-1 is included in it".
Then, at the end of your program, output the minimum of M[0] and L[1].

Related

C++ How to optimize this algorithm ? (std::map)

The problem is the following: We are given a number 's', s ∈ [0, 10^6], and a number 'n', n ∈ [0, 50000], then n numbers, and we have to find how many number pairs' sum is equal to the 's' number (and we must use either maps or sets to solve it)
Here is the example:
Input:
5 (this is s)
6 (this is n)
1
4
3
6
-1
5
Output:
2
explanation : these are the (1,4) and (6,−1) pairs. (1 +4 = 5 and 6 + (-1) = 5)
Here is my "solution" , I don't even know if it's correct, but it works for the example that we got.
#include <iostream>
#include <map>
#include <iterator>
using namespace std;
int main()
{
cin.tie(0);
ios::sync_with_stdio(false);
int s;
cin >> s;
int n;
cin >> n;
map<int, int> numbers;
int element;
int counter = 0;
for(int i=0; i<n;i++)
{
cin >> element;
numbers.insert(pair<int, int>(element, s-element));
}
for(map<int, int>::iterator it = numbers.begin(); it != numbers.end(); it++)
{
map<int, int>::iterator it2 = it;
while(it2 != numbers.end())
{
if(it->second == it2->first)
{
counter++;
break;
}
it2++;
}
}
cout << counter << "\n";
return 0;
}
Thanks for the answers in advance! I'm still a beginner and I'm learning, sorry.
element, s-element is a good idea but there is no reason to store all the pairs and only then check for duplicates. This removes the O(n^2) loop you have there at the end.
The standard way using hashing would be:
seen=unordered_map<number,count>()
for 1...n:
e = read_int()
if (s-e) in seen:
duplicates+=seen[s-e] # Found new seen[s-e] duplicates.
if e in seen:
seen[e]+=1
else:
seen.insert(e,1)
return duplicates
Here's a brute-force method, using a vector:
int target_s = 0;
int quantity_numbers = 0;
std::cin >> target_s >> quantity_numbers;
std::vector<int> data(quantity_numbers);
for (int i = 0; i < quantity_numbers; ++i)
{
cin >> data[i];
}
int count = 0;
for (int i = 0; i < quantity_numbers; ++i)
{
for (j = 0; j < quantity_numbers; ++j)
{
if (i == j) continue;
int pair_sum = data[i] + data[j];
if (pair_sum == target_s) ++count;
}
}
std::cout << count;
The above code includes the cases where pair <a,b> == s and pair <b,a> == s. Not sure if the requirement only wants pair <a,b> in this case.
As always with this kind of questions, the selection of the appropriate algorithm will improve your solution. Writing some "better" C++ code, will nearly never help. Also, brute forcing is nearly never a solution for such an algorithm.
With the following described approach (which was of course not invented by me), we need just one std::map (or even better, a std::unordered_map) and one for loop. We do not need to store the read values in an additional std::vector or such alike. So, we can come up with low memory condumption and fast computation.
Approach. Any time, after reading a value, we will calculate the delta from the desired sum.
If we look at the required condition that the current value and some previuosly read value, should add up to the desired sum, we can write the following mathematical equations:
currentValue + previouslyReadValue = desiredSum
or
desiredSum - currentValue = previouslyReadValue
or with
delta = desiredSum - currentValue
-->
delta == previouslyReadValue
So, we need to look at the already read values and if they are equal to the delta (Because then they would add up the the desired sum), add their count of occurence the the resulting count of valid pairs.
The already read values and their count of occurence will be stored in a std::unordered_map.
All this will result in a 10 line solution:
#include <iostream>
#include <unordered_map>
int main() {
// Initialize our working variables
int numberOfValues{}, desiredSum{}, currentValue{}, resultingCount{};
// Read basic parameters. Desired sum and overall number of input values.
std::cin >> desiredSum >> numberOfValues;
// Here, we will store all values and their count of occurence
std::unordered_map<int, int> valuesAndCount{};
// Read all values and operate on them
for (int i{}; i < numberOfValues; ++i) {
std::cin >> currentValue; // Read from cin
const int delta{ desiredSum - currentValue }; // Calculate the delta from the desired sum
// Look, if the calculated delta is already in the map. Becuase, if the delta and the
// current value sum up to our desired sum, then we found a valid pair.
if (valuesAndCount.find(delta) != valuesAndCount.end())
// Increase the resulting count, by the number of times that this delta value has already been there
resultingCount += valuesAndCount[delta];
// Nothing special, Just cound the occurence of this value.
valuesAndCount[currentValue]++;
}
return !!(std::cout << resultingCount);
}

What does this variable do?

One day, Twilight Sparkle is interested in how to sort a sequence of
integers a1, a2, ..., an in non-decreasing order. Being a young
unicorn, the only operation she can perform is a unit shift. That is,
she can move the last element of the sequence to its beginning:
a1, a2, ..., an → an, a1, a2, ..., an - 1. Help Twilight Sparkle to
calculate: what is the minimum number of operations that she needs to
sort the sequence?
Input
The first line contains an integer n (2 ≤ n ≤ 105). The second
line contains n integer numbers a1, a2, ..., an (1 ≤ ai ≤ 105).
Output
If it's impossible to sort the sequence output -1. Otherwise
output the minimum number of operations Twilight Sparkle needs to sort
it.
Examples
input
2
2 1
output
1
input
3
1 3 2
output
-1
input
2
1 2
output
0
Above is the problem and now I am confused because the solution down there used a variable called "s" and played around it for some reason but I don't know why was that variable used, if someone can tell me I'll be thankful.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int n, s, v(0);
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < n - 1; i++) if (a[i] > a[i + 1]) s = i, v++;
if (a[n - 1] > a[0]) s = n - 1, v++;
if (v == 0) cout << 0 << endl;
else if (v > 1) cout << -1 << endl;
else cout << n - 1 - s << endl;
return 0;
}
Now here is my own solution, it works and everything except on a 10^5(and around that) size array but the question time limit is only 1000 ms, and mine exceeds that limit due to the nested loops making it go over O(10^8) which is 1000 ms on their systems.
#include <bits/stdc++.h>
#define fl(i,n) for(int i = 0; i < n; i++)
#define ll long long
#define nl endl
#define pb push_back
#define mp make_pair
#define PII pair<int,int>
#define EPS 1e-9
#define INF 1e9
using namespace std;
bool check(int a[], int n){
for(int i = 0; i < n-1; i++){
if(a[i] <= a[i+1]) continue;
return false;
}
return true;
}
int main()
{
int n;
cin >> n;
int a[n]; //is out of standard i know but it's accepted in the contest's compiler so we just use it
for(int i = 0; i < n; i++){
cin >> a[i];
}
if(check(a,n)){
cout << 0;
return 0;
}
int ret = 0;
for(int i = 0; i < n-1; i++){
ret++;
for(int j = n-1; j > 0; j--)
a[j] ^= a[j-1] ^= a[j] ^= a[j-1]; //is xor swap
if(check(a,n)){
cout << ret;
return 0;
}
}
cout << -1;
return 0;
}
PS: I TRACED the solution's code and even if I get the correct answers I simply don't know what it refers to.
The other person's implementation relies on an algorithmic insight. The only way a sequence can be sorted by moving back to front is if the sequence is made of two already-sorted sections. Then, the goal is to check how many unsorted discontinuities exist, and where they are. That's what s appears to be used for: the index of the (last) discontinuity of the sequence. v is the count of discontinuities.
If there are 0, it's already sorted. If more than 1, it's unsortable. If it's exactly one, then you can easily figure out how many shifts you need to perform to pull the discontinuity back to the front, using it's location (s) in the original sequence.
The only extra line of code is the special case of checking for the discontinuity around end of the sequence.
My recommendation: Generate a larger set of test sequences, and print v and s for each one.

Deleting elements from a vector that meet a condition

I am trying to program the Sieve of Eratosthenes, but I am not sure how to delete elements from the vector I made given a specific condition. Does anyone know how to achieve this? Here is my code:
#include <iostream>
#include <vector>
using namespace std;
int prime(int n);
int prime(int n)
{
vector<int> primes;
for(int i = 2; i <= n; i++)
{
primes.push_back(i);
int t = i % (i + 1);
if(t == 0)
{
delete t; // is there a way of deleting the elements from
// the primes vector that follow this condition t?
}
cout << primes[i] << endl;
}
}
int main()
{
int n;
cout << "Enter a maximum numbers of primes you wish to find: " << endl;
cin >> n;
prime(n);
return 0;
}
Your algorithm is wrong:
t = i % (i + 1);
is
i
which is always != 0 because i is larger than 1.
By the way if you absolutely want to remove the t-th element you have to be sure that the vector is not empty and then you do:
primes.erase(primes.begin()+t);
Even if you fix the algorithm your approach is inefficient: erasing an element in the middle of a vector means copying back of one position all the ones following the erased element.
You don't usually want to delete elements in the middle of a Sieve of Eratosthenes, but when you do want to, you usually want to use the remove/erase idiom:
x.erase(std::remove_if(x.begin(), x.end(), condition), x.end());
std::remove basically just partitions the collection into those that don't meet the specified condition, followed by objects that may have been used as the source of either a copy or a move, so you can't count on their value, but they are in some stable state so erasing them will work fine.
The condition can be either a function or a functor. It receives (a reference to a const) object that it examines and determines whether it lives or dies (so to speak).
Find here a c++ pseudocode for the sieve algorithm. Once you've understood the algorithm you can start working on this.
primes(vector& primes, size_t max){
vector primesFlag(1,max);
i=1
while(i*i<max){
++i;
for(j=i*i; j < max; j+= i){
primesFlag[j] = 0;
}
}
primes.clear()
primes.reserve(...);
for(j >= 2;
if primesFlag[j] = 1
primes.push_back(j);
}

Need help optimizing a program that finds all possible substrings

I have to find all possible, unique substrings from a bunch of user-input strings. This group of substrings has to be alphabetically sorted without any duplicate elements, and the group must be queryable by number. Here's some example input and output:
Input:
3 // This is the user's desired number of strings
abc // So the user inputs 3 strings
abd
def
2 // This is the user's desired number of queries
7 // So the user inputs 2 queries
2
Output:
// From the alphabetically sorted group of unique substrings,
bd // This is the 7th substring
ab // And this is the 2nd substring
Here's my implementation:
#include <map>
#include <iostream>
using namespace std;
int main() {
int number_of_strings;
int number_of_queries;
int counter;
string current_string;
string current_substr;
map<string, string> substrings;
map<int, string> numbered_substrings;
int i;
int j;
int k;
// input step
cin >> number_of_strings;
string strings[number_of_strings];
for (i = 0; i < number_of_strings; ++i)
cin >> strings[i];
cin >> number_of_queries;
int queries[number_of_queries];
for (i = 0; i < number_of_queries; ++i)
cin >> queries[i];
// for each string in 'strings', I want to insert every possible
// substring from that string into my 'substrings' map.
for (i = 0; i < number_of_strings; ++i) {
current_string = strings[i];
for (j = 1; j <= current_string.length(); ++j) {
for (k = 0; k <= current_string.length()-j; ++k) {
current_substr = current_string.substr(k, j);
substrings[current_substr] = current_substr;
}
}
}
// my 'substrings' container is now sorted alphabetically and does
// not contain duplicate elements, because the container is a map.
// but I want to make the map queryable by number, so I'm iterating
// through 'substrings' and assigning each value to an int key.
counter = 1;
for (map<string,string>::iterator it = substrings.begin();
it != substrings.end(); ++it) {
numbered_substrings[counter] = it->second;
++counter;
}
// output step
for (i = 0; i < number_of_queries; ++i) {
if (queries[i] > 0 && queries[i] <= numbered_substrings.size()) {
cout << numbered_substrings[queries[i]] << endl;
} else {
cout << "INVALID" << endl;
}
}
return 0;
}
I need to optimize my algorithm, but I'm not sure how to do it. Maybe it's the fact that I have a second for loop for assigning new int keys to each substring. Help?
Check out Suffix tree. It usually runs in O(n) time:
This article was helpful for me:
http://allisons.org/ll/AlgDS/Tree/Suffix/
Minor notes:
1. include <string>
2. careful with those } else {; one day you'll have a lot of else if branches
and a lot of lines and you'll wonder where an if starts and where it ends
3. careful with unsigned versus signed mismatching... again, one day it will
come back and bite (also, it's nice to compile without errors or warnings)
4. don't try to define static arrays with a variable size
5. nice with ++ i. not many know it has a slight performance boost
(maybe not noticeable with today's processors but still)
While I do agree that using proper algorithms when needed (say bubble sort, heap sort etc. for sorting, binary search, binary trees etc. for searching), sometimes I find it nice to do an optimization on current code. Imagine having a big project and implementing something requires rewrites... not many are willing to wait for you (not to mention the required unit testing, fat testing and maybe fit testing). At least my opinion. [and yes, I know some are gonna say that if it is so complicated then it was written badly from the start - but hey, you can't argue with programmers that left before you joined the team :P]
But I do agree, using existing stuff is a good alternative when called for. But back to the point. I tested it with
3, abc, def, ghi
4, 1, 3, 7, 12
I can't say whether yours is any slower than mine or vice-versa; perhaps a random string generator that adds maybe 500 inputs (then calculates all subs) might be a better test, but I am too lazy at 2 in the morning. At most, my way of writing it might help you (at least to me it seems simpler and uses less loops and assignments). Not a fan of vectors, cos of the slight overhead, but I used it to keep up with your requirement of dynamic querying... a static array of a const would be faster, obviously.
Also, while not my style of naming conventions, I decided to use your names so you can follow the code easier.
Anyway, take a look and tell me what you think:
#include <map>
#include <iostream>
#include <string> // you forgot to add this... trust me, it's important :)
#include <vector> // not a fan, but it's not that bad IF you want dynamic buffers
#include <strstream>
using namespace std;
int main ()
{
unsigned int number_of_strings = 0;
// string strings[number_of_strings]; // don't do this... you can't assign static arrays of a variable size
// this just defaults to 0; you're telling the compiler
cin >> number_of_strings;
map <string, string> substrings;
string current_string, current_substr;
unsigned int i, j, k;
for (i = 0; i < number_of_strings; ++ i)
{
cin >> current_string;
substrings[current_string] = current_string;
for (j = 1; j <= current_string.length(); ++ j)
{
for (k = 0; k <= current_string.length() - j; ++ k)
{
current_substr = current_string.substr(k, j);
substrings[current_substr] = current_substr;
}
}
}
vector <string> numbered_substrings;
for (map <string, string>::iterator it = substrings.begin(); it != substrings.end(); ++ it)
numbered_substrings.push_back(it->second);
unsigned int number_of_queries = 0;
unsigned int query = 0;
cin >> number_of_queries;
current_string.clear();
for (i = 0; i < number_of_queries; ++ i)
{
cin >> query;
-- query;
if ((query >= 0) && (query < numbered_substrings.size()))
current_string = current_string + numbered_substrings[query] + '\n';
else
cout << "INVALID: " << query << '\n' << endl;
}
cout << current_string;
return 0;
}

Find the biggest 3 numbers in a vector

I'm trying to make a function to get the 3 biggest numbers in a vector. For example:
Numbers: 1 6 2 5 3 7 4
Result: 5 6 7
I figured I could sort them DESC, get the 3 numbers at the beggining, and after that resort them ASC, but that would be a waste of memory allocation and execution time. I know there is a simpler solution, but I can't figure it out. And another problem is, what if I have only two numbers...
BTW: I use as compiler BorlandC++ 3.1 (I know, very old, but that's what I'll use at the exam..)
Thanks guys.
LE: If anyone wants to know more about what I'm trying to accomplish, you can check the code:
#include<fstream.h>
#include<conio.h>
int v[1000], n;
ifstream f("bac.in");
void citire();
void afisare_a();
int ultima_cifra(int nr);
void sortare(int asc);
void main() {
clrscr();
citire();
sortare(2);
afisare_a();
getch();
}
void citire() {
f>>n;
for(int i = 0; i < n; i++)
f>>v[i];
f.close();
}
void afisare_a() {
for(int i = 0;i < n; i++)
if(ultima_cifra(v[i]) == 5)
cout<<v[i]<<" ";
}
int ultima_cifra(int nr) {
return nr - 10 * ( nr / 10 );
}
void sortare(int asc) {
int aux, s;
if(asc == 1)
do {
s = 0;
for(int i = 0; i < n-1; i++)
if(v[i] > v[i+1]) {
aux = v[i];
v[i] = v[i+1];
v[i+1] = aux;
s = 1;
}
} while( s == 1);
else
do {
s = 0;
for(int i = 0; i < n-1; i++)
if(v[i] < v[i+1]) {
aux = v[i];
v[i] = v[i+1];
v[i+1] = v[i];
s = 1;
}
} while(s == 1);
}
Citire = Read
Afisare = Display
Ultima Cifra = Last digit of number
Sortare = Bubble Sort
If you were using a modern compiler, you could use std::nth_element to find the top three. As is, you'll have to scan through the array keeping track of the three largest elements seen so far at any given time, and when you get to the end, those will be your answer.
For three elements that's a trivial thing to manage. If you had to do the N largest (or smallest) elements when N might be considerably larger, then you'd almost certainly want to use Hoare's select algorithm, just like std::nth_element does.
You could do this without needing to sort at all, it's doable in O(n) time with linear search and 3 variables keeping your 3 largest numbers (or indexes of your largest numbers if this vector won't change).
Why not just step through it once and keep track of the 3 highest digits encountered?
EDIT: The range for the input is important in how you want to keep track of the 3 highest digits.
Use std::partial_sort to descending sort the first c elements that you care about. It will run in linear time for a given number of desired elements (n log c) time.
If you can't use std::nth_element write your own selection function.
You can read about them here: http://en.wikipedia.org/wiki/Selection_algorithm#Selecting_k_smallest_or_largest_elements
Sort them normally and then iterate from the back using rbegin(), for as many as you wish to extract (no further than rend() of course).
sort will happen in place whether ASC or DESC by the way, so memory is not an issue since your container element is an int, thus has no encapsulated memory of its own to manage.
Yes sorting is good. A especially for long or variable length lists.
Why are you sorting it twice, though? The second sort might actually be very inefficient (depends on the algorithm in use). A reverse would be quicker, but why even do that? If you want them in ascending order at the end, then sort them into ascending order first ( and fetch the numbers from the end)
I think you have the choice between scanning the vector for the three largest elements or sorting it (either using sort in a vector or by copying it into an implicitly sorted container like a set).
If you can control the array filling maybe you could add the numbers ordered and then choose the first 3 (ie), otherwise you can use a binary tree to perform the search or just use a linear search as birryree says...
Thank #nevets1219 for pointing out that the code below only deals with positive numbers.
I haven't tested this code enough, but it's a start:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> nums;
nums.push_back(1);
nums.push_back(6);
nums.push_back(2);
nums.push_back(5);
nums.push_back(3);
nums.push_back(7);
nums.push_back(4);
int first = 0;
int second = 0;
int third = 0;
for (int i = 0; i < nums.size(); i++)
{
if (nums.at(i) > first)
{
third = second;
second = first;
first = nums.at(i);
}
else if (nums.at(i) > second)
{
third = second;
second = nums.at(i);
}
else if (nums.at(i) > third)
{
third = nums.at(i);
}
std::cout << "1st: " << first << " 2nd: " << second << " 3rd: " << third << std::endl;
}
return 0;
}
The following solution finds the three largest numbers in O(n) and preserves their relative order:
std::vector<int>::iterator p = std::max_element(vec.begin(), vec.end());
int x = *p;
*p = std::numeric_limits<int>::min();
std::vector<int>::iterator q = std::max_element(vec.begin(), vec.end());
int y = *q;
*q = std::numeric_limits<int>::min();
int z = *std::max_element(vec.begin(), vec.end());
*q = y; // restore original value
*p = x; // restore original value
A general solution for the top N elements of a vector:
Create an array or vector topElements of length N for your top N elements.
Initialise each element of topElements to the value of your first element in your vector.
Select the next element in the vector, or finish if no elements are left.
If the selected element is greater than topElements[0], replace topElements[0] with the value of the element. Otherwise, go to 3.
Starting with i = 0, swap topElements[i] with topElements[i + 1] if topElements[i] is greater than topElements[i + 1].
While i is less than N, increment i and go to 5.
Go to 3.
This should result in topElements containing your top N elements in reverse order of value - that is, the largest value is in topElements[N - 1].