This question already has answers here:
How to find the minimum number of operation(s) to make the string balanced?
(5 answers)
Closed 1 year ago.
I'm trying to write this program that asks for user input of string, my job is to print out the minimum number of steps required to equalize the frequency of distinct characters of the string.
Example
Input
6
aba
abba
abbc
abbbc
codedigger
codealittle
Output
1
0
1
2
2
3
Here is my program:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <unordered_map>
using namespace std;
int main()
{
unordered_map<char, int >m;
vector<int> vec1, vec2;
string s;
int n;
cin >> n;
cin.ignore();
for (int i = 0; i < n; ++i)
{
m.clear();
vec1.clear();
getline(cin, s);
for (int i = 0; i < s.size(); i++)
m[s[i]]++;
for (auto itr : m)
vec1.push_back(itr.second);
sort(vec1.begin(), vec1.end());
int mid = vec1[vec1.size() / 2];
int ans = 0;
for (auto itr : vec1)
ans += abs(mid - itr);
vec2.push_back(ans);
}
for (int i = 0; i < vec2.size(); ++i)
cout << vec2[i] << endl;
}
What I tried to do is for each test case:
Using an unordered_map to count the frequency of the characters of the string.
Push the key values of the map to a vector.
Sort the vector in ascending order.
Calculate the middle element of the vector to equalize the distinct characters with as least steps as possible.
The result will add the difference between the middle element with the current element.
Push the result to another vector and print it.
But my result is wrong at test case number 5:
1
0
1
2
3 // The actual result is 2
3
I don't understand why I get the wrong result, can anyone help me with this? Thanks for your help!
The issue is that your algorithm is not finding the optimal number of steps.
Consider the string you obtained an incorrect answer for: codedigger. It has 4 letters of frequency 1 (coir) and 3 letters of frequency 2 (ddeegg).
The optimal way is not to convert half the letters of frequency 2 into some new character (not present in the string) to make all frequency 1. From my understanding, your implementation is counting the number of steps that this would require.
Instead, consider this:
c[o]dedigge[r]
If I replace o with c and r with i, I obtain:
ccdediggei
which already has equalized character frequencies. You will note that I only performed 2 edits.
So without giving you a solution, I believe this might still answer your question? Perhaps with this in mind, you can come up with a different algorithm that is able to find the optimal number of edits.
Your code correctly measures the frequencies of each letter, as the important information.
But then, there were mainly two issues:
The main target value (final equalized frequency) is not necessarily equal to the median value. In particular, this value must divide the total number of letters
For a given targeted height value, your calculation of the number of steps is not correct. You must pay attention not to count twice the same mutation. Moreover, the general formula is different, depending the final number of different letters is equal, less or higher than the original number of letters.
The following code focuses on correctness, not on efficiency too much. It considers all the possible values of the targeted height (frequency), i.e. all the divisors of the total number of letters.
If efficiency is really a concern (not mentioned in the post), then for example one could consider that the best value is unlikely to be very far from the initial average frequency value.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include <unordered_map>
// calculates the number of steps for a given target
// This code assumes that the frequencies are sorted in descending order.
int n_steps (std::vector<int>& freq, int target, int nchar) {
int sum = 0;
int n = freq.size();
int m = nchar/target; // new number of characters
int imax = std::min (n, m);
for (int i = 0; i < imax; ++i) {
sum += std::abs (freq[i] - target);
}
for (int i = imax; i < n; ++i) {
sum += freq[i];
}
if (m > n) sum += m-n;
sum /= 2;
return sum;
}
int main() {
std::unordered_map<char, int >m;
std::vector<int> vec1, vec2;
std::string s;
int n;
std::cin >> n;
std::cin.ignore();
for (int i = 0; i < n; ++i)
{
m.clear();
vec1.clear();
//getline(cin, s);
std::cin >> s;
for (int i = 0; i < s.size(); i++)
m[s[i]]++;
for (auto itr : m)
vec1.push_back(itr.second);
sort(vec1.begin(), vec1.end(), std::greater<int>());
int nchar = s.size();
int n_min_oper = nchar+1;
for (int target = 1; target <= nchar; ++target) {
if (nchar % target) continue;
int n_oper = n_steps (vec1, target, nchar);
if (n_oper < n_min_oper) n_min_oper = n_oper;
}
vec2.push_back(n_min_oper);
}
for (int i = 0; i < vec2.size(); ++i)
std::cout << vec2[i] << std::endl;
}
Related
i have to find how many other numbers are less than nums[i] and return them in another vector, for example [6,5,4,8] nums[0] = 6 so there is two numbers less than 6. so 2 would be pushed to the other vector. i am not getting 3 when it comes to checking the last element
class Solution {
public:
vector<int> smallerNumbersThanCurrent(vector<int>& nums) {
vector<int> nums2;
for(int i =0; i< nums.size(); ++i){
int max = nums[i];
int count = 0;
for(int j =0; j < nums.size(); ++j){
if(nums[j] < max && j!=0)
count++;
else
continue;
}
nums2.push_back(count);
}
return nums2;
}
};
You exclude the first element when counting in the condition:
if(nums[j] < max && j!=0)
// ^^ ---- remove this
There are algorithms that do want you need. std::transform transforms one range of values to another one and count_if counts how often a predicate returns true for a given range:
#include <vector>
#include <iostream>
#include <algorithm>
std::vector<size_t> count_if_smaller(const std::vector<int>& v) {
std::vector<size_t> result(v.size());
std::transform(v.begin(),v.end(),result.begin(),
[&](int x){
return std::count_if(v.begin(),v.end(),[&](int y){
return y < x;
});
} );
return result;
}
int main() {
std::vector<int> v{6,5,4,8};
auto r = count_if_smaller(v);
for (auto e : r) std::cout << e << " ";
}
One advantage of using algorithms is that you need not bother about indices of single elements. Introducing the same bug as in your code would be more difficult in the above. In other words, using algorithms is less error prone. Consider to use them when you can.
PS: Your current approach has complexity O(N^2). If you sort the input vector you could get O(N log N) easily.
I am writing a code where 2d matrix array is given and by choosing 1 element from each row you must output the smallest sums. Sums as in you must give n number of minimum sums
#include<iostream>
#include<math.h>
using namespace std;
int main() {
int n;
cin>>n;
int hist[n][n];
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>hist[i][j];
}
}
int num=pow(n,n);
int sum[num];
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
sum[i]=sum[i]+hist[i][j];
}
}
for(int i=0;i<n;i++){
cout<<sum[i]<<" ";
}
return 0;
}
example input would be:
3
1 8 5
9 2 5
10 7 6
The output will be
9 10 12
since 1+2+6=9; 1+2+7=10; 1+2+10
The main problem I am facing would be that I can't find the lowest sum or even the sums I tried to brute force it put it won't work.
Could you help me fix the code so that at least I could find the sums?
Many problems with your code (it's not even legal C++). But the problem that is causing your current question is that you must initialise sum to zero. at the moment you have garbage values in sum.
int sum[num] = {0};
Some other issues
int num=pow(n,n);
This calculates n to the power of n, but there are only n squared sums. So this would be better
int sum[n*n] = {0};
But the big issue, the issue that makes your code illegal C++, is that in C++ array dimensions must be compile time constants not variables. So this
int hist[n][n];
and this
int sum[num];
are not legal C++. They are legal in C, which is why your compiler is accepting them, but not every C++ compiler would. Since you are trying to write C++ code you should use a vector. Here's your code rewritten to use vectors.
#include <vector>
using std::vector;
...
vector<vector<int>> hist(n, vector<int>(n));
...
vector<int> sum(num, 0);
...
That's it nothing else needs to change.
Instead of brute forcing, why not realize that the smallest path is simply the smallest element of each row and the second smallest path is the smallest element of the first n-1 rows, and the second smallest element of n.
You can elegantly express this by sorting the rows of the matrix first and then keeping a counter of where you are at each row:
#include <algorithm>
#include <iostream>
#include <vector>
struct path {
path(int n) : n(n), indexes(n) {}
// Add one to last row index, then carry over to previous rows.
path& operator ++() {
indexes.back()++;
for (int i = n-1; i >= 0; i--) {
if (indexes[i] == n) {
indexes[i] = 0;
indexes[i-1]++;
} else {
break;
}
}
return this;
}
int n;
std::vector<int> indexes;
};
Now your problem is as simple as:
int main() {
int n;
cin>>n;
std::vector<std::vector<int>> hist(n, std::vector<int>(n));
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>hist[i][j];
}
// sort each row after reading
std::sort(hist[i].begin(), hist[i].end());
}
int num_minimum_sums = n;
path p(n);
while (num_minimum_sums-- > 0) {
int sum = 0;
for (int i = 0; i < n; i++) {
sum += hist[i][p.indexes[i]];
}
std::cout << sum << std::endl;
++p;
}
}
I am trying to output 9 random non repeating numbers. This is what I've been trying to do:
#include <iostream>
#include <cmath>
#include <vector>
#include <ctime>
using namespace std;
int main() {
srand(time(0));
vector<int> v;
for (int i = 0; i<4; i++) {
v.push_back(rand() % 10);
}
for (int j = 0; j<4; j++) {
for (int m = j+1; m<4; m++) {
while (v[j] == v[m]) {
v[m] = rand() % 10;
}
}
cout << v[j];
}
}
However, i get repeating numbers often. Any help would be appreciated. Thank you.
With a true random number generator, the probability of drawing a particular number is not conditional on any previous numbers drawn. I'm sure you've attained the same number twice when rolling dice, for example.
rand(), which roughly approximates a true generator, will therefore give you back the same number; perhaps even consecutively: your use of % 10 further exacerbates this.
If you don't want repeats, then instantiate a vector containing all the numbers you want potentially, then shuffle them. std::shuffle can help you do that.
See http://en.cppreference.com/w/cpp/algorithm/random_shuffle
When j=0, you'll be checking it with m={1, 2, 3}
But when j=1, you'll be checking it with just m={2, 3}.
You are not checking it with the 0th index again. There, you might be getting repetitions.
Also, note to reduce the chances of getting repeated numbers, why not increase the size of random values, let's say maybe 100.
Please look at the following code to get distinct random values by constantly checking the used values in a std::set:
#include <iostream>
#include <vector>
#include <set>
int main() {
int n = 4;
std::vector <int> values(n);
std::set <int> used_values;
for (int i = 0; i < n; i++) {
int temp = rand() % 10;
while (used_values.find(temp) != used_values.end())
temp = rand() % 10;
values[i] = temp;
}
for(int i = 0; i < n; i++)
std::cout << values[i] << std::endl;
return 0;
}
This question already has answers here:
c++ : dynamic number of nested for loops (without recursion)
(3 answers)
Closed 6 years ago.
I have read the following questions but have not found a solution to my problem:
c++ : dynamic number of nested for loops (without recursion)
variable nested for loops
actual problem statement is :-
Job and Jimmy both are playing with numbers. Job gives Jimmy an array of numbers and asks him to tell the minimum possible last number of a non decreasing sequence of length L.
Input Format
First input line consists of a number which is size of array N.
Next line contains N space separated elements of array.
Next line contains length of the non decreasing sequence i.e. L.
Output Format
You have to print the minimum possible last number of a sequence and if their is no non-decreasing sequence of length L, then print -1
Sample Input
7
9 7 2 5 4 11 12
3
Sample Output
11
Explanation
In sample input, possible non-decreasing sequences of length L=3 are (9,11,12) , (7,11,12) , (2,5,11) , (2,4,11) , (2,5,12) , (2,4,12) , (2,11,12) , (5,11,12) , (4,11,12) and the minimum last number is 11 for the sequences (2,5,11) and (2,4,11). Hence, the answer is 11."
my code...
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int fact(int y,int x)
{
static int temp=0;
if(temp==x)
{
temp=0;
return 1;
}
else
{
++temp;
return y*fact((y-1),x);
}
}
int main() {
int num,randmax,n,s,q,w last=-1, minlast=-1;
cin>>n;
vector<int> a(n);
for(int i=0;i<n; i++)
{
cin>>a[i];
}
cin>>s;
vector<vector<int>> c;
q=fact(s);
c.resize(q);
for(int i = 0 ; i < q ; ++i)
{
//Grow Columns by n
a[i].resize(s);
}
w=q;
randmax=n-1;
int k=0;
while(w)
{
for(int i=0 ; i<n ; i++){
}
num=rand()%randmax; // this works perfect as expected
c[][i]=a[num];
}
w--;
}
/*for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
for(int k=j+1;k<n; k++)
{
if((a[i]<=a[j])&&(a[j]<=a[k]))
{
last=a[k];
if(minlast=-1)
{
minlast=a[k];
}
if(last<minlast){
minlast=last;
}
}
}
}
}
*/
cout<<last;
return 0;
}
`
I would tell you what I tried to do... I thought of mapping the data by having them randomly assigned in one of my array and then computing them..
I got lost somewhere in my code...plz gimme an solution to it...and more imp. a good explanation of the same as I got stuck at times when I need a dynamic nested n loop type of thing...
also it would be more helpful if you edit in my code or algo so that I could learn where my mistakes are there...
Thanks in advance for you time...
As the answers your links have pointed out, you can imitate a dynamic amount of for loops by using an array David gives a fine implementation here.
For the actual problem you gave though, I see no need for a dynamic amount of for loops at all. The problem is a standard non-decreasing subsequence problem with a slight variation.
#include <iostream>
#include <fstream>
int N, L;
int arr[100], seq[100];
int bst;
int main() {
std::ifstream file ("c.txt");
file >> N;
for(int n = 0; n < N; ++n)
file >> arr[n];
file >> L;
file.close();
bst = 1e9;
for(int i = 0; i <= N; ++i) seq[i] = 1e9;
for(int i = 0; i < N; ++i)
{
int x = 0;
while(seq[x] < arr[i]) ++x;
seq[x] = arr[i];
if(x + 1 >= L)
bst = std::min(bst, arr[i]);
}
std::cout << bst << std::endl;
return 0;
}
This code should solve your problem. The first part does standard parsing and initialization. The rest is a variation on the LIS problem, which has several standard algorithms that solve it. Here, we just check that whenever we extend an array of length L or longer, we see if the element is smaller than our current.
I have to sort a vector N into M equals parts(M less than N).
But those equal parts have to be in the middle. If I have parts that are not equal i need to put them in the first and/or last element.Difference between first and last has to be minimal. I have managed to make a sort of that function. Function is making new vector(sizeof(M)) and inside stores number of parts from vector N.
ex. 10/7 vector M [1 1 2 2 2 1 1] 1+1+2+2+2+1+1=10 into 7 parts. Meaning I am taking n or n+1 objects for vector N and storing index in vector M. Values inside do not have to be equal.
Now I am having trouble because my deviations can only be first and last element.
And also i am having problems whit for
ex. 12/9 because i get M[1 1 1 2 2 2 1 1 1 ]
but if I can only have first and last as different
then it should be like M[3 1 1 1 1 1 1 1 2]
So my question : Is there any better way of making this?
#include "stdafx.h"
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int N = 12; // size of vector
int M = 9; // numbers of divisions
static void subsizes(int vecSize, int subCount, vector<int> &v)
{
int baseSize = vecSize / subCount;
int bumps = vecSize % subCount;
int i,n=0,nPlus,counterPlus=0,counterN,counterLeft;
vector<int> temp(subCount); // for new results
vector<int> proba(subCount);
for (i = 0; i < subCount; i++) //dividing to n, n+1 and placing them in vector
{
temp[i]= baseSize + (i < bumps);
}
for (i=0; i<subCount; i++) // finding what numbers are n, n+1
{
nPlus=temp[i];
if(n==0 && n<nPlus){
n=nPlus;}
}
for(i=0; i<subCount;i++) //counting n, n+1
{
if(nPlus==temp[i])counterPlus++;
}
counterN=subCount-counterPlus;
counterLeft=counterPlus-2;
for(i=0; i<counterPlus/2; i++) //placing them in right order
temp[i]=nPlus;
for(i=counterPlus/2; i<counterPlus/2+counterN; i++)
temp[i]=n;
for(i=counterPlus/2+counterN; i<subCount; i++)
temp[i]=nPlus;
cout<<endl<<"Divided vector is :"<<endl; //printing results
for(i=0; i<subCount;i++)
{
int part = temp[i];
cout<<"At : vector["<<i<<"] nubmer of objects is --- "<<part<<endl;
}
putchar('\n');
}
int _tmain(int argc, _TCHAR* argv[])
{
vector<int> vec(N);
int vecSize = vec.size(); //length of original vector
int subCount=M; //number of sub-vectors parts
generate(vec.begin(), vec.end(), rand); // filling vector with C function rand()
cout<<"Vector is [ ";
for (auto i : vec) // printing out a vector
{
cout<<i<<" ";
}
cout<<"]"<<endl;
subsizes(vecSize,subCount,vec); // calling funciton that divideds and print results
system("PAUSE");
return 0;
}
You are complicating this, a lot.
If I understand you correctly
you want to take a vector of size N and divide it into M parts
Each of the M parts should have the same length
If there is remaining elements in N, you want to distribute the remainder to extra sub-parts at the beginning and end
Your output is a vector of the sizes of sub-parts
edit: it seems my assumption of "you want to distribute the remainder to extra sub-parts at the beginning and end" was wrong
If that is indeed what you want then you can just do this
void subsizes(int vecSize, int subCount, vector<int> &v)
{
int regular_size = (vecSize+2) / subCount;
int remainder = vecSize - regular_size * subCount;
vector<int> sizes(subCount, regular_size);
int front_remainder = remainder - (remainder / 2);
int back_remainder = remainder / 2;
sizes.front() += front_remainder;
sizes.back() += back_remainder;
for (int i = 0; i<sizes.size(); i++)
{
int part = sizes[i];
cout << "At : vector[" << i << "] nubmer of objects is --- " << part << endl;
}
putchar('\n');
}
I'm not sure I have a complete grip on your problem, but it appears that you are allowed to change the elements contained in vec. In which case, this is probably what you are looking for:
void subsizes(vector<int>& vec)
{
if(vec.size() > 1) // Don't do anything if there aren't at least 2 elements
{
// Get the sum of all the elements,
// but we're going to be adding back in 1s in every element but the last
// so subtract (vec.size() - 1) from this total.
// This is done by initializing accumulate to 1 - vec.size()
int last = accumulate(vec.begin(), vec.end(), 1 - vec.size());
// Now put 1s in all the elements
fill(vec.begin(), vec.end(), 1);
// Change the last element to the value accumulated in last
vec.back() = last;
}
}