I have one array like {7, 3, 1, 5, 2} for example. I want to get a max value from one index onwards, so the result should be like {7, 5, 5, 5, 2}. I just use a for loop like below. It throws strange heap overflow problem.
int maxProfit(vector<int>& prices) {
vector<int> maxRight;
int runningMax = 0;
for(auto i=(prices.size()-1);i>=0;i--){
if(runningMax < prices[i]){
runningMax = prices[i];
}
maxRight.push_back(runningMax);
}
maxRight.push_back(runningMax);
std::reverse(maxRight.begin(), maxRight.end());
......
But if i change to the below code, it works. Isn't the below code the same as the above one? I just changed the comparison of the index i to 0 or to 1.
int maxProfit(vector<int>& prices) {
vector<int> maxRight;
int runningMax = 0;
for(auto i=(prices.size()-1);i>=1;i--){
if(runningMax < prices[i]){
runningMax = prices[i];
}
maxRight.push_back(runningMax);
}
if(runningMax < prices[0]){
runningMax=prices[0];
}
std::reverse(maxRight.begin(), maxRight.end());
......
As was pointed out in a comment,
auto i=(prices.size()-1) , i is deduced to be unsigned value, and the condition i >= 0 is always true. You have accessing out of bounds of array.
Instead of using an index, use an iterator, in this case a std::vector::reverse_iterator.
for(auto it = prices.rbegin(); it != prices.rend(); ++it)
{
if(runningMax < *it)
{
runningMax = *it;
}
maxRight.push_back(runningMax);
}
As the variable i declared in the for loop
for(auto i=(prices.size()-1);i>=0;i--){
has the unsigned integer type std::vector<int>::size_type then you will get an infinite loop because when i is equal to 0 then the expression i-- will afain produces a non-negative number.
Another problem is that the for loop will again invoke undefined behavior if the passed vector is empty dues to the initialization in the declaration part of the for loop
auto i=(prices.size()-1)
because prices.size()-1 produces a positive value in this case.
In the second function implementation you forgot to push a calculated value for the first element of the vector prices. You just wrote after the loop
if(runningMax < prices[0]){
runningMax=prices[0];
}
that does not make a great sense.
`
You could write a separate function that returns the desired vector of maximum prices.
Here is a demonstrative program.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
std::vector<int> max_prices( const std::vector<int> &prices )
{
std::vector<int> maxRight;
maxRight.reserve( prices.size() );
for ( auto first = std::rbegin( prices), last = std::rend( prices );
first != last;
++first )
{
if ( maxRight.empty() )
{
maxRight.push_back( *first );
}
else
{
maxRight.push_back( std::max( maxRight.back(), *first ) );
}
}
std::reverse( std::begin( maxRight ), std::end( maxRight ) );
return maxRight;
}
int main()
{
std::vector<int> prices = { 7, 3, 1, 5, 2 };
auto maxRight = max_prices( prices );
for ( const auto &price : maxRight )
{
std::cout << price << ' ';
}
std::cout << '\n';
return 0;
}
The program output is
7 5 5 5 2
Related
I am trying to remove the duplicates from sorted array.Code is giving correct output for one test case but fails to give correct output for multiple test cases.I am getting correct output with other methods but what is wrong with this method? How can I solve this problem?
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int main() {
// your code goes here
int t;
cin>>t;
while(t--){
int n;
cin>>n;
int a[n],i,k,temp,count;
for(i=0;i<n;i++){
cin>>a[i];
}
sort(a,a+n);
count=0;
for(i=0;i<n;i++){
if(a[i-1]-a[i]==0){
temp = a[i];
count++;
for(k=i;k<n;k++){
a[k] = a[k+1];
}
}
}
for(i=0;i<n-count;i++){
cout<<a[i]<<" ";
}
cout<<endl;
}
}
Variable length arrays like this
int a[n],i,k,temp,count;
is not a standard C++ feature. Instead you should use the standard container std::vector<int>.
This if statement
if(a[i-1]-a[i]==0){
invokes undefined behavior when i is equal to 0 due to the expression a[i-1].
The same problem exists in this for loop
for(k=i;k<n;k++){
a[k] = a[k+1];
}
when k is equal to n - 1 due to the expression a[k+1].
Also it is inefficient to copy all elements after the found duplicated element each time when such an element is found.
Pay attention to that there is the standard algorithm std::unique that can be used instead of your loops.
If to use the for loop then you may implement something like the following
#include <iostream>
int main()
{
int a[] = { 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5 };
const size_t N = sizeof( a ) / sizeof( *a );
size_t n = 0;
for ( size_t i = 0; i < N; i++ )
{
if ( i == 0 || a[i] != a[n-1] )
{
if ( i != n ) a[n] = a[i];
++n;
}
}
for ( size_t i = 0; i < n; i++ )
{
std::cout << a[i] << ' ';
}
std::cout << '\n';
return 0;
}
The program output is
1 2 3 4 5
If to use the standard algorithm std::unique then the solution will be simpler because there is no need to write your own for loop.
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
int a[] = { 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5 };
auto last = std::unique( std::begin( a ), std::end( a ) );
for ( auto first = std::begin( a ); first != last; ++first )
{
std::cout << *first << ' ';
}
std::cout << '\n';
return 0;
}
The program output is the same as shown above that is
1 2 3 4 5
I see two major problems with your code, both are out-of-bounds reads from an array:
if(a[i-1]-a[i]==0) will at one point be called with i==0, accessing element a[-1].
And here:
for(k=i;k<n;k++){
a[k] = a[k+1];
}
in the last loop iteration, when k == n-1 array element a[n] will be accessed, which is also an out-of-bounds access.
I have a task to remove the duplicates from a sorted array.
However, when I try this it doesn't remove anything and still gives me the same values in the output as the original.
I think I'm missing something in the removeDuplicates() function.
Also pointer notation would be recommended. Thank you!
void removeDuplicates(int *arr, int *size)
{
int s,*p,i,k=0;
p=arr;
s=*size;
int arr1[s];
for(i=0;i<s-1;i++)
{
if (*(p+i)!=*(p+i+1))
{
arr1[k++]=*(p+i);
}
}
arr1[k++]=*(p+s-1);
for(i=0; i<k; i++)
{
*(p+i) = arr1[i];
}
for(i=0; i<k; i++)
{
cout<<*(p+i)<<endl;
}
}
For starters variable length arrays as the array declared in your function
int arr1[s] = {};
is not a standard C++ feature. And moreover in C where variable length arrays exist you may not initialize them in their declarations.
Moreover if the source array contains only one or two different elements then the value of the variable k will be incorrect and equal to either 0 (instead of 1) or 1 (instead of 2).
Apart from this the function shall not output anything. It is the caller of the function decides whether to output the sub-array of unique elements. And as the second parameter is passed by reference in C meaning then it shall be changed within the function.
There is standard algorithm std::unique that can be used to do the task. Here is a demonstrative program.
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
int a[] = { 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5 };
auto last = std::unique( std::begin( a ), std::end( a ) );
for ( auto first = std::begin( a ); first != last; ++ first )
{
std::cout << *first << ' ';
}
std::cout << '\n';
return 0;
}
The program output is
1 2 3 4 5
If you want to write a similar function for arrays yourself using pointers within the function then it can look for example the following way
#include <iostream>
template <typename T>
size_t removeDuplicates( T *a, size_t n )
{
T *dest = a;
if ( n != 0 )
{
++dest;
for ( T *current = a; ++current != a + n; )
{
if ( *current != *( dest - 1 ) )
{
if ( dest != current )
{
*dest = *current;
}
++dest;
}
}
}
return dest - a;
}
int main()
{
int a[] = { 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5 };
const size_t N = sizeof( a ) / sizeof( *a );
size_t last = removeDuplicates( a, N );
for ( size_t first = 0; first != last; ++first )
{
std::cout << a[first] << ' ';
}
std::cout << '\n';
return 0;
}
Again the program output is
1 2 3 4 5
So I want to compare the 0th element of a vector with the other elements to see if they're equal because I want to remove other instances of that element's value from the vector e.g. {1, 1, 2, 3, 1} becomes {1, 2, 3} and this is the code I wrote:
std::vector<int> arr = {1,1,5,5,1,1};
for (int k = 1; k < arr.size(); k++)
{
if(arr[0] == arr[k]) {
arr.erase(arr.begin() + k);
}
The output I expected from this was:
155
Since it's supposed to remove all instances of the 1 except the first one, but what I instead get is:
1551
Where'd the last 1 come from and how do I fix this?
The loop is written incorrectly.
for (int k = 1; k < arr.size(); k++)
{
if(arr[0] == arr[k]) {
arr.erase(arr.begin() + k);
}
You should write at least
for (int k = 1; k < arr.size(); )
{
if(arr[0] == arr[k])
{
arr.erase(arr.begin() + k);
}
else
{
++k;
}
}
But in any case it is better to use the standard algorithm std::remove. For example
arr.erase( std::remove( std::next( std::begin( arr ) ), std::end( arr ), arr[0] ), std::end( arr ) );
Here is a demonstrative program.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<int> arr = { 1, 1, 5, 5, 1, 1 };
arr.erase( std::remove( std::next( std::begin( arr ) ), std::end( arr ), arr[0] ),
std::end( arr ) );
for ( const auto &item : arr ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
Its output is
1 5 5
The issue is that the index of your for-loop is keeping increasing after you removed an element. Just imagine that k is 1. You remove the arr[1] element. After that arr[1] is 5 but the index is increasing to 2. So actually you need to check arr[1] again but you won't. So in this way you skip some elements in the array.
I propose to replace for loop by while loop and increase the index only if you don't erase an element.
Run code here
this is my code for my bubble sort in c++ that for some reason only bubble sorts the last few but not the first 5 ints in the array. Help please
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
/* Tom Dresner
* 3/17/17
*/
int tom[10];
int b;
int x;
void sort()
{
cout << "\n";
for(int b=0;b<10;b++)
{
for(int x=0;x<9;x++)
{
if(tom[x]>tom[x + 1])
{
int t = tom[x];
tom[x] = tom[x+1];
tom[x+1] = t;
}
}
cout<< tom[b] << endl;
}
}
int main()
{
cout << "\n";
for(int i=0;i<10;i++)
{
tom[i] = rand()%10;
cout<< tom[i] << endl;
}
sort();
}
Not a complete answer, because that looks like homework, but here is a solution to a related problem that shows what kind of techniques you can use. In particular, a way to generate and return data without using globals, and a way to print it.
You may want to sort in place instead of what I do below. If so, you will find std::swap(v[i],v[j]) from the header <algorithm> helpful. You would also want to take a std::vector<int>& reference as your argument and return the same reference, like I do for std::ostream& os.
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::size_t;
std::vector<int> merge( const std::vector<int>& a, const std::vector<int>& b )
/* Given two sorted vectors, a and b, returns a sorted vector that merges the
* elements of a and b. Maybe you can figure out how this would be useful
* for sorting faster than bubble sort? Or you can ask your professor.
*/
{
std::vector<int> output; // Will hold the results;
/* If you haven't seen iterators yet, they're like indices inside the array.
* The expression *it++ returns the value at position it, then increments
* it.
*/
std::vector<int>::const_iterator it = a.begin();
std::vector<int>::const_iterator jt = b.begin();
// Reserve as much memory as we will need, because resizing vectors is slow.
output.reserve( a.size() + b.size() );
while ( it < a.end() || jt < b.end() ) {
if ( it == a.end() ) // We've reached the end of a, but not b.
while ( jt < b.end() ) // So we can stop checking a.
output.push_back(*jt++); // Add each element to the end.
else if ( jt == b.end() ) // We've reached the end of b, but not a.
while ( it < a.end() )
output.push_back(*it++);
else if ( *jt >= *it ) // Always add the lowest remaining element.
output.push_back(*it++);
else // What is the only remaining case?
output.push_back(*jt++);
} // end while
/* Do we know for sure that we've added each element from a or b to output
* exactly once, and in the right order? We assume a and be were sorted
* already. On each invocation of the loops, we copied exactly one element
* from either a or b to output, and stepped past it. The element we added
* was the smallest remaining element of a, unless there were no more in a
* or the smallest remaining element of b was smaller. Otherwise, it was
* the smallest remaining element of b. We stopped when we ran out of
* elements in both a and b.
*/
output.shrink_to_fit(); // Maybe save a few bytes of memory.
// Check that we have the correct number of elements:
assert( output.size() == a.size() + b.size() );
return output;
}
bool is_sorted( const std::vector<int>& v )
// Returns true if and only if v is sorted.
{
// Check that the elements are sorted.
for ( size_t i = 1; i < v.size(); ++i )
if( v[i] < v[i-1] )
return false;
/* If we escape the loop, we tested each pair of consecutive elements of v,
* and none were out of order.
*/
return true;
}
std::ostream& operator<< ( std::ostream& os, const std::vector<int>& v )
// Boilerplate to serialize and print a vector to a stream.
{
const size_t size = v.size();
os << '[';
if (size > 0)
os << v[0];
for ( size_t i = 1; i < size; ++i )
os << ',' << v[i];
os << ']';
return os;
}
int main(void)
{
// Our sorted input lists:
const std::vector<int> a = {0, 2, 4, 6, 8};
const std::vector<int> b = {-3, -2, -1, 0, 1, 2, 3};
assert(is_sorted(a)); // Input validation.
assert(is_sorted(b));
//Our output:
const std::vector<int> sorted = merge(a, b);
assert(is_sorted(sorted)); // Output validation.
cout << sorted << endl;
return EXIT_SUCCESS;
}
I ran into a problem where i need to delete the last elements of a vector until a certain condition is met (for sake of this example let it be the element is not zero)
I wrote this code, it does the trick -
auto next = vec.rbegin();
while (next != vec.rend())
{
auto current = next++;
if (*current == 0)
vec.pop_back();
else
break;
}
But i would much rather find an stl algorithm that i can use (i can use find_if and then erase, but i'd like to loop once through the elements that i remove...)
Also, i'm afraid i may be invoking some UB here, should i be worried?
Your code can be simplier:
while( !vec.empty() && vec.back() == 0 )
vec.pop_back();
Using std::remove or std::remove_if would remove all elements based by criteria, so you should use std::find_if as Vlad provided in his answer.
Here is an example. It uses the general idiom for erasing vectors
v.erase( std::remove( /*...*/ ), v.end() )
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5, 0, 0, 0 };
v.erase(
std::find_if( v.rbegin(), v.rend(),
[]( int x ) { return x != 0; } ).base(), v.end() );
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The output is
1 2 3 4 5