vector<int>& mergesort(vector<int> &a) {
if (a.size() == 1) return a;
int middle = a.size() / 2;
vector<int>::const_iterator first = a.begin();
vector<int>::const_iterator mid = a.begin() + (middle - 1);
vector<int>::const_iterator last = a.end();
vector<int> ll(first, mid);
vector<int> rr(mid, last);
vector<int> l = mergesort(ll);
vector<int> r = mergesort(rr);
vector<int> result;
result.reserve(a.size());
int dp = 0, lp = 0, rp = 0;
while (dp < a.size()) {
if (lp == l.size()) {
result[dp] = (r[rp]);
rp++;
} else if (rp == r.size()) {
result[dp] = (l[lp]);
lp++;
} else if (l[lp] < r[rp]) {
result[dp] = (l[lp]);
lp++;
} else {
result[dp] = (r[rp]);
rp++;
}
dp++;
}
a = result;
return a;
}
It compiles correctly but while execution, I am getting:
This application has requested the
runtime to end it in an unusual way.
This is a weird error.
Is there something that is fundamentally wrong with the code?
This result.reserve(a.size()) just affects the vector's capacity, not it's size. (The vector's capacity tells up to which size the vector can grow without needing to re-allocate and copy all members. Basically it's only there for optimization purposes.) You cannot access any members in result after that reservation, since there aren't any. Either use result.push_back(...) instead of result[dp] = ... or result.resize(a.size()) instead of result.reserve(a.size()).
I suppose the former could be more effective.
One problem is with the usage of reserve() (either use resize() or append items with push_back() instead of accessing the index).
if (a.size() == 1) return a;
int middle = a.size() / 2;
vector<int>::const_iterator first = a.begin();
vector<int>::const_iterator mid = a.begin() + (middle - 1);
vector<int>::const_iterator last = a.end();
vector<int> ll(first, mid);
vector<int> rr(mid, last);
This could be another problem. If the size is 2, then ll would end up being an empty vector, and this function doesn't appear to handle this. There doesn't seem to be much reason to subtract 1 from middle anyway.
It is also possible that you are copying things around far more than needed: you shouldn't need the l and r vectors (because they will just be copies of ll and rr), similarly I don't think you need the result vector, since you could just write the merged results right back to a.
reserve() does not change the amount of contents in the vector. You've created an empty vector, reserved a certain size for it, and then used v[i] = x; This is not a valid use of vector since there still isn't any i'th element in the vector.
Use resize() instead.
The error message is very unclear, because it is the standard message of VC++ when an exception goes unhandled. You could add a try-catch-clock to your main to get the exception and a more meaningful error:
int main() {
try {
// do main stuff here
}
catch ( std::exception & e ) {
std::cout << e.what() << std::endl;
}
}
This is for the command-line. If your application doesn't have one, use a message box or write the error to a log-file.
With regard to the problem in your code, all the other answers appear to be correct.
Related
Error:
Line 1034: Char 9: runtime error: reference binding to null pointer of type 'int' (stl_vector.h)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_vector.h:1043:9
My Code:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> sol;
int temp, i = 0, l = nums.size();
while(true && i < l)
{
temp = nums[i] - target;
int it = nums.end() - find(nums.begin(), nums.end(), temp);
if(it == 0)
{ i++;
continue;
}
sol[0] = i;
sol[1] = it;
break;
}
return sol;
}
The problem statement from Two Sum - LeetCode says:
Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
You can return the answer in any order.
The bigger issue in the posted implementation is the repeated access out of bounds of sol, which is declared as an empty vector:
vector<int> sol;
Later, in loop, it's accessed via operator[] at indices 0 and 1, but those elements don't exist. So, to fix it, just declare a vector of two elements.
std::vector<int> sol(2);
Other minor issues (not really errors) are the followings:
int temp, i = 0, l = nums.size();
while ( true && i < l )
{ // ^^^^^^^ Why? It's pointless.
int it = nums.end() - find(nums.begin(), nums.end(), temp);
// ^^^^^^^^^^^^
// This traverses the vector every time from the beginning, which is a waste.
// Also, "you may not use the same element twice".
// Just start from the element after nums[i].
if(it == 0) // Consider to invert the logic: break when a pair is found
{
i++;
continue;
}
sol[0] = i; // Already addressed, but...
sol[1] = it;
// ^^ I lied, this IS another error.
// Do you remember how 'it' was calculated?
break;
}
To summarize, this is a possible solution
std::vector<int> twoSum(std::vector<int> const& nums, int target)
{ // We are not modifying it, so ^^^^^
std::vector<int> sol(2);
// IMHO, a std::pair would have been a better fir, here.
for (auto i{ nums.cbegin() }; i != nums.cend(); ++i)
{ // It's const... ^
auto const j = std::find(i + 1, nums.cend(), *i - target);
// Don't count twice ^^^^^
if( j != nums.cend() )
{ // ^^
sol[0] = std::distance(nums.cbegin(), i);
sol[1] = std::distance(nums.cbegin(), j);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Count from the beginning.
break;
}
}
return sol;
}
I am reversing a string and comparing it to another string whether it matches or not.
String d is reversed correctly, but in the If statement, it is not comparing. Strings comparing like this usually works I have done it before. Can someone explain this?
Thank You
int main()
{
string a, d, e;
int b, c;
cin >> a >> e;
for (int i = a.size(); i >= 0; i--)
{
d.push_back(a[i]);
}
cout << d;
if (d == e)
cout << "YES";
else
cout << "NO";
return 0;
}
If a string is 4 characters long, then s[4] will give you 1 past the end of the string. So here:
for (int i = a.size(); i >= 0; i--)
when you use i which would be 4 in the first step, you are accessing past the end of the string. You could do:
for (int i = a.size() - 1; i >= 0; i--)
but be careful if a is empty! You will underflow the integer and end up with big problems! You could check for empty string at the top of your function but that is extra work. To avoid this problem, you could use an iterator, but these only go forward :( Oh wait, reverse_iterator!
for (auto rit = s.rbegin(); rit != s.rend(); ++rit) {
d.push_back(*rit);
This will solve the problem. You could wrap this up in a function, call it reverse! Luckily, this actually exists: std::reverse:
a = d;
std::reverse(std::begin(d), std::end(d));
Easy peasy
Note that the i = a.size() when used in d.push_back(a[i]); will lead to undesired subscript access (recall that indexing starts with 0, while size() returns the amount of elements in a container).
You should look toward this implementation:
#include <string>
#include <iostream>
int main()
{
std::string a, d, e;
int b, c;
std::cin >> a >> e;
for (auto i = a.rbegin(); i != a.rend(); ++i) // Using return iterators
{
d.push_back(*i); // Dereference the iterator and push_back() it
}
std::cout << d << std::endl;
if (d == e)
std::cout << "YES" << std::endl;
else
std::cout << "NO" << std::endl;
return 0;
}
Example:
foo
oof
oof
YES
This approach uses reverse iterators on the string. Note, in order to advance this type of iterator, you use the same increment operation, only in this case, the iterator goes backwards (from the end of container to beginning).
The issue is that you accessing the NUL terminator of a, and putting that at the start of d. The behaviour of your program was undefined up to but not including C++11.
Using
a = d;
std::reverse(std::begin(d), std::end(d));
is the solution. Alternatives such as character by character access are poor due to the potential pitfalls with using unsigned arithmetic. Using the C++ standard library can also help your compiler in its optimisation choices.
Rather than reversing the string then comparing, you could compare the strings using std::equal:
bool result = std::equal(a.rbegin(), a.rend(),
d.begin(), d.end());
If all you want is to check if the string is a palindrome, you don't need to allocate a new string. Here's a much more efficient way:
#include <algorithm>
#include <string_view>
[[nodiscard]] constexpr bool IsPalindrome(std::string_view const str) noexcept {
auto begin = str.begin();
auto mid = begin + str.size() / 2;
return std::equal(begin, mid, str.rbegin());
}
The usual idiom for writing a loop is to start at the beginning and stop when you've passed the last element. With an index it looks like this:
for (int i = 0; i < a.size(); ++i) {
// do something with a[i]
}
Note that the terminating condition becomes true when i goes off the end.
To do that when you want to go in the other direction you have two choices:
for (int i = a.size(); i > 0; --i) {
// do something with a[i - 1]
}
In this case, the element we're interested in is a[i - 1]. The loop starts with the topmost element, when i is a.size(), and stops after the last element, when i becomes 0 and accessing a[i - 1] would be off the end.
That's a bit tricky to visualize, so you might be tempted to write it like this instead:
for (int i = a.size() - 1; i >= 0; --i) {
// do something with a[i]
}
This version has a subtle bug, and should not be your usual approach. The problem is that a.size() is unsigned. When a is empty, a.size() is 0, and a.size() - 1 wraps around and becomes a very large value. So don't use it.
Another way to avoid problems like this is to use iterators, which handle the details of recognizing the beginning and end of the sequence:
for (auto iter = std::begin(a); iter != std::end(a); ++iter) {
// do something with *iter
}
This is easily adapted to reverse iteration:
for (auto iter = std::rbegin(a); iter != std::rend(a); ++iter) {
// do something with *iter
}
And yet another possibility is to let the standard library handle the iteration:
void do_someting_with_a_sub_i(int) {
// whatever
}
std::for_each(std::begin(a), std::end(a), do_someting_with_a_sub_i);
or, in reverse,
std::for_each(std::rbegin(a), std::rend(a), do_someting_with_a_sub_i);
(yes, modern fashion calls for using a lambda instead of writing out do_something_with_a_sub_i. Sigh.)
I have the following given vector:
vector<int> arr = {2,1,2,2,2,3,4,2};
The goal is to move a target number all the way to the back. Say target is 2, then final result should be something like:
arr = {1,3,4,2,2,2,2,2}
Attempt
My approach is to loop through the vector, then if I find a 2, I would use push_back to add to the end, and at the same time, erase the current 2.
In code, it looks like this:
vector<int> moveEndV1(vector<int> &arr, int toMove){
for (unsigned int i = 0; i < arr.size() ; i++) {
if (arr[i] == toMove) {
arr.push_back(arr[i]); // add to the end
arr.erase(arr.begin()+i); // erase current
}
}
return arr;
}
Problem Once we erase the an element, the loop counter is wrong because now it is dealing with a modified vector.
In other words, say we start with the original vector:
{2,1,2,2,2,3,4,2}
At i = 0, the value is 2 so we moved 2 to the back and erased the first 2.
So we have at i = 0:
{1,2,2,2,3,4,2,2}
This is fine, but then when we go to i = 1, the value at i = 1 is no longer 1 like the original array, but instead it is 2. This is because we erased an element when we were at i = 0. So, at i = 1, after push_back and erasing, we get:
{1,2,2,3,4,2,2,2}
So far so good, but now if we go to i = 2, we get:
{1,2,3,4,2,2,2,2}
i will keep increasing till the end, and in the end we have that extra 2 at the front.
{1,2,3,4,2,2,2,2}
Is there a way to resolve this? Other than writing a separate function to search for this 2 at the front and then move to back?
Any help is greatly appreciated.
You can do this easily by using std::stable_partition:
std::stable_partition(arr.begin(), arr.end(),
[toMove](int i) { return i != toMove; });
#cigien solution is elegant;
but modified your code a bit, will work too;
void moveEndV1(std::vector<int> &arr, int toMove){
auto it = arr.begin();
for ( int i = 0; i < arr.size(); i++ )
{
if (*it == toMove )
{
int val = *it;
it = arr.erase( it );
arr.push_back( val );
}
else
{
++it;
}
}
}
A stable partition works, but seems like an overkill (O(n log n) time, O(log n) space). Since you know your target number, you don't have to push it back immediately. Instead, use two iterators, src and dst, along the lines of
auto dst = arr.begin();
for (auto src = arr.begin(); src != arr.end(); src++) {
if (*src != toMove) {
*dst++ = *src;
}
}
// At this point all non-target numbers are at the beginning of the
// array, and the order is preserved. Fill the rest with the target.
while (dst != arr.end()) {
*dst++ = toMove;
}
I came across this problem and wondering if there could be a better complexity to solve the problem.
For e.g.
array a = [1,4,2,4]
array b = [3,5]
DESIRED OUTPUT ==> [2, 4]
EDIT: Put another example
array a = [1,4,2,4]
array b = [3, 1000000]
DESIRED OUTPUT ==> [2,4]
So far, what I've found and tried runs in O(nlogn) + O(blogn) and O(n).
O(nlogn) + O(blogn) approach:
int binarysearch(vector<int>arr, int l, int r, int target)
{
int mid;
while(l <= r)
{
mid = (r+l) / 2;
if(arr[mid] > target)
r = mid - 1;
else
l = mid + 1;
}
return r;
}
vector<int> counts(vector<int> a, vector<int> b)
{
vector<int> result;
sort(a.begin(), a.end()); // O(nlogn)
for(auto i : b){
int count = binarysearch(a, 0, a.size()-1, b); // b*O(log n) times
result.push_back(count)
}
return result;
}
O(n) approach:
vector<int> counts(vector<int> a, vector<int> b)
{
vector<int> result;
int maxi = *max_element(b.begin(), b.end()) + 1;
int mymap[maxi] = {0};
for(auto i : a) mymap[i]++;
for(int i = 1; i < maxi; i++){
mymap[i] = mymap[i] + mymap[i-1];
}
for(auto i : b){
result.push_back(mymap[i]);
}
return result;
}
[I am] wondering if there could be a better complexity to solve the problem.
Time complexity.
O(n) approach:
No, there exists no solution with less than linear time complexity.
That said, you linear solution is incorrect. If the input array contains the value 1000000 or greater, or a negative number, then you access outside the bounds of mymap and behaviour is undefined. Furthermore, i <= 1000000 also accesses mymap outside the bound upon the last iteration. Besides, int[1000000] is way too big to be a local variable. On some systems, even one such variable could cause the stack to overflow.
There is no better way doing this than O(n).
So this is also O(n) but with STL style adapted:
template <class Iter1, class Iter2>
std::vector<std::size_t> counts(const Iter1 beg_a, const Iter1 end_a, const Iter2 beg_b, const Iter2 end_b)
{
std::vector<std::size_t> result;
const auto& max = *std::max_element(beg_b, end_b);
std::vector<std::size_t> mymap(max + 1, 0);
for (auto iter = beg_a; iter != end_a; iter++)
{
if (*iter <= max)
{
mymap[*iter]++;
}
}
for (std::size_t i = 1; i < mymap.size(); i++)
{
mymap[i] = mymap[i] + mymap[i - 1];
}
for (auto iter = beg_b; iter != end_b; iter++)
{
result.push_back(mymap[*iter]);
}
return result;
}
Okay, it turns out there's a faster way to compute the map index. For e.g. given a = {1,4,2,4,5,8,80} and b = {3,1000000}. DESIRED OUTPUT would be [2,7].
Using my previous approach, I would need to compute mymap[4], mymap[5].. mymap[9999]....mymap[1000000]. And that's why the program crashes and returns running time error.
the way we handle this is to use for(auto& entry:mymap) which gives access to all dictionary/map. Then, we use the upper_bound STL C++ to return the correct map.
vector<int> counts(vector<int> nums, vector<int> maxes){
vector<int> result;
map<int,unsigned int> mymap;
for(auto i : nums) mymap[i]++;
// doesn't need to run 1000000 times
int temp = 0;
for(auto& entry: mymap){
entry.second = entry.second + temp;
temp = entry.second;
//cout << "first : " << entry.first << "second: " << entry.second << endl;
}
map<int,unsigned int>::iterator itl;
for(auto i : maxes){
itl = --mymap.upper_bound(i); // points to the correct map
result.push_back(itl->second);
}
return result;
}
First let's take better notations: let's call A the number of elements in a, B the number of elements in B, and say elements are M bits values.
Your solution is, as others said, A log(A) to construct the map plus B log(A) to get the returned values.
Using a https://en.wikipedia.org/wiki/Y-fast_trie you could get (A+B) log M instead, which is faster if A >> M (but probably slower in practice for most use cases).
I have an assignment to merge two sorted vectors into a third sorted vector. I'm sure the solution to this problem is pretty simple, but my brain is fried at the moment and could use your help.
Basically vectors A and B have a size of 3. They will hold integers such as 1, 2, 3 and 4, 5, 6 respectively. I can't seem to get the syntax of my while loop correctly. I've tried making it a do/while loop, putting parentheses around the cases, and a few other things. It just doesn't seem to be reading the part after the &&.
The first for loop just makes the R vector have the right size. And the second for loop just displays the values of the R vector. The result should print out from 1-6, but I'm only seeing 1-3.
Any help would be appreciated!
void::combine(vector<int> A, vector<int> B, vector<int> R) {
int ia = 0, ib = 0, ir = 0;
for (int i = 0; i < A.size() + B.size(); i++) {
R.push_back(0);
}
while (ia != A.size() && ib != B.size()) {
if (A[ia] < B[ib]) {
R[ir] = A[ia];
ia += 1;
}
else {
R[ir] = B[ib];
ib += 1;
}
ir += 1;
}
for (int i = 0; i < R.size(); i++) {
cout << "L3[" << i << "] = " << R[i] << endl;
}
}
Assuming A contains [1,2,3] and B contains [4,5,6] as you say, this will not add any of the element in the B vector to the R vector.
This is because on the 4th iteration, ia == 3, and so the conjunctive condition is no longer true..
Try changing it to while(ia != A.size() || ib != B.size())
Probably you should avoid the loop altogether:
void combine(vector<int> const& A, vector<int> const& B, vector<int> & R) {
R.resize( A.size() + B.size() );
std::copy( A.begin(), A.end(), R.begin() );
std::copy( B.begin(), B.end(), R.begin()+A.size() );
std::sort( R.begin(), R.end() );
for ( int i = 0; i < R.size(); ++i )
{
cout << "L3[" << i << "] = " << R[i] << endl;
}
}
This is suboptimal as you are first copying and then ordering, but for a small size it will have no impact.
On the actual issues with your code: try to avoid pass-by-value, use resize instead of multiple push_back() to fix the size (note that if the R argument to your function was a non-empty vector then the final size would be bigger than you want). Consider using a return value instead of a reference argument --easier to read. You looped until the first of the counters reached the end, but left the rest of the elements in the other container without copying.
A manual implementation, using iterators would also be simpler:
typedef std::vector<int> vector_t;
vector_t combine( vector_t const & a, vector_t const & b ) {
vector_t r( a.size() + b.size() ); // [*]
vector_t::const_iterator ita = a.begin(), enda = a.end();
vector_t::const_iterator itb = b.begin(), endb = b.end();
vector_t::iterator itr = r.begin();
while ( ita != enda && itb != endb ) {
if ( *ita < *itb )
*itr++ = *ita++;
else
*itr++ = *itb++;
}
if ( ita != enda )
std::copy( ita, enda, itr );
else
std::copy( itb, endb, itr );
return r;
}
I don't know what you're trying to do in the while loop. But if you're just populating the vector R with the elements in A and B, without giving any regard to the order how they're added, then you can use insert function, as:
void::combine(const vector<int> &A, const vector<int> &B, vector<int>& R)
{
R.insert(R.end(), A.begin(), A.end());
R.insert(R.end(), B.begin(), B.end());
}
And if you want to order the vector R, then you can add the following line to the above function:
sort( R.begin(), R.end()); //sorts in increasing order.
You've to #include<algorithm> if you do so. If you want to sort in decreasing order then do this:
bool compare( int a, int b ) { return a > b; }
sort( R.begin(), R.end(), compare); //sorts in decreasing order.
First of all, this smells like a classic merge sort or a piece of it:
http://en.wikipedia.org/wiki/Merge_sort
The objective is to examine elements of the first vector, A, to elements of vector B, and append the elements to a resulting vector R, in order.
Thus if A[i] < B[j], append A[i] to R. With std::vector, there is no need to load the result vector with zeros before starting. See std::vector::push_back().
The following is untested code:
void Sort_Vector(const std::vector& A, const std::vector& B, std::vector& result)
{
unsigned int index_a = 0; // Point to first element in first vector.
unsigned int index_b = 0; // Point to first element in second vector.
result.clear(); // Clear all elements, so size == 0.
while ((index_a < A.size()) && (index_b < B.size())
{
if (A[index_a] < B[index_b])
{
result.push_back(A[index_a]);
++index_a;
}
else // B[index_b] <= A[index_a]
{
result.push_back(B[index_b]);
++index;
}
}
// Append any remaining elements to the result vector.
// Only one of the two loops should be executed,
// the other will fail the comparison expression
// and not execute.
for (; index_a < A.size(); ++index_a)
{
result.push_back(A[index_a]);
}
for (; index_b < B.size(); ++index_b)
{
result.push_back(B[index_b]);
}
return;
}
Notice the difference between my function's signature (parameters) and yours. I'm passing the source vectors as constant data and the result vector is passed by reference which enables my function to modify the caller's result vector.
Also, I'm lazy and using the std::vector::push_back() method. I believe this is more readable than assigning to an element in the result vector. The push_back method implies that I am appending to the vector. The assignment route may catch readers off-guard if they forget that a vector will expand in order resolve the assignment.
that's because of your && condition. as soon as ia == A.size(), the first part of the condition (ia != A.size()) will always evaluate to false and the ib part of your loop won't execute.
to fix it, you can change the condition to : (iA < A.size()) || (iB < B.size())
e.g. with 123 and 456 what is being done right now.
Initialize R to {0,0,0,0,0,0}
until all values from one vector are inserted into R compare candidates and insert smaller one into R, get next candidate from winner list.
and that's all - I don't know that is the purpose of the function if you'll write it I/We can provide solution otherwise just review 2nd point in above form.
The syntax is fine (the code wouldn't compile otherwise), but your loop condition isn't. Given your example A = { 1, 2, 3 } and B = { 4, 5, 6 }, the loop will enter the A[ia] < B[ib] branch three times and increment ia to 3. Once this happens, the first part of the loop condition, ia != A.size() won't be true, and so the loop ends.
Since you already know how many items you need to place in the result vector, I'd recommend replacing your while loop with a simple for one with the same body.