I have an array which spans as follows. So the example to understand is consider a block with 6 faces. The array contains the index in this array from which the faces for a particular colour will start.
array[0] 0
array[1] 2
array[2] 4
array[3] 5
so this means that colour 0 is for faces 0 and 1, colour 1 is for faces 2 and 3,
and colour 2 is only for face 4
But the array will not always look like this. if there is a block with just a single colour the array would look like
array[0] 0
array[1] 1
which means face 0 is coloured with 0 color, and faces 1,2,3,4,5 are coloured with color 1
I will get an input as the face number and need to find the corresponding colour
I tried it with a for loop
for (int index = 0; index < array.size(); ++index)
{
if (array[index] == input)
{
return index;
}
if (array[index] < input)
{
return index - 1;
}
}
but the answer is not always correct . Can this be done with while . Please help
As I understand, you want to find the largest index of the array which is less or equal to the given input.
Then you can use the following with binary search.
std::size_t getIndexFor(const std::vector<int>& v, int input)
{
auto it = std::lower_bound(v.begin(), v.end(), input);
if (it != v.begin() && (it == v.end() || *it != input)) {
--it;
}
return std::distance(v.begin(), it);
}
Demo
A simpler (and linear) way:
std::size_t getIndexFor(const std::vector<int>& v, int input)
{
auto it = std::find_if(v.begin(), v.end(), [&](int e){ return e > input;});
if (it == v.begin()) {
throw std::runtime_error("input not handled");
}
--it;
return std::distance(v.begin(), it);
}
Demo
You would just do the same thing, looping through the array to search for the term you want. Of course if it's a sorted array this would be much faster, so something similar to prehaps:
for(int i = 0; i < arraySize; i++){
if(array[i] == itemToFind){
break;
}
}
You are very close to the right solution, just change array[index] < input into array[index] > input:
#include <iostream>
#include <vector>
std::vector<int> array = {0, 2, 4, 5};
int subs(int input)
{
for (int index = 0; index < array.size(); ++index)
{
if (array[index] == input)
{
return index;
}
if (array[index] > input)
{
return index - 1;
}
}
return -1;
}
int main(int argc, const char *argv[])
{
for (int i = 0; i <= 5; i++) {
std::cout<<"input: "<<i<<" "<<"color: "<<subs(i)<<std::endl;
}
return 0;
}
This gives:
input: 0 color: 0
input: 1 color: 0
input: 2 color: 1
input: 3 color: 1
input: 4 color: 2
input: 5 color: 3
I used the for loop also but using break after one if condition that checks if the input equals any element in the array.
#include <iostream>
using namespace std;
int main(){
string arr = " ";
int x;
cout << "Enter your input";
cin >> x;
for (int i =0; i< arr.length(); i++ ){
if (arr[i] == x){
break;
}
}
return 0;
}
Another, maybe simpler solution:
int findIndex( const std::vector<int>& vec, int input )
{
int count = vec.size()-1;
for ( auto it = vec.rbegin(); it != vec.rend(); it++)
{
if ( *it<=input )
{
return count;
}
count--;
}
return -1; // if nothing found
}
int main()
{
std::vector<int> vec { 0,2,4,5 };
for ( int input=0; input <=5; input++)
{
std::cout << findIndex( vec, input ) << " " << input << std::endl;
}
}
Output:
0 0
0 1
1 2
1 3
2 4
3 5
Related
I am doing this particular exercise where I have to implement the Binary Search algorithm which returns the index of the first occurence of an element in a sorted array, if it contains duplicates. Since I am primarily working on my algorithmic skills in C++, I am only trying to do it in C++. Here is my code:
#include <iostream>
#include <cassert>
#include <vector>
using std::vector;
int binary_search(const vector<int> &a, int x, int n) {
int left = 0, right = n-1;
while(left<= right){
int mid = left + (right-left)/2;
if(x== a[mid]){
return mid;
}else if(a[mid]>x){
right = mid-1;
}else{
left = mid+1;
}
}
return -1;
}
int first_occurence(const vector<int>&a, int x, int n) {
int out = binary_search(a, x, n);
if(out !=-1){
for(int i = out;i>0&& a[i]==x;--i ){
out = i;
}
}
return out;
}
int main() {
int n;
std::cin >> n;
vector<int> a(n);
for (size_t i = 0; i < a.size(); i++) {
std::cin >> a[i];
}
int m;
std::cin >> m;
vector<int> b(m);
for (int i = 0; i < m; ++i) {
std::cin >> b[i];
}
for (int i = 0; i < m; ++i) {
std::cout << first_occurence(a, b[i], n) << ' ';
}
}
The first input to the program tells how many items the array should contain, the second is the enumeration of these elements, third line tells how many keys to search for and the final line are the individual keys. The output is the indices for the key or -1 when no such key is found.
My strategy is to use a function to find the index of a key. If it is found, then in case of duplicates, the first occurrence has to have a lower index. That is what the first_occurence() method does; keep looping back till the first occurence is found.
For the following input:
10
1 5 4 4 7 7 7 3 2 2
5
4 7 2 0 6
The output is:
-1 4 -1 -1 -1
Which is only correct for the key 7. I have been trying to debug this for quite some time but I can not figure out the problem.
returns the index of the first occurence of an element in a sorted array,
Your binary search algorithm requires that the data is sorted before you call it.
Example:
#include <algorithm>
#include <sstream>
int main() {
std::istringstream in(R"aw(10
1 5 4 4 7 7 7 3 2 2
5
4 7 2 0 6
)aw");
int n;
in >> n;
vector<int> a(n);
for (auto& v : a) {
in >> v;
}
std::sort(a.begin(), a.end()); // <- add this
// display the sorted result:
for (auto v : a) std::cout << v << ' ';
std::cout << '\n';
int m;
in >> m;
vector<int> b(m);
for (auto& v : b) {
in >> v;
}
for (auto v : b) {
std::cout << v << ' ' << first_occurence(a, v, n) << '\n';
}
}
I have a vector {42.195 42.195 39.025 40.075 34.220 42.195 39.750}. Here I want to get top 3 values just smaller than 42.195. Below is my approach.
I sorted the vector in descending order.
Initialize an output vector and a counter=0.
Then I traversed through the vector and checked if an element is not equal to 42.195. If it is so, increment the counter. If counter value is <= 3, push that element in the output vector. Once the counter value becomes greater than 3, break out of the for loop and return the output vector.
The above approach looks logically fine, but the code is not working fine while comparing each element with 42.195 value. Please help me.
#include<bits/stdc++.h>
#include<vector>
using namespace std;
int validateData(vector<float> &arr){
for(int i = 0 ; i < arr.size() ; i++){
if(arr[i] <= 0.0){
cout<<"\nInvalid data";
return -1;
}
}
return 0;
}
vector <float> getTop3(vector<float>& arr){
if(validateData(arr) == -1)
cout<<"\nCannot perform operation";
else {
vector<float> output;
int count = 0;
cout<<"Sorted values are: \n";
sort(arr.begin(), arr.end(), greater<float>());
for(int i = 0 ; i < arr.size() ; i++){
cout<<arr[i]<<" ";
}
for(int i = 0 ; i < arr.size() ; i++){
if(arr[i] != 42.195) {
count++;
if(count <= 3)
output.push_back(arr[i]);
else
break;
}
}
cout<<"\nOutput vector is\n";
for(int i = 0 ; i < output.size() ; i++){
cout<<output[i]<<" ";
}
return output;
}
}
int main(int argc, char *argv[]){
vector<float> arr;
cout<<"Arguments are:\n";
for(int i = 1 ; i < argc ; i++){
arr.push_back(stof(argv[i]));
}
for(int i = 0 ; i < arr.size() ; i++){
cout<<arr[i]<<" ";
}
cout<<"\n";
//Function call
getTop3(arr);
}
Below is the output.
std::partition followed by std::nth_element can do the job:
std::vector<float> get_top3(std::vector<float> v, float threshold)
{
auto end = std::partition(v.begin(), v.end(), [&](auto f){ return f < threshold; });
if (std::distance(v.begin(), end) <= 3) return {v.begin(), end};
std::nth_element(v.begin(), v.begin() + 3, end, std::greater<>{});
return {v.begin(), v.begin() + 3};
}
int main() {
std::vector<float> arr = {42.195, 42.195, 39.025, 40.075, 34.220, 42.195, 39.750};
for (auto f : get_top3(arr, 42.195))
std::cout << f << " ";
}
Demo
One of your issue is that: 42.195 != 42.195f.
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.
I have an array like this:
600
250
600
600
600
I want to define the begin and the end indexes of this array where the value is greather than 500.
I made a variable which value is 2, because there are two section in my array where the values are greather than 500 (1-1 and 3-5).
So how could I output this:
1 1 3 5
The first 1 means the begin index is 1, the second 1 means the end index is also 1.
The 3 means the next section begin index where the value is greather than 500 is 3.
And the 5 means the end index of the second section is 5.
Using std:
std::vector<std::pair<std::size_t, std::size_t>>
compute_range_greater_than(const std::vector<int>& v, int threshold)
{
std::vector<std::pair<std::size_t, std::size_t>> res;
for (auto it = v.begin(); it != v.end(); /*Empty*/)
{
auto beg = std::find_if(it, v.end(), [=](int i) { return !(i < threshold); });
if (beg == v.end()) {
return res;
}
it = std::find_if(beg, v.end(), [=](int i) { return i < threshold; });
// using 1-index
res.push_back({1 + std::distance(v.begin(), beg), std::distance(v.begin(), it)});
}
return res;
}
Live Demo
Try this:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v;
v.push_back(10);
v.push_back(200);
v.push_back(170);
v.push_back(160);
v.push_back(20);
v.push_back(300);
v.push_back(12);
v.push_back(230);
std::vector<int> indexes;
int limit = 150;
bool started = false;
for (int i = 0; i < v.size(); i++)
{
int value = v[i];
if (value > limit && !started)
{
started = true;
indexes.push_back(i);
}
else if (value < limit && started)
{
started = false;
indexes.push_back(i - 1);
}
}
if (started)
indexes.push_back(v.size() - 1);
for (int i = 0; i < indexes.size(); i++)
{
if (i % 2 == 0)
std::cout << indexes[i] << "-";
else
std::cout << indexes[i] << "; ";
}
return 0;
}
Here limit is 150, but you can change it. Output is
1-3; 5-5; 7-7;
Good luck :)
You really should consider improving your question by better explaining what you want to do and by providing code that you already wrote (and if you didnt you should do it). However, I am in a good mood, so here you go:
#include <vector>
#include <iostream>
struct BeginAndEndIndex{
int begin;
int end;
BeginAndEndIndex(int begin) : begin(begin),end(begin) {}
};
typdef std::vector<BeginAndEndIndex> IndexV;
typdef std::vector<int> IV;
IndexV findBeginAndEndIndex(const IV& in,int threshold){
IndexV result;
bool isBiggerThanThreshold = false;
for (int i=0;i<in.size();i++){
if (!isBiggerThanThreshold) {
if (in[i]>threshold){
result.push_back(BeginAndEndIndex(i));
isBiggerThanThreshold = true;
}
} else {
if (in[i]<threshold){
result.back().end = i-1;
isBiggerThanThreshold = false;
}
}
}
if (isBiggerThanThreshold){result.back().end = in.size()-1;}
return result;
}
int main(void) {
IV foo {600,250,600,600,600};
IndexV bar = findBeginAndEndIndex(foo,500);
for (int i=0;i<bar.size();i++){
std::cout << bar[i].begin << " " << bar[i].end << std::endl;
}
return 0;
}
I am pretty sure that there is a more elegant way to implement it by using std::algorithms.
Just in straight C and not storing the indices anywhere, the following code produces the exact output that you are asking for:
#include <stdio.h>
int main(int argc, char **argv)
{
int values[] = {600, 250, 600, 600, 600};
int threshhold = 500;
int begIndex = -1;
int endIndex = -1;
int i;
for (i = 0; i < sizeof(values)/sizeof(values[0]); i++)
{
if (values[i] > threshhold)
{
if (begIndex < 0)
{
begIndex = i;
}
endIndex = i;
}
else if (begIndex >= 0)
{
printf("%d %d ", begIndex + 1, endIndex + 1);
begIndex = endIndex = -1;
}
}
if (begIndex >= 0)
printf("%d %d", begIndex + 1, endIndex + 1);
printf("\n");
return 0;
}
Keep in mind the arrays in C/C++ start at zero, not one. Changing the above code to store the begIndex and endIndex pairs should be a trivial operation.
I have to find least common number from an int array , I have written code but it is not working properly ,
Here is my logic,
1. sort the array
2. get min common counter updated
3. get if all are unique
and the code below,
static int min_loc ; //minimum value location
static int min_cnt ;
int all_uniqFlag = true;
void leastCommon(int data[],int n)
{
int rcount = 0; //Repeated number counter
int mcount = n; // minimum repetetion counter;
// The array is already sorted we need to only find the least common value.
for(int i = 0 ; i < n-1 ; i++)
{
//Case A : 1 1 2 2 2 3 3 3 3 4 5 5 5 5 : result should be 4
//Case B : 1 2 3 4 5 6 7 (All unique number and common values so all values should be printed
// and )
//Case C : 1 1 2 2 3 3 4 4 (all numbers have same frequency so need to display all )
cout << "data[i] : " << data[i] << " data[i+1] : " << data[i+1] << "i = " << i << endl;
if(data[i] != data[i+1])
{
//mcount = 0;
//min_loc = i;
//return;
}
if(data[i] == data[i+1])
{
all_uniqFlag = false;
rcount++;
}
else if(rcount < mcount)
{
mcount = rcount;
min_loc = i ;//data[i];
}
}
min_cnt = mcount;
}
As mentioned in the comment only Case B works and Case A and C is not working could you help me fix the issue ?
scan through the list
compare each element in the list with the last element in the out array
If the element matches, then increment its count by 1
If the element doesn't match then add the new element into out
array and increment index by 1
Once the scan is done, the out array will have all the distinct elementsout[][0] and their frequencies out[][1]
Scan through the frequency list (out[][1]) to find the lowest frequency
Finally do another scan through the element list out[][0] and print elements whose frequency matches with the lowest frequency
.
#include<stdio.h>
#include<stdlib.h>
#define N 8
int main()
{
//int data[N]={1,2,3,4,5,6,7};
int data[N]={1,1,2,2,3,3,4,4};
//int data[N]={1,1,2,2,2,3,3,3,3,4,5,5,5,5};
int out[N][2];
int i=0,index=0;
for(i=0;i<N;i++)
{
out[i][0]=0;
out[i][1]=0;
}
out[0][0] = data[0];
out[0][1]=1;
for(i=1;i<N;i++)
{
if(data[i] != out[index][0])
{
index++;
out[index][0] = data[i];
out[index][1] = 1;
}
else
{
out[index][1]++;
}
}
int min=65536;
for(i=0;i<N;i++)
{
if(out[i][1] == 0)
{
break;
}
if(out[i][1] < min)
{
min = out[i][1];
}
}
for(i=0;i<N;i++)
{
if(out[i][1] == min)
{
printf("%d\t",out[i][0]);
}
}
printf("\n");
}
You can use a map for this:
#include <string>
#include <map>
#include <iostream>
typedef std::map<int, int> Counter;
void leastCommon(int data[],int n) {
Counter counter;
int min = n;
for (int i = 0; i < n; i++)
counter[data[i]]++;
for (Counter::iterator it = counter.begin(); it != counter.end(); it++) {
if (min > it->second) min = it->second;
}
for (int i = 0; i < n; i++) {
if (counter[data[i]] == min) {
std::cout << data[i] << std::endl;
counter[data[i]]++;
}
}
}
int main() {
int data[] = {1, 1,3,4,4,2,4,3,2};
leastCommon(data, 9);
return 0;
}
Approach is-
select 1st element from the sorted array, and while consecutive elements to it are same, store them in output[] until the loop breaks
store the frequency of element in leastFrequency
select next element, check with its consecutive ones and store them in same output[] until the loop breaks
check frequency of this with the leastFrequency
if same, do nothing (let these be added in the output[])
if less, clear output[] and store the element same no. of times
if more, change the effective output[] length to previous length before iterating for this element
similarly iterate for all distinct elements and finally get the result from output[] from 0 to effective length
void leastCommon(int data[], int len) {
if ( len > 0) {
int output[] = new int[len];
int outlen = 0; // stores the size of useful-output array
int leastFrequency = len; // stores the lowest frequency of elements
int i=0;
int now = data[i];
while (i < len) {
int num = now;
int count = 0;
do {
output[outlen] = now;
outlen++;
count++;
if((++i == len)){
break;
}
now = data[i];
} while (num == now); // while now and next are same it adds them to output[]
if (i - count == 0) { // avoids copy of same values to output[] for 1st iteration
leastFrequency = count;
} else if (count < leastFrequency) { // if count for the element is less than the current minimum then re-creates the output[]
leastFrequency = count;
output = new int[len];
outlen = 0;
for (; outlen < leastFrequency; outlen++) {
output[outlen] = num; // populates the output[] with lower frequent element, to its count
}
} else if (count > leastFrequency) {
outlen -= count; // marks outlen to its same frequent numbers, i.e., discarding higher frequency values from output[]
}
}
//for(int j = 0; j < outlen; j++) {
// print output[] to console
//}
}
}
Plz suggest for improvements.