Codeforces 519B Using Vectors vs Some Other Container - c++

To solve 519B I created three vectors that each hold different numbers and occurrences of those numbers for each line. These vectors are also sorted.
eg if the line was 1 1 3 2, the vector would store <1, 2>, <2, 1>, <3, 1>
From there, I would compare one pair from one vector with the pair from the next vector to find the missing number.
This passes most test cases until there are a large number of numbers in each line. I actually saw the answer for this question, but it uses a different method to find the answer. However, I would like to know if there is a way to solve the question with "my way." I read online that using maps and other containers could yield a faster result, but I'm skeptical that using another container would really make that big of a difference. Any thoughts?
#include <iostream>
#include <vector>
#include <algorithm>
int has(std::vector<std::pair<int, int>> &error, int i) {
for (int j = 0; j < error.size(); j++) {
if (error[j].first == i) {
return j;
}
}
return -1;
}
std::vector<std::pair<int, int>> generate(int n) {
int temp;
std::vector<std::pair<int, int>> tempVec;
for (int i = 0; i < n; i++) {
std::cin >> temp;
int pos = has(tempVec, temp);
if (pos != -1) {
tempVec[pos].second++;
} else {
tempVec.push_back(std::make_pair(temp, 1));
}
}
return tempVec;
}
bool sortPair(const std::pair<int, int> &a, const std::pair<int, int> &b) {
return a.first < b.first;
}
int main() {
int n, temp;
std::cin >> n;
std::vector<std::pair<int, int>> a = generate(n), b = generate(n - 1), c = generate(n - 2);
std::sort(a.begin(), a.end(), sortPair);
std::sort(b.begin(), b.end(), sortPair);
std::sort(c.begin(), c.end(), sortPair);
bool found = false;
for (int i = 0; i < n - 1; i++) {
if (a[i] != b[i]) {
found = true;
std::cout << a[i].first << std::endl;
break;
}
}
if (!found) {
std::cout << a[n - 1].first << std::endl;
}
bool found2 = false;
for (int i = 0; i < n - 2; i++) {
if (b[i] != c[i]) {
found2 = true;
std::cout << b[i].first << std::endl;
break;
}
}
if (!found2) {
std::cout << b[n - 2].first << std::endl;
}
}

Related

How to sum up values of occuring chars from a string, make them pairs and sort them in ascending order?

My task is to write a function that gets a vector of strings as an argument, and returns a vector of pair<char,int> containing pairs representing characters and their frequency (how much times the letter has appeared) summed up from all strings passed in vector as an argument of the function. It should also be sorted in ascending order.
The code below is my approach on how to do it. So far I'm only able to count how many times the character occured in every string, but I'm not able to sum all of the occuring letters to be the one pair.
#include <iostream>
#include <vector>
#include <utility>
#include <string>
using namespace std;
bool isEqual(const pair<char, int> &element) {
return element.first;
}
vector<pair<char, int>> all_occurrences(vector<string> vec) {
vector<pair<char, int>> sorted_vec;
vector<pair<char, int>> final_vec;
char c;
int count_chars = 0;
string element;
vector<char> check_chars = {' '};
bool char_found = false;
for (int i = 0; i < vec.size(); i++) {
element = vec[i];
for (int j = 0; j < element.length(); j++) {
c = element.at(j);
for (int k = 0; k < check_chars.size(); ++k) {
if (c == check_chars[k]) {
char_found = true;
break;
}
}
if (!char_found) {
check_chars.push_back(c);
count_chars = count(element.begin(), element.end(), c);
sorted_vec.push_back(make_pair(c, count_chars));
}
char_found = false;
}
check_chars = {' '};
}
vector<pair<char, int>>::iterator it;
for (int i = 0; i < sorted_vec.size(); ++i) {
it = find_if(sorted_vec.begin(), sorted_vec.end(), isEqual);
cout << it << endl;
}
return sorted_vec;
}
void print_vector(vector<pair<char, int>> pair_vector) {
cout << "---" << endl;
for (int i = 0; i < pair_vector.size(); i++) {
cout << pair_vector[i].first << ',' << pair_vector[i].second << endl;
}
cout << "---" << endl;
}
int main() {
vector<string> string_vector = {"ala", "ma", "kota"};
print_vector(all_occurrences(string_vector));
return 0;
}
First you can calculate all the frequency counts with a std::map:
std::map<char,int> m;
for(auto c : vec | std::views::join) // for every char in all strings
m[c]++;
Then you can copy this map into a vector as needed:
vector<pair<char, int>> res;
std::ranges::copy(m, std::back_inserter(res));
And finally you can sort the vector in ascending order of the frequency counts:
std::ranges::sort(res, std::less{}, &std::pair<char, int>::second);
Here's a demo.
Pre C++20, you can write the above code like this:
Construct a frequency count:
std::map<char,int> m;
for (auto const &s : vec) // for every string
for(auto c : s) // for every character
m[c]++; // add to the frequency count
Copy into a vector:
vector<pair<char, int>> res;
std::copy(m.begin(), m.end(), std::back_inserter(res));
And sort it:
std::sort(res.begin(), res.end(), [](auto a, auto b) {
return a.second < b.second;
});
Here's a demo.

Kurskal algorithm, Runtime Error in Kattis

I've been trying to solve the Minimum Spanning Tree on Kattis. (https://open.kattis.com/problems/minspantree) The first test runs fine, the second gives an unspecified runtime error. I've been struggling with this for over a week. It must be some logical error, but no matter how much effort i'm putting into it, I can't see what's wrong.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <tuple>
using namespace std;
class DisjointSet {
public:
vector<int> parent, rank;
DisjointSet(int _size) {
parent.resize(_size);
rank.resize(_size); // Maybe this?
// make the sets
for (int i = 0; i < _size; i++) { // fill set
parent[i] = i;
rank[i] = 0;
}
}
void make_set(int v) {
parent[v] = v;
rank[v] = 0;
}
int find_set(int v) {
if (v == parent[v])
return v;
return parent[v] = find_set(parent[v]);
}
void union_sets(int a, int b) {
a = find_set(a);
b = find_set(b);
if (a != b) {
if (rank[a] < rank[b])
swap(a, b);
parent[b] = a;
if (rank[a] == rank[b])
rank[a]++;
}
}
};
bool sort_weight(const tuple<int, int, int> &one, const tuple<int, int, int> &two) {
return get<2>(one) < get<2>(two); // Weight
}
bool sort_node(const tuple<int, int, int> &one, const tuple<int, int, int> &two) {
if (get<0>(one) != get<0>(two)) {
return get<0>(one) < get<0>(two); // node one
}
return get<1>(one) < get<1>(two); // node two
}
int main()
{
int n_nodes = 0, n_arcs = 0;
int tmp_node1, tmp_node2, tmp_weight;
while (cin >> n_nodes >> n_arcs) { // Until the end
if (n_nodes == 0 && n_arcs == 0) { break; }
if (n_arcs < n_nodes - 1) { // If it is not possible to build a MST
cout << "Impossible\n";
}
else {
int cost = 0;
DisjointSet s(n_nodes); // make set
vector<tuple<int, int, int>> vArcs;
vector<tuple<int, int, int>> vResult;
vArcs.resize(n_arcs);
for (int i = 0; i < n_arcs; i++) {
cin >> tmp_node1 >> tmp_node2 >> tmp_weight;
vArcs[i] = make_tuple(tmp_node1, tmp_node2, tmp_weight);
}
sort(vArcs.begin(), vArcs.end(), sort_weight); // Sort by weight lowest to highest
for (int i = 0; i < n_arcs && vResult.size()<(n_nodes - 1); i++)
{
if (s.find_set(get<0>(vArcs[i])) != s.find_set(get<1>(vArcs[i]))) {
cost += get<2>(vArcs[i]);
vResult.push_back(vArcs[i]);
s.union_sets(get<0>(vArcs[i]), get<1>(vArcs[i]));
}
}
// We are done, order and print
sort(vResult.begin(), vResult.end(), sort_node);
cout << cost << "\n";
for (int i = 0; i < vResult.size(); i++)
{
cout << get<0>(vResult[i]) << " " << get<1>(vResult[i]) << "\n";
}
}
}
}
You need to read the whole input for each test case, even if the number of edges is below n - 1.

Finding two associated indexes where the sum of two elements equals a target value

Background:
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
Question:
I have a list of numbers 1,2,3,4,5. My target value is 8, so I should return indices 2 and 4. My first thought is to write a a double for loop that checks to see if adding two elements from the list will get my target value. Although, when checking to see if there is such a solution, my code returns that there is none.
Here is my code:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> list;
list.push_back(1);
list.push_back(2);
list.push_back(3);
list.push_back(4);
list.push_back(5);
int target = 8;
string result;
for(int i = 0; i < list.size(); i++) {
for(int j = i+1; j < list.size(); j++) {
if(list[i] + list[j] == target) {
result = "There is a solution";
}
else {
result = "There is no solution";
}
}
}
cout << result << endl;
return 0;
}
Perhaps my approach/thinking is plain wrong. Could anyone provide any hints or suggestions to solving this problem?
Your approach is correct but you are forgetting you are in a loop that continues after finding the solution.
This will get you halfway there. I recommend putting both loops in a function, and returning once you find a match. One thing you could do is return a pair<int,int> from that function or you could simply output the results from within that point in the loop.
bool solutionFound = false;
int i,j;
for(i = 0; i < list.size(); i++)
{
for(j = i+1; j < list.size(); j++)
{
if(list[i] + list[j] == target)
{
solutionFound = true;
}
}
}
Here is what the function approach might look like:
pair<int, int> findSolution(vector<int> list, int target)
{
for (int i = 0; i < list.size(); i++)
{
for (int j = i + 1; j < list.size(); j++)
{
if (list[i] + list[j] == target)
{
return pair<int, int>(i, j);
}
}
}
return pair<int, int>(-1, -1);
}
int main() {
vector<int> list;
list.push_back(1);
list.push_back(2);
list.push_back(3);
list.push_back(4);
list.push_back(5);
int target = 8;
pair<int, int> results = findSolution(list, target);
cout << results.first << " " << results.second << "\n";
return 0;
}
Here's the C++ incorporating Dave's answer for linear execution time and a couple helpful comments:
pair<int, int> findSolution(vector<int> list, int target)
{
unordered_map<int, int> valueToIndex;
for (int i = 0; i < list.size(); i++)
{
int needed = target - list[i];
auto it = valueToIndex.find(needed);
if (it != valueToIndex.end())
{
return pair<int, int>(it->second, i);
}
valueToIndex.emplace(list[i], i);
}
return pair<int, int>(-1, -1);
}
int main()
{
vector<int> list = { 1,2,3,4,5 };
int target = 10;
pair<int, int> results = findSolution(list, target);
cout << results.first << " " << results.second << "\n";
}
You're doing this in n^2 time. Solve it in linear time by hashing each element, and checking each element to see if it's complement wrt. the total you're trying to achieve is in the hash.
E.g., for 1,2,3,4,5, with a target of 8
indx 0, val 1: 7 isn't in the map; H[1] = 0
indx 1, val 2: 6 isn't in the map, H[2] = 1
indx 2, val 3: 5 isn't in the map, H[3] = 2
indx 3, val 4: 4 isn't in the map, H[4] = 3
indx 4, val 5: 3 is in the map. H[3] = 2. Return 2,4
Code, as requested (Ruby)
def get_indices(arr, target)
value_to_index = {}
arr.each_with_index do |val, index|
if value_to_index.has_key?(target - val)
return [value_to_index[target - val], index]
end
value_to_index[val] = index
end
end
get_indices([1,2,3,4,5], 8)
Basically the same as zzxyz's most recent edit but a little quicker and dirtier.
#include <iostream>
#include <vector>
bool FindSolution(const std::vector<int> &list, // const reference. Less copying
int target)
{
for (int i: list) // Range-based for (added in C++11)
{
for (int j: list)
{
if (i + j == target) // i and j are the numbers from the vector.
// no need for indexing
{
return true;
}
}
}
return false;
}
int main()
{
std::vector<int> list{1,2,3,4,5}; // Uniform initialization Added in C++11.
// No need for push-backs of fixed data
if (FindSolution(list, 8))
{
std::cout << "There is a solution\n";
}
else
{
std::cout << "There is no solution\n";
}
return 0;
}

reduce the complexity of the program

Here is the program to find the pairs that sums up to 3.
For example:
INPUT : 0,3,5,1,2,4
OUTPUT: 0,3,1,2.
That means it should return all the pairs whose sum is equal to 3.
But I want to reduce the time complexity of this program. Right now I am using two nested for loops.
Can anyone suggest a better method to reduce the time complexity.
#include<iostream>
#include <vector>
using namespace std;
void main()
{
vector<int> v;
vector<int> r;
int x;
cout << "Enter the elements";
for(int i = 0; i < 6; i++)
{
cin >> x;
v.push_back(x);
}
for(int i = 0 ; i < v.size() - 1; i++)
{
for(int j = i + 1; j < v.size(); j++)
{
if(v[i] + v[j] == 3)
{
r.push_back(v[i]);
r.push_back(v[j]);
}
}
}
cout << "\noutput\n";
for(int i = 0 ; i < r.size(); i++)
{
cout<<r[i]<<"\n";
}
}
I'd do two preparation steps; First, eliminate all numbers > 3, as they will not be part of any valid pair. This reduces the complexity of the second step. Second, sort the remaining numbers such that a single walk through can then find all the results.
The walk through approaches the pairs from both ends of the sorted array; if a pair is found, both bounds can be narrowed down; if the current endings do sum up to a value > 3, only one boundary is narrowed.
Runtime complexity is O(N logN), where N is the count of elements <= 3; O(N logN) basically comes from sorting; the two single walk throughs will not count for large Ns.
int main(int argc, char* argv[]) {
const int N = 3;
std::vector<int> input{ 0,3,5,1,2,4};
std::vector<int>v(input.size());
int t=0;
for (auto i : input) {
if (i <= N) {
v[t++]=i;
}
}
std::sort (v.begin(), v.end());
long minIdx = 0;
long maxIdx = v.size()-1;
while (minIdx < maxIdx) {
int minv = v[minIdx];
int maxv = v[maxIdx];
if (minv+maxv == 3) {
cout << minv << '+' << maxv << endl;
minIdx++;maxIdx--;
}
else
minIdx++;
}
return 0;
}
You are searching for all the combinations between two numbers in n elements, more specifically, those that sum up to specific value. Which is a variation of the subset sum problem.
To make this happen you could generate all combinations without repetitions of the indexes of the vector holding the values. Here is an example of how to do this recursively and here is an example of how to do it iteratively, just to get an idea and possibly use it as a benchmark in your case.
Another approaches are dynamic programming and backtracking.
Late answer but works for negative integers too... For first, find the smallest number in the std::vector<int>, then like this answer says, remove all elements (or copy the opposite), which are higher than 3 + minimum. After sorting this std::vector<int> iterate through it from both ends with condition shown bellow:
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
std::vector<int> findPairs(const std::vector<int>& input, const int sum) {
int minElem = INT_MAX;
for(auto lhs = input.begin(), rhs = input.end() - 1; lhs < rhs;
++lhs, --rhs) {
const int elem = (*lhs < *rhs ? *lhs : *rhs);
if(elem < minElem)
minElem = elem;
}
std::vector<int> temp(input.size());
const auto tempBegin = temp.begin();
const auto tempEnd = std::remove_copy_if(input.begin(), input.end(),
temp.begin(), [minElem, sum](int elem) {
return (elem + minElem) > sum;
});
std::sort(tempBegin, tempEnd);
std::vector<int> result;
auto leftIter = tempBegin;
auto rightIter = tempEnd - 1;
while(leftIter < rightIter) {
if(*leftIter + *rightIter == sum) {
result.push_back(*leftIter++);
result.push_back(*rightIter--);
}
else {
if(sum - *leftIter < *rightIter) rightIter--;
else leftIter++;
}
}
return result;
}
int main() {
auto pairs = findPairs({ 0, 3, 5, 1, 2, 4, 7, 0, 3, 2, -2, -4, -3 }, 3);
std::cout << "Pairs: { ";
for(auto it = pairs.begin(); it != pairs.end(); ++it)
std::cout << (it == pairs.begin() ? "" : ", ") << *it;
std::cout << " }" << std::endl;
}
The code above will results the following:
Pairs: { -4, 7, -2, 5, 0, 3, 0, 3, 1, 2 }
I think you can solve this in O(n) with a map.
public void printPairs(int[] a, int v)
{
map<int, int> counts = new map<int, int>();
for(int i = 0; i < a.length; i++)
{
if(map.count(a[i]) == 0)
{
map[a[i]] = 1;
}
else
{
map[a[i]] = map[a[i]] + 1;
}
}
map<int, int>::iterator it = map.begin();
while(it != map.end())
{
int v1 = it->second;
if (map.count(v - v1) > 0)
{
// Found pair v, v1
//will be found twice (once for v and once for v1)
}
}
}

Mode of Array C++

My code to find the mode (most often) and how many times said mode was displayed runs into a never-ending loop. Does anyone know what I can do to fix it?
EDIT I UPDATED THE CODE: It returns 0, which is not the mode.
void calculateMode(int array[], int size)
{
int counter = 0;
int max = 0;
int mode = 0;
for (int pass = 0; pass < size - 1; pass++)
for (int count = pass + 1; count < size; count++) {
if (array[count] > max) {
max = array[count];
mode = 1;
counter = array[pass];
}
cout << "The mode is: " << counter "It's been displayed: " << count << "times" << endl;
}
A solution using map. Compile with g++ -std=c++11 a.cpp.
Here is definition of mode
#include <iostream>
#include <map>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {1, 1, 2, 2, 3, 3};
map<int, int> count;
for (size_t i = 0; i < v.size(); ++i)
count[v[i]]++;
vector<int> mode;
int cnt = 0;
for (map<int, int>::iterator it = count.begin(); it != count.end(); ++it) {
if (it->second > cnt) {
mode.clear();
mode.push_back(it->first);
cnt = it->second;
} else if (it->second == cnt) {
mode.push_back(it->first);
}
}
if (mode.size() * cnt == v.size()) {
cout << "No mode" << endl;
} else {
cout << "mode:";
for (size_t i = 0; i < mode.size(); ++i)
cout << ' ' << mode[i];
cout << endl;
}
return 0;
}
This code uses "map" to find out the MODE from the given array. I hope this solution might help you.
int findMode(int * arr, int size)
{
map<int, int> modeMap;
sort(arr, arr + size);
for (int i = 0; i < size; ++i) {
++modeMap[arr[i]];
}
auto x = std::max_element(modeMap.begin(), modeMap.end(),
[](const pair<int, int>& a, const pair<int, int>& b) {
return a.second < b.second; });
return x->first;
}