n choose k implementation with condition - c++

I used the code in this topic
https://stackoverflow.com/a/5097100/3617657
and I edit it little bit to work on std::vector<std::vector<int>> instead std::vector<int>
K in my case has different values (from 1- to 4), instead only one single value
Example: my data
1 2 3 4
1 2 4
1 3
if k=3, Then for each line in my data, n choose k=
123
124
134
234
124
13
but I want my result in map, where the value represents the frequency of subset as:
(123, 1)
(124, 2)
(134, 1)
(234, 1)
(13, 1)
This is my code:
std::vector<std::vector<int>> data;
std::map <int, set<int>> CandidateSet;
typedef std::pair<set<int>, int> combo;
std::map <int, combo> CandidateSup;
void ScanData()
{
ifstream in;
in.open("mydata.txt");
/* mydata.txt
1 2 3 4 5
1 3 4 5
1 2 3 5
1 3
*/
std::string line;
int i = 0;
while (std::getline(in, line))
{
std::stringstream Sline1(line);
std::stringstream ss(line);
std::vector<int> inner;
int info;
while (ss >> info)
inner.push_back(info);
data.push_back(inner);
}
}
int main()
{
ScanData();
std::size_t k = 0;
int j = 0;
int c = 0;
int supp = 1;
int Lsize = 1;
while (Lsize <= 4)
{
for (unsigned i = 0; i < data.size(); ++i)
{
std::vector<int>::iterator items = data[i].begin();
if (Lsize > data[i].size())
k = data[i].size();
else
k = Lsize;
do
{
for (std::vector<int>::iterator items = data[i].begin(); j < k; ++items)
{
CandidateSet[c].insert(*items);
++j;
}
++c;
std::cout << "\n";
j = 0;
}
while (next_combination(data[i].begin(), data[i].begin() + k, data[i].end()));
/******************************************************************************************************************************
//here my problem
// check if the (next_combination) is already exist in CandidateSet, if yes add one to existing support
auto it = CandidateSet.begin();
set <int> A = it->second;
set <int> B;
B = CandidateSet[*items]; // I don't know how to set be as the next_combination
while (it != CandidateSet.end())
{ // if it found
if (!(A < B) && !(B < A))
{
CandidateSup[*items] = std::make_pair(A, ++supp);
break;
}
else
{ // if not found yet
++it;
A = it->second;
}
}// end while
// if it is not exist, add this new set with support =1
++c;
CandidateSup[c] = std::make_pair(B, supp);
/******************************************************************************************************************************/
}
++Lsize;
}
data.clear();
system("PAUSE");
return 0;
}
This "combination.h"
template <typename Iterator>
inline bool next_combination(const Iterator first, Iterator k, const Iterator last)
{
/* Credits: Thomas Draper */
if ((first == last) || (first == k) || (last == k))
return false;
Iterator itr1 = first;
Iterator itr2 = last;
++itr1;
if (last == itr1)
return false;
itr1 = last;
--itr1;
itr1 = k;
--itr2;
while (first != itr1)
{
if (*--itr1 < *itr2)
{
Iterator j = k;
while (!(*itr1 < *j)) ++j;
std::iter_swap(itr1, j);
++itr1;
++j;
itr2 = k;
std::rotate(itr1, j, last);
while (last != j)
{
++j;
++itr2;
}
std::rotate(k, itr2, last);
return true;
}
}
std::rotate(first, k, last);
return false;
}

The following may help: (https://ideone.com/5EPuGd)
std::map<std::set<int>, int> counts;
for (std::size_t Lsize = 1; Lsize <= 4; ++Lsize)
{
for (unsigned i = 0; i < data.size(); ++i)
{
std::size_t k = std::min(Lsize, data[i].size());
do
{
std::set<int> n_k(data[i].begin(), data[i].begin() + k);
++counts[n_k];
}
while (next_combination(data[i].begin(), data[i].begin() + k, data[i].end()));
}
}

Related

Finding majority element in an array ( getting wrong output for particular cases with long integer input)

I was solving a Majority_element problem, where I would be provided an int 'n' followed by an array whose size is n, as input. If any element's frequency in the array is more than n/2, then return 1, otherwise, return 0. Now, my program works correctly for small values of integer elements, but it's giving a false output for bigger int values.
Here's the source code
#include <algorithm>
#include <iostream>
#include <vector>
using std::vector;
int get_majority_element(vector<int> &a) {
int count{};
std::sort(a.begin(),a.end());
for( size_t i{}; i<a.size() ; ++i ){ //counter
for( size_t j = i+1 ; j<a.size() ; ++j ){
if( a.at(i) == a.at(j) ){
count += 1; // may have to inclue a count nullifier if two elements are repeated
}
}
}
if( count > ( a.size()/2 ) ){
return 1;
}
else {
return 0;
}
}
int main() {
int n;
std::cin >> n;
vector<int> a(n);
for (size_t i = 0; i < a.size(); ++i) {
std::cin >> a.at(i);
}
std::cout << get_majority_element(a) << '\n';
return 0;
}
Here are some outputs
6
1 1 1 2 3 4
0
6
1 1 1 1 2 3
1
10
512766168 717383758 5 126144732 5 573799007 5 5 5 405079772
1 ( should be 0)
Now could somebody please explain to me what's going wrong? I even tried setting vector data type to long long to prevent potential memory leaks.
As you do,
you don't need std::sort.
you need to reset count.
check should be done in outer loop
bool get_majority_element(const vector<int> &a) {
for (size_t i{}; i < a.size() ; ++i) {
int count{};
for (size_t j = i+1 ; j<a.size() ; ++j) {
if (a.at(i) == a.at(j)){
count += 1;
}
}
if (count > ( a.size()/2 )) {
return true;
}
}
return false;
}
or
bool get_majority_element(const vector<int> &a) {
for (size_t i{}; i < a.size() ; ++i) {
if (std::count(a.begin() + i, a.end(), a[i]) > a.size() / 2) {
return true;
}
}
return false;
}
Complexity: O(n²).
Once sorted, equal elements are adjacent, so you don't need to check each element:
bool get_majority_element(vector<int> &a) {
std::sort(a.begin(), a.end());
for (auto it = a.begin(); it != a.end(); /*empty*/) {
auto next = std::find_if(it, a.end(), [&](int n){ return n != *it; });
if (std::distance(it, next) > a.size() / 2) {
return true;
}
it = next;
}
return false;
}
Complexity: O(n lon n).
For info, there exist also an algorithm to do it linearly which consist to find possible candidate, and then check it.

Find substring in string from the end

I need to find position of string in substring. Scan has to begin from the end. For example:
findch(L"asdhuifdsahdfasasd", L"asd");
return 16 instead of 1
Here is my function:
int findchr(LPCWSTR T, LPCWSTR P)
{
int n = lstrlenW(T);
int m = lstrlenW(P);
for (int i = 0; i <= n - m; ++i) {
int j = 0;
while (j < m && T[i + j] == P[j]) {
++j;
}
if (j == m) {
return i;
}
}
return -1;
}
You can try using std::string::rfind which does exactly what you want:
Finds the last substring equal to the given character sequence.
Then you can have something like this:
#include <string>
#include <iostream>
std::string::size_type reverse_find(std::string const& str, std::string const& substr) {
return str.rfind(substr);
}
int main() {
auto first = reverse_find("asdhuifdsahdfasasd", "asd");
if (std::string::npos != first) {
std::cout << first << std::endl; // 15
}
auto second = reverse_find("asdhuifdsahdfasasd", "z");
if (std::string::npos != second) {
std::cout << second << std::endl; // won't be outputted
}
return 0;
}
Demo
Above reverse_find function returns 15 because indices start at 0.
int findchr(LPCWSTR str, LPCWSTR substr)
{
int n = lstrlenW(str);
int m = lstrlenW(substr);
for (int i = n; i >= m - n; --i) {
int j = 0;
while (j < m && str[i + j] == substr[j]) {
++j;
}
if (j == m) {
return i;
}
}
return -1;
}

How can I find minimum and unique element of array in c++?

I have array(of numbers) with size N. I need to find minimum element which is unique,so if arr[5] ={1,2,3,1,2}, answer is 3.
I tried that with following code:
Int n = sizeof(arr)/sizeof(arr[0]);
sort(arr,arr + n);
for(int i = 0;i<N;i++){
for(int j = 0;j<N;j++){
if(arr[i] == arr[j]){
remove(arr,arr+n,i);
remove(arr,arr+n,j);
}
}
}
But problem is that this only work if I have 2 identical elements of arr.I could create if conditions for number of identical, but I can have 3 or 4 or 1000,so it will be pretty odd. So what is more elagant way to do this? Thank you in advance.
try this code, this uses an unordered map
int m = 2147483647;
int int_array[] = { 1,2,3,3,1,6,7,7,9 };
unordered_map<int, int> map;
for (int i = 0; i < sizeof(int_array) / sizeof(int_array[0]); i++) {
map[int_array[i]] = map[int_array[i]] + 1;
}
unordered_map<int, int>::iterator itr;
for (itr = map.begin(); itr != map.end(); itr++)
{
if (itr->second == 1) {
if (itr->first < m) {
m = itr->first;
}
}
}
printf("minimum unique is %d", m);
after sorting the array you can count the number of the dublicated members , if the member is unique then its count equals zero :
int main()
{
int arr[] = { 1, 2, 1, 3, 4, 1, 2 };
int n = sizeof(arr) / sizeof(int);
sort(arr, arr + n);
int count = 0;
int unique = -1;
for (int i = 0; unique == -1 && i < n - 1; ++i) {
if (arr[i] != arr[i + 1]) {
if (count==0)
unique = arr[i];
else
count = 0;
}
else {
count++;
}
}
if (count == 0 && unique ==-1)
unique = arr[n-1];
cout << unique;
return 0;
}
I propose the following code:
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int arr[5] = { 1,2,3,2,1 };
int N = sizeof(arr) / sizeof(arr[0]);
sort(arr, arr + N);
int index = -1;
// Check first element is different comparing with second one.
// If the array is only one element, then first element is unique
if (N == 1 || arr[0] != arr[1]) {
index = 0;
}
else {
int i = 1;
while (i < N - 1 && index == -1) {
// Check number is different to previous and different to next value
if (arr[i - 1] != arr[i] && arr[i] != arr[i + 1]) {
index = i;
}
else
{
i++;
}
}
if (index == -1) {
// No found, check last element comparing with previous
if (arr[i - 1] != arr[i]) {
index = i;
}
}
}
if (index != -1) {
// Have found min value
cout << "Min not repeated value is " << arr[index] << endl;
}
else {
// All elements are repeated
cout << "No min value" << endl;
}
}
Once the array is sorted, I compare each value with previous and next value to check it is unique. But for first and last element are a special case.
Using what I said in the comments, with an extra bool.
int arr[] = { 1, 2, 1, 3, 4, 1, 2 };
int n = sizeof( arr ) / sizeof( int );
std::sort( arr, arr + n );
bool match = false;
for ( int i = 0; i < n; ++i ) {
if ( i == n - 1 || arr[i] != arr[i + 1] ) {
if ( match )
match = false;
else
return arr[i];
} else {
match = true;
}
}
return -1; // made up number in case all duplicates
If the two values are equal, then we know that we can't use that value again, so I set match to true. If they are not equal, then if it was already disqualified, I ignore it and set match back to false, otherwise, return that value.
There are more elegant ways to do this; this is just the simplest.

How do I add the value -1 in front of odd numbered elements in a C++ vector, I have problems using the insert function

int main ()
{
vector < int > v;
v = initialize (v);
cout << "Initial Vector: " << endl;
print (v);
cout << "Adding -1 in front of Odds: " << endl;
v = insert_odds(v);
cout << "Final Vector: " << endl;
print(v);
}
double random (unsigned int &seed)
{
const int MODULUS = 15749;
const int MULTIPLIER = 69069;
const int INCREMENT = 1;
seed = ((MULTIPLIER * seed) + INCREMENT) % MODULUS;
return double (seed) / double (MODULUS);
}
vector <int > initialize (vector < int > v)
{
unsigned int seed=2;
for (int i = 0; i < 10; i++)
v.push_back(int (10 + (10 * random (seed))));
return v;
}
void print (vector < int > v)
{
for (int i = 0; i < v.size(); i++)
cout << v[i] << " ";
cout << endl;
}
bool isOdd(int n)
{
return n%2 != 0 && n > 0;
}
vector<int> insert_odds(vector <int> v)
{
std::vector<int>::iterator it = find_if(v.begin(),v.end(),isOdd);
while(it != v.end())
{
it = find_if(v.begin(),v.end(),isOdd);
v.insert(it,-1);
}
return v;
}
This is the code I have.
The vector at the beginning is
17 10 14 16 15 19 19 10 14 18
and I want the output to be
-1 17 10 14 16 -1 15 -1 19 -1 19 10 14 18
As of right now the program runs but doesn't have an output.
If you want to insert new elements into a vector while iterating through it, you have two choices:
make use of the iterator that insert() returns:
vector<int>::iterator iter = myVector.begin();
while (iter != myVector.end())
{
if ((*iter % 2) != 0)
iter = myVector.insert(iter, -1) + 2;
else
++iter;
}
use indexes instead of iterators:
vector<int>::size_type idx = 0;
while (idx < myVector.size())
{
if ((myVector[idx] % 2) != 0)
{
myVector.insert(myVector.begin()+idx, -1);
idx += 2;
}
else
++idx;
}
Use the return value from vector::insert() :
vector<int> v = { 1, 2, 3, 4, 5 };
for (auto it = v.begin(); it != v.end(); it++)
{
if (*it & 1)
{
it = v.insert(it, -1);
it++;
}
}

Count of consecutive numbers in a vector

Suppose I have the following sorted vectors as input:
[22]
[22, 23]
[22, 46]
[22, 46, 47]
[22,23,33,44,45,46,55,56]
I want the following output which shows the count of consecutive numbers in each vector:
1 //edgecase: if there's 1 number it's consecutive)
2 //22, 23 are 2 consecutive numbers
0 //22, 46 not consecutive
2 //46, 47 are 2 consecutive numbers
7 //22,23 (2) 44,45,46 (3) 55,56(2) 7 consecutive numbers
My vector will not have duplicates.
What I have so far is:
vector<int> numbers;
int consecCount=0;
if (numbers.size()==1)
consecCount++;
else{
for (size_t k=1; k<numbers.size(); k++) {
if (numbers[k]==numbers[k-1]+1) {
consecCount +=2;
}
}
Of course this method doesn't work for the last array. The solution seems really wrong.
My actual vectors are really large, so prefer any ideas that does not involve using a another vector
Something like this?
size_t conseccount(const vector<int> &v)
{
size_t s = v.size();
size_t ret = 0;
bool seqstart = true;
if(s < 2) return 0;
for(size_t i = 1; i < s; i++)
{
if(v[i - 1] + 1 == v[i])
{
if(seqstart) ret++;
seqstart = false;
ret++;
}
else seqstart = true;
}
return ret;
}
Expected output
vector question why my query
1 1 22 Is it 1 or 0. // I don't understand why
2 2 22,23
3 0
4 2 46,47
5 7 22,23 44,45,46 55,56
That is count the number of entries which are part of sequences such that a[i] = a[i+1]
The key to this is to ensure you count singly, but add one at the end of a sequence.
You need to check whether you are in a sequence bool bInSequence, which is false initially. When you transition into a sequence, you set it to true.
Then when you leave a sequence, or the loop, you add one.
vector<int> numbers;
int consecCount=0;
if (numbers.size()==1)
consecCount++;
else{
bool inSequence = false;
for (size_t k=1; k<numbers.size(); k++) {
if (numbers[k]==numbers[k-1]+1) {
consecCount +=1;
inSequence = true;
} else if ( inSequence ) {
inSequence = false;
consecCount ++;
}
}
if( inSequence == true ) {
// inSequence = false; //not needed, but logically correct
consecCount ++;
}
}
With std::adjacent_find, you may do something like:
std::size_t count_consecutive_sequence(const std::vector<int> &v)
{
if (v.size() <= 1) {
return v.size();
}
std::size_t res = 0;
for (auto it = v.begin(); it != v.end(); ) {
auto e = std::adjacent_find(it, v.end(),
[](int lhs, int rhs) { return lhs + 1 != rhs; });
if (it == e || it + 1 == v.end()) {
++it;
} else {
if (e != v.end()) {
++e;
}
res += distance(it, e);
it = e;
}
}
return res;
}
Demo