I try to solve this challenge on CodeFights, but, it doesn't work. My best solution got 25/26 (time limit exceeded on the last test) but I deleted that because I tried it yesterday (it was O(n^2)). Now I tried a new one in O(n). I am very tired and I really want to get this done today, so please help me.
Here are the statements:
Given a sequence of integers as an array, determine whether it is possible to obtain a strictly increasing sequence by removing no more than one element from the array.
Example
For sequence = [1, 3, 2, 1], the output should be
almostIncreasingSequence(sequence) = false;
There is no one element in this array that can be removed in order to get a strictly increasing sequence.
For sequence = [1, 3, 2], the output should be
almostIncreasingSequence(sequence) = true.
You can remove 3 from the array to get the strictly increasing sequence [1, 2]. Alternately, you can remove 2 to get the strictly increasing sequence [1, 3].
And here is my code until now... (poor code):
#include <iostream>
#include <vector>
#include <algorithm>
bool almostIncreasingSequence(std::vector<int> sequence)
{
int count = 0;
for(int i = 0; i < sequence.size()-1; i++)
{
if(sequence[i] > sequence[i+1])
{
count++;
sequence.erase(sequence.begin(), sequence.begin() + i);
i--;
}
if(count == 2)
return false;
}
return true;
}
int main()
{
std::cout << std::endl;
return 0;
}
Here is a C++11 solution with O(N) runtime:
constexpr auto Max = std::numeric_limits<std::size_t>::max();
bool is_sorted_but_skip(const std::vector<int>& vec, std::size_t index = Max){
auto Start = index == 0 ? 1 : 0;
auto prev = vec[Start];
for(std::size_t i = Start + 1; i < vec.size(); i++){
if(i == index) continue;
if(prev >= vec[i]) return false;
prev = vec[i];
}
return true;
}
bool almostIncreasingSequence(std::vector<int> v)
{
auto iter = std::adjacent_find(v.begin(), v.end(), [](int L, int R){ return L >= R; });
if(is_sorted_but_skip(v, std::distance(v.begin(), iter)))
return true;
return is_sorted_but_skip(v, std::distance(v.begin(), std::next(iter)));
}
We use std::adjacent_find to find the first element, iter greater than or equal its next element. Then we check that sequence is strictly sorted while skipping iter's position.
Otherwise, we check that the sequence is strictly sorted while we skip iter+1's position
Worse case complexity: 3 linear scan
Demo
Here's a hint (well, almost a solution really):
If you see a decrease between one element to the next, then you have to remove one of them (*).
Now, what if you find two decreases, between two disjoint pairs of elements? That's right :-)
Keeping that in mind, you should be able to solve your problem using a linear scan and a bit of constant-time work.
(*) excluding the first and the last pair of elements.
This is still O(N^2), because you delete the first element of the vector in each iteration. Don't delete the first element and don't i-- in the loop.
If you must erase the numbers (you don't, but still), at least do it from the end of the list. That way erasing a number is probably an O(1) operation (I'm not 100% sure that's how std::vector is implemented).
You really don't have to erase the numbers.
#include<iostream>
#include<vector>
using namespace std;
int almostIncreasingSequence( vector<int> sequence );
int main(){
int array[] = {40, 50, 60, 10, 20, 30};
std::vector<int> vect (array, array + sizeof(array) / sizeof(int) );
bool ret = almostIncreasingSequence(vect);
if( ret ){
std::cout<<"Array is strictly increasing.";
}
else{
std::cout<<"Array is not strictly increasing.";
}
return 0;
}
bool almostIncreasingSequence(std::vector<int> sequence) {
int val = 0;
int currentBig = sequence.at(0);
for (int i = 1; i < sequence.size(); i++){
if( currentBig < sequence.at(i))
{
currentBig = sequence.at(i);
}
else{
val++;
if( val>1)
{
return false;
}
if( i > 1 ){
if (sequence.at(i) > sequence.at(i-2)){
if( currentBig < sequence.at(i) ){
}
else{
currentBig = sequence.at(i);
}
}
}
else{
currentBig = sequence.at(i);
}
}
}
return true;
}
Related
Input: int arr[] = {10, 20, 20, 30, 40, 40, 40, 50, 50}
Output: 10, 30
My code:
int removeDup(int arr[], int n)
{
int temp;
bool dupFound = false;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(arr[i] == arr[j]){
if(!dupFound){
temp = arr[i];
dupFound = true;
}
else{
arr[i] = temp;
}
}
}
}
//shift here
}
First of all, I don't know if this is the most efficient way of doing this.
I'm trying to find the first duplicate element, assign it to every duplicate element and shift them to the end of the array, which doesn't work because the last duplicate element cannot be compared.
I need some help with finding the last duplicate element, so I can assign temp to it.
I do not understand the logic of your code. When you find the second element arr[j] that equals arr[i] you will assign temp to arr[i]. However, temp has been assigned arr[i] when you found the first duplicate. Essentially you do arr[i] = arr[i]. Its not clear how this is supposed to find unique elements.
You can use a map to count frequency of elements, then print those with frequency 1:
#include <unordered_map>
#include <iostream>
int main()
{
std::unordered_map<int,size_t> freq;
int arr[] = {10, 20, 20, 30, 40, 40, 40, 50, 50};
// count frequencies
for (auto e : arr) { ++freq[e]; }
// print the elements e where freq[e] == 1
for (const auto& f : freq) {
if (f.second == 1) {
std::cout << f.first << "\n";
}
}
}
Only small modifications needed to add the unique elements to a vector.
Instead of trying to do everything at once, let us focus on correctness first:
int removeDup(int* arr, int n) {
// Note: No i++! This depends on whether we find a duplicate.
for (int i = 0; i < n;) {
int v = arr[i];
bool dupFound = false;
for (int j = i+1; j < n; j++) {
if (v == arr[j]) {
dupFound = true;
break;
}
}
if (!dupFound) {
i++;
continue;
}
// Copy values to the sub-array starting at position i,
// skipping all values equal to v.
int write = i, skipped = 0;
for (int j = i; j < n; j++) {
if (arr[j] != v) {
arr[write] = arr[j];
write++;
} else {
skipped++;
}
}
// The previous loop duplicated some non-v elements.
// We decrease n to make sure these duplicates are not
// considered in the output
n -= skipped;
}
return n;
}
Let's start with logistics (so to speak). An array always contains a fixed number of items. There's simply no way to start with an array of 5 items, and turn it into an array of 2 items. Simply can't be done.
So, as a starting point, you need to either return something like an std::vector that keeps track of its size along with the data it contains, or else you're going to need to track the size, and return something to indicate how many elements in the array are valid after the processing.
Probably the simplest way to do things would be to use something like an std::unoredered_map to count the items, then walk through the map, and insert an item in the output if (and only if) its count is 1.
std::unordered_map<int, std::size_t> counts;
for (int i=0;i<n; i++)
++counts[arr[i]];
std::vector<int> output;
for (auto item : counts)
if (item.second == 1)
output.push_back(item.first);
return output;
If you want to modify the data in place, I'd start by sorting the input data. Then you'll start with two indices: one for your "input" position, and one for your "output" position. output starts as zero, and input as 1.
The general idea from there is pretty simple: we look at data[input] and see if it's different from both the preceding and succeeding elements. If so, we copy it to data[output], and increment the output position.
Since this tries to look at both the preceding and succeeding elements, we have to include special cases for the beginning and end of the array. The first element is unique if it's different from the following, and the end is unique if it's different from the preceding. Code can look like this:
#include <algorithm>
#include <iostream>
unsigned remove_dupe(int *data, unsigned n) {
if (n < 2) {
return n;
}
std::sort(data, data+n);
unsigned output = data[0] != data[1];
for (unsigned input = output+1; input<n-1; input++)
if (data[input] != data[input-1] && data[input] != data[input+1])
data[output++] = data[input];
if (data[n-1] != data[n-2]) {
data[output++] = data[n-1];
}
return output;
}
template <class T, std::size_t N>
void test(T (&arr)[N]) {
unsigned end = remove_dupe(arr, N);
for (int i=0; i<end; i++)
std::cout << arr[i] << "\t";
std::cout << "\n";
}
int main() {
int arr0[] = {10, 20, 20, 30, 40, 40, 40, 50, 50};
int arr1[] = { 1, 2};
int arr2[] = { 1, 1};
test(arr0);
test(arr1);
test(arr2);
}
Result:
10 30
1 2
Another option that might be available is to sort() the array. When this is done, all duplicate values throughout the array are now adjacent. You simply compare element [n] with element [n+1] to see if they are the same. You can now find and count all duplicates in a single linear pass through the sorted array.
Sorting is one of the most heavily-studied class of algorithms in computer science, and very efficient processes can be developed which rely upon things being sorted a certain way.
I wrote this code in C++ as part of a uni task where I need to ensure that there are no duplicates within an array:
// Check for duplicate numbers in user inputted data
int i; // Need to declare i here so that it can be accessed by the 'inner' loop that starts on line 21
for(i = 0;i < 6; i++) { // Check each other number in the array
for(int j = i; j < 6; j++) { // Check the rest of the numbers
if(j != i) { // Makes sure don't check number against itself
if(userNumbers[i] == userNumbers[j]) {
b = true;
}
}
if(b == true) { // If there is a duplicate, change that particular number
cout << "Please re-enter number " << i + 1 << ". Duplicate numbers are not allowed:" << endl;
cin >> userNumbers[i];
}
} // Comparison loop
b = false; // Reset the boolean after each number entered has been checked
} // Main check loop
It works perfectly, but I'd like to know if there is a more elegant or efficient way to check.
You could sort the array in O(nlog(n)), then simply look until the next number. That is substantially faster than your O(n^2) existing algorithm. The code is also a lot cleaner. Your code also doesn't ensure no duplicates were inserted when they were re-entered. You need to prevent duplicates from existing in the first place.
std::sort(userNumbers.begin(), userNumbers.end());
for(int i = 0; i < userNumbers.size() - 1; i++) {
if (userNumbers[i] == userNumbers[i + 1]) {
userNumbers.erase(userNumbers.begin() + i);
i--;
}
}
I also second the reccomendation to use a std::set - no duplicates there.
The following solution is based on sorting the numbers and then removing the duplicates:
#include <algorithm>
int main()
{
int userNumbers[6];
// ...
int* end = userNumbers + 6;
std::sort(userNumbers, end);
bool containsDuplicates = (std::unique(userNumbers, end) != end);
}
Indeed, the fastest and as far I can see most elegant method is as advised above:
std::vector<int> tUserNumbers;
// ...
std::set<int> tSet(tUserNumbers.begin(), tUserNumbers.end());
std::vector<int>(tSet.begin(), tSet.end()).swap(tUserNumbers);
It is O(n log n). This however does not make it, if the ordering of the numbers in the input array needs to be kept... In this case I did:
std::set<int> tTmp;
std::vector<int>::iterator tNewEnd =
std::remove_if(tUserNumbers.begin(), tUserNumbers.end(),
[&tTmp] (int pNumber) -> bool {
return (!tTmp.insert(pNumber).second);
});
tUserNumbers.erase(tNewEnd, tUserNumbers.end());
which is still O(n log n) and keeps the original ordering of elements in tUserNumbers.
Cheers,
Paul
It is in extension to the answer by #Puppy, which is the current best answer.
PS : I tried to insert this post as comment in the current best answer by #Puppy but couldn't so as I don't have 50 points yet. Also a bit of experimental data is shared here for further help.
Both std::set and std::map are implemented in STL using Balanced Binary Search tree only. So both will lead to a complexity of O(nlogn) only in this case. While the better performance can be achieved if a hash table is used. std::unordered_map offers hash table based implementation for faster search. I experimented with all three implementations and found the results using std::unordered_map to be better than std::set and std::map. Results and code are shared below. Images are the snapshot of performance measured by LeetCode on the solutions.
bool hasDuplicate(vector<int>& nums) {
size_t count = nums.size();
if (!count)
return false;
std::unordered_map<int, int> tbl;
//std::set<int> tbl;
for (size_t i = 0; i < count; i++) {
if (tbl.find(nums[i]) != tbl.end())
return true;
tbl[nums[i]] = 1;
//tbl.insert(nums[i]);
}
return false;
}
unordered_map Performance (Run time was 52 ms here)
Set/Map Performance
You can add all elements in a set and check when adding if it is already present or not. That would be more elegant and efficient.
I'm not sure why this hasn't been suggested but here is a way in base 10 to find duplicates in O(n).. The problem I see with the already suggested O(n) solution is that it requires that the digits be sorted first.. This method is O(n) and does not require the set to be sorted. The cool thing is that checking if a specific digit has duplicates is O(1). I know this thread is probably dead but maybe it will help somebody! :)
/*
============================
Foo
============================
*
Takes in a read only unsigned int. A table is created to store counters
for each digit. If any digit's counter is flipped higher than 1, function
returns. For example, with 48778584:
0 1 2 3 4 5 6 7 8 9
[0] [0] [0] [0] [2] [1] [0] [2] [2] [0]
When we iterate over this array, we find that 4 is duplicated and immediately
return false.
*/
bool Foo(int number)
{
int temp = number;
int digitTable[10]={0};
while(temp > 0)
{
digitTable[temp % 10]++; // Last digit's respective index.
temp /= 10; // Move to next digit
}
for (int i=0; i < 10; i++)
{
if (digitTable [i] > 1)
{
return false;
}
}
return true;
}
It's ok, specially for small array lengths. I'd use more efficient aproaches (less than n^2/2 comparisons) if the array is mugh bigger - see DeadMG's answer.
Some small corrections for your code:
Instead of int j = i writeint j = i +1 and you can omit your if(j != i) test
You should't need to declare i variable outside the for statement.
I think #Michael Jaison G's solution is really brilliant, I modify his code a little to avoid sorting. (By using unordered_set, the algorithm may faster a little.)
template <class Iterator>
bool isDuplicated(Iterator begin, Iterator end) {
using T = typename std::iterator_traits<Iterator>::value_type;
std::unordered_set<T> values(begin, end);
std::size_t size = std::distance(begin,end);
return size != values.size();
}
//std::unique(_copy) requires a sorted container.
std::sort(cont.begin(), cont.end());
//testing if cont has duplicates
std::unique(cont.begin(), cont.end()) != cont.end();
//getting a new container with no duplicates
std::unique_copy(cont.begin(), cont.end(), std::back_inserter(cont2));
#include<iostream>
#include<algorithm>
int main(){
int arr[] = {3, 2, 3, 4, 1, 5, 5, 5};
int len = sizeof(arr) / sizeof(*arr); // Finding length of array
std::sort(arr, arr+len);
int unique_elements = std::unique(arr, arr+len) - arr;
if(unique_elements == len) std::cout << "Duplicate number is not present here\n";
else std::cout << "Duplicate number present in this array\n";
return 0;
}
As mentioned by #underscore_d, an elegant and efficient solution would be,
#include <algorithm>
#include <vector>
template <class Iterator>
bool has_duplicates(Iterator begin, Iterator end) {
using T = typename std::iterator_traits<Iterator>::value_type;
std::vector<T> values(begin, end);
std::sort(values.begin(), values.end());
return (std::adjacent_find(values.begin(), values.end()) != values.end());
}
int main() {
int user_ids[6];
// ...
std::cout << has_duplicates(user_ids, user_ids + 6) << std::endl;
}
fast O(N) time and space solution
return first when it hits duplicate
template <typename T>
bool containsDuplicate(vector<T>& items) {
return any_of(items.begin(), items.end(), [s = unordered_set<T>{}](const auto& item) mutable {
return !s.insert(item).second;
});
}
Not enough karma to post a comment. Hence a post.
vector <int> numArray = { 1,2,1,4,5 };
unordered_map<int, bool> hasDuplicate;
bool flag = false;
for (auto i : numArray)
{
if (hasDuplicate[i])
{
flag = true;
break;
}
else
hasDuplicate[i] = true;
}
(flag)?(cout << "Duplicate"):("No duplicate");
I've written some code to find a desired sub-array within a larger array and replace it with a different sub-array of the same length.
e.g.:
int array[] = {1,2,3,4,1,2,3,4};
int find[] = {1,2,3};
int replace[] = {7,8,9};
replaceSubArray(array, 8, find, replace, 3);
And replaceSubArray modifies 'array' to contain {7,8,9,4,7,8,9,4}
My function looks like this:
void replaceSubArray(char* longArray, int longLength, char* find, char* replace, int shortLength) {
int findIndex = 0, replaceIndex = 0;
for (int i = 0; i < longLength; ++i) //loop through larger array
{
if (longArray[i] == find[findIndex]) //if we find a match for an element
{
if (++findIndex == shortLength) //increment the findIndex and see if the entire subarray has been found in the larger array
{
for (int j = i - (shortLength - 1); j <= i; ++j) //entire array has been matched so go back to start of the appearance of subarray in larger array
{
longArray[j] = replace[replaceIndex]; //replace the matched subarray with the contents of replace[]
replaceIndex++;
}
replaceIndex = 0; //reset replaceIndex and findIndex to 0 so we can restart the search for more subarray matches
findIndex = 0;
}
} else { //if an element wasn't matched, reset findIndex to 0 to restart the search for subarray matches
findIndex = 0;
}
replaceIndex = 0;
}
}
It works fine but I am a beginner programmer and was curious if there is any better way to do this? Or if there are any built in functions that would help.
Use standard algorithms. You have
int array[] = {1,2,3,4,1,2,3,4};
int find[] = {1,2,3};
int replace[] = {7,8,9};
then you can use (requires #include <algorithm>, #include <iterator>)
using std::begin, std::end;
auto it = begin(array);
for (;;) {
it = std::search(it, end(array), begin(find), end(find));
if (it == end(array))
break;
it = std::copy(begin(replace), end(replace), it);
}
(live demo)
You can also use the Boyer-Moore searcher: (requires #include <functional>)
using std::begin, std::end;
auto searcher = std::boyer_moore_searcher(begin(find), end(find));
auto it = begin(array);
for (;;) {
it = std::search(it, end(array), searcher);
if (it == end(array))
break;
it = std::copy(begin(replace), end(replace), it);
}
(live demo)
Whether or not this will improve performance depends on a lot of factors, so profile.
To replace just the first occurence:
#include <string.h>
void replaceSubArray(int* longArray, int longLength, int* find, int* replace, int shortLength)
{
int i, k = 0;
for (i = 0 ; i < longLength ; ++i)
{
if (longArray[i] == find[k++])
{
if ( k == shortLength )
{
memcpy(longArray + i + 1 - k, replace, sizeof(int) * shortLength);
break;
}
continue;
}
k = 0;
}
}
To replace all occurences:
#include <string.h>
void replaceSubArray(int* longArray, int longLength, int* find, int* replace, int shortLength)
{
int i, k = 0;
for (i = 0 ; i < longLength ; ++i)
{
if (longArray[i] == find[k++])
{
if ( k == shortLength )
memcpy(longArray + i + 1 - k, replace, sizeof(int) * shortLength);
else
continue;
}
k = 0;
}
}
In C I would prefer this way.
PS: The question was tagged with C too before. Noticed that just now that C tag has been removed. Still posted in case if it helps.
If the elements in your find-array are all different, you could in most cases skip some indexes in your else-case:
replace:
else { //if an element wasn't matched, reset findIndex to 0 to restart the search for subarray matches
findIndex = 0;
}
with
else { //if an element wasn't matched, reset findIndex to 0 to restart the search for subarray matches
findIndex = 0;
i+=find.length-findIndex; // there could not be a match starting before this index.
}
If not all entries in your find-index are different you could use a similar (more complicated) approach. See Knuth–Morris–Pratt algorithm
Using memcpy instead of a loop to make the actual replace should also speed things up a bit.
Hint:
Always profile each change to see if, and in which extend, the change improved the performance.
Here is the sample code in which I used std::vector and few already present feature of c++
#include<stdio.h>
#include<iostream>
#include<vector>
#include<algorithm>
int main () {
std::vector<int> vect1 = {1,2,3,4,5};
std::vector<int> find = {3,4,5};
std::vector<int> replace = {5,6,7};
auto it = std::search(vect1.begin(),vect1.end(),find.begin(),find.end()); // Finds sub array in main vect1
int i = 0;
while ((it != vect1.end()) && (i< replace.size())) {
*it = replace[i]; // replace each elements on by one start from searched index from std::search
i++; //iterate replace vector
it++; //iterate main vector
}
return 0;
}
I have created a function that creates all the possible solutions for a game that I am creating... Maybe some of you know the bullcow game.
First I created a function that creates a combination of numbers of max four integers and the combination can't have any repeating number in it... like...
'1234' is a solution but not '1223' because the '2' is repeating in the number. In total there is 5040 numbers between '0123' and '9999' that haven't repeating numbers.
Here is my function:
std::vector <std::array<unsigned, 4>> HittaAllaLosningar(){
std::vector <std::array<unsigned, 4>> Losningar;
for (unsigned i = 0; i < 10; i++) {
for (unsigned j = 0; j < 10; j++) {
for (unsigned k = 0; k < 10; k++) {
for (unsigned l = 0; l < 10; l++) {
if (i != j && i != k && i != l && j != k && j != l && k != l) {
Losningar.push_back({i,j,k,l});
}
}
}
}
}
return Losningar;
}
Now let's say I have the number '1234' and that is not the solution I am trying to find, I want to remove the solution '1234' from the array since that isn't a solution... how do I do that? have been trying to find for hours and can't find it. I have tried vector.erase but I get errors about unsigned and stuff... also its worth to mention the guesses are in strings.
What I am trying to do is, to take a string that I get from my program and if it isn't a solution I want to remove it from the vector if it exists in the vector.
Here is the code that creates the guess:
std::string Gissning(){
int random = RandomGen();
int a = 0;
int b = 0;
int c = 0;
int d = 0;
for (unsigned i = random-1; i < random; i++) {
for (unsigned j = 0; j < 4; j++) {
if (j == 0) {
a = v[i][j];
}
if (j == 1) {
b = v[i][j];
}
if (j == 2) {
c = v[i][j];
}
if (j == 3) {
d = v[i][j];
}
}
std::cout << std::endl;
AntalTry++;
}
std::ostringstream test;
test << a << b << c << d;
funka = test.str();
return funka;
}
The randomgen function is just a function so I can get a random number and then I go in the loop so I can take the element of the vector and then I get the integers of the array.
Thank you very much for taking your time to help me, I am very grateful!
You need to find the position of the element to erase.
std::array<unsigned, 4> needle{1, 2, 3, 4};
auto it = std::find(Losningar.begin(), Losningar.end(), needle);
if (it != Losningar.end()) { Losningar.erase(it); }
If you want to remove all the values that match, or you don't like checking against end, you can use std::remove and the two iterator overload of erase. This is known as the "erase-remove" idiom.
std::array<unsigned, 4> needle{1, 2, 3, 4};
Losningar.erase(std::remove(Losningar.begin(), Losningar.end(), needle), Losningar.end());
To erase from a vector you just need to use erase and give it an iterator, like so:
std::vector<std::array<unsigned, 4>> vec;
vec.push_back({1,2,3,4});
vec.push_back({4,3,2,1});
auto it = vec.begin(); //Get an iterator to first elements
it++; //Increment iterator, it now points at second element
it = vec.erase(it); // This erases the {4,3,2,1} array
After you erase the element, it is invalid because the element it was pointing to has been deleted. Ti continue to use the iterator you can take the return value from the erase function, a valid iterator to the next element after the one erased, in this the case end iterator.
It is however not very efficient to remove elements in the middle of a vector, due to how it works internally. If it's not important in what order the different solution are stored, a small trick can simplify and make your code faster. Let's say we have this.
std::vector<std::array<unsigned, 4>> vec;
vec.push_back({1,2,3,4});
vec.push_back({4,3,2,1});
vec.push_back({3,2,1,4});
To remove the middle one we then do
vec[1] = vec.back(); // Replace the value we want to delete
// with the value in the last element of the vector.
vec.pop_back(); //Remove the last element
This is quite simple if you have ready other functions:
using TestNumber = std::array<unsigned, 4>;
struct TestResult {
int bulls;
int cows;
}
// function which is used to calculate bulls and cows for given secred and guess
TestResult TestSecretGuess(const TestNumber& secret,
const TestNumber& guess)
{
// do it your self
… … …
return result;
}
void RemoveNotMatchingSolutions(const TestNumber& guess, TestResult result)
{
auto iter =
std::remove_if(possibleSolutions.begin(),
possibleSolutions.end(),
[&guess, result](const TestNumber& possibility)
{
return result == TestSecretGuess(possibility, guess);
});
possibleSolutions.erase(iter, possibleSolutions.end());
}
Disclaimer: it is possible to improve performance (you do not care about order of elements).
So for an assignment I've been asked to create a function that will generate an array of fibonacci numbers and the user will then provide an array of random numbers. My function must then check if the array the user has entered contains any fibonacci numbers then the function will output true, otherwise it will output false. I have already been able to create the array of Fib numbers and check it against the array that the user enters however it is limited since my Fib array has a max size of 100.
bool hasFibNum (int arr[], int size){
int fibarray[100];
fibarray[0] = 0;
fibarray[1] = 1;
bool result = false;
for (int i = 2; i < 100; i++)
{
fibarray[i] = fibarray[i-1] + fibarray[i-2];
}
for (int i = 0; i < size; i++)
{
for(int j = 0; j < 100; j++){
if (fibarray[j] == arr[i])
result = true;
}
}
return result;
}
So basically how can I make it so that I don't have to use int fibarray[100] and can instead generate fib numbers up to a certain point. That point being the maximum number in the user's array.
So for example if the user enters the array {4,2,1,8,21}, I need to generate a fibarray up to the number 21 {1,1,2,3,5,8,13,21}. If the user enters the array {1,4,10} I would need to generate a fibarray with {1,1,2,3,5,8,13}
Quite new to programming so any help would be appreciated! Sorry if my code is terrible.
It is possible that I still don't understand your question, but if I do, then I would achieve what you want like this:
bool hasFibNum (int arr[], int size){
if (size == 0) return false;
int maxValue = arr[0];
for (int i = 1; i < size; i++)
{
if (arr[i] > maxValue) maxValue = arr[i];
}
int first = 0;
int second = 1;
while (second < maxValue)
{
for (int i = 0; i < size; i++)
{
if (arr[i] == first) return true;
if (arr[i] == second) return true;
}
first = first + second;
second = second + first;
}
return false;
}
Here is a function that returns a dynamic array with all of the Fibonacci numbers up to and including max (assuming max > 0)
std::vector<size_t> make_fibs( size_t max ) {
std::vector<size_t> retval = {1,1};
while( retval.back() < max ) {
retval.push_back( retval.back()+*(retval.end()-2) );
}
return retval;
}
I prepopulate it with 2 elements rather than keeping track of the last 2 separately.
Note that under some definitions, 0 and -1 are Fibonacci numbers. If you are using that, start the array off with {-1, 0, 1} (which isn't their order, it is actually -1, 1, 0, 1, but by keeping them in ascending order we can binary_search below). If you do so, change the type to an int not a size_t.
Next, a sketch of an implementation for has_fibs:
template<class T, size_t N>
bool has_fibs( T(&array)[N] ) {
// bring `begin` and `end` into view, one of the good uses of `using`:
using std::begin; using std::end;
// guaranteed array is nonempty, so
T m = *std::max_element( begin(array), end(array) ); will have a max, so * is safe.
if (m < 0) m = 0; // deal with the possibility the `array` is all negative
// use `auto` to not repeat a type, and `const` because we aren't going to alter it:
const auto fibs = make_fibs(m);
// d-d-d-ouble `std` algorithm:
return std::find_if( begin(array), end(array), [&fibs]( T v )->bool {
return std::binary_search( begin(fibs), end(fibs), v );
}) != end(array);
}
here I create a template function that takes your (fixed sized) array as a reference. This has the advantage that ranged-based loops will work on it.
Next, I use a std algorithm max_element to find the max element.
Finally, I use two std algorithms, find_if and binary_search, plus a lambda to glue them together, to find any intersections between the two containers.
I'm liberally using C++11 features and lots of abstraction here. If you don't understand a function, I encourage you to rewrite the parts you don't understand rather than copying blindly.
This code has runtime O(n lg lg n) which is probably overkill. (fibs grow exponentially. Building them takes lg n time, searching them takes lg lg n time, and we search then n times).