C++ recursive string mergesort - c++

This is a homework question so while I'd like usable code what I'm really seeking is insight on how to tackle this problem. I have two sorted arrays in ascending order that I need to combine in a recursive function. It seems like I need to institute the sorting part of a merge sort algorithm. The requirements are that the recursive function can only take the two sorted strings as parameters and it cannot use global or static variables.
I think the psuedocode is:
if the size of the two strings == 0 then return the result string.
compare substr(0,1) of each strings to see which is lesser, and append that to result string
recursively call the function with the new parameters being a substr of the string that appended
My questions are: how do I save a result string if I can't use static variables? I've seen code where a string is defined as = to the return statement of the recursive call. Would that work in this case?
The second question is how to increment the function. I need to call a substr(1,size-1) after the first iteration and then increment that without using static variables.
Here's my attempt to solve the equation WITH static variables (which are not allowed):
static string result="";
static int vv=0;
static int ww=0;
if(v.size()==0 && w.size()==0)
return result;
if(w.size()==0 || v.substr(0,1) <= w.substr(0,1)){
result+=v.substr(0,1);
vv++;
return spliceSortedStrings( v.substr(vv,v.size()-vv) , w);
}
else if(v.size()==0 || w.substr(0,1) > v.substr(0,1)){
result+=w.substr(0,1);
ww++;
return spliceSortedStrings( v , w.substr(ww,w.size()-ww));
}
I'll be appreciative for any guidance.

How about this:
std::string merge(std::string a, std::string b) {
if (a.size() == 0) return b;
if (b.size() == 0) return a;
if (a.back() < b.back()) {
std::string m = merge(a, b.substr(0, b.size()-1));
return m + b.back();
}
else {
std::string m = merge(a.substr(0, a.size()-1), b);
return m + a.back();
}
}
Correctness and termination should be obvious, and I think it should fit the constraints you are given. But I wonder what teacher would pose such a task in C++, for the above code is about as inefficient as it possibly can be.

Related

Why is the time complexity so different in the below two solutions?

I was trying to solve this Leetcode problem - https://leetcode.com/problems/partition-equal-subset-sum/. I came up with a memoized solution that never got accepted because apparently it took too much time. Below is that solution.
class Solution{
public:
bool canPartition(vector<int>& nums){
int totalSum = 0;
for(auto value : nums)
totalSum += value;
if(totalSum%2 == 1)
return false;
return helper(nums, totalSum/2, 0);
}
private:
bool helper(vector<int> nums, int totalSum, int index){
if(totalSum == 0)
return true;
if(totalSum < 0)
return false;
if(index == nums.size())
return false;
// Check in the cache
pair<int, int> key = make_pair(totalSum, index);
if(cache.count(key)){
//cout << "Cache hit!\n";
return cache[key];
}
// Include this
bool include = helper(nums, totalSum-nums[index], index+1);
// Exclude this
bool exclude = helper(nums, totalSum, index+1);
cache[key] = include || exclude;
return cache[key];
}
map<pair<int, int>, bool> cache;
};
After trying for a while, I made a small change where instead of using "include" and "exclude" booleans, I just did the below and the time complexity improved so significantly that it dropped from ~1000ms to ~0ms. I am confused why did this happen? Why is using two booleans and then storing their result in a map so much slower than when not using them?
cache[key] = helper(nums, totalSum-nums[index], index+1) || helper(nums, totalSum, index+1);
Can anyone please enlighten me here? Pretty confused about it.
The first version calls helper twice - once for include and once for exclude. The second version, since it uses the logical-or operator, will not call the 2nd helper if the first helper is true. In other words, if include is true, the exclude call is not made because it will not change the result of the expression.
Another performance hit is the nums parameter to helper. You don't make any changes to it within the function, so you can pass it as const vector<int> &nums to avoid making an unnecessary copy of the entire content of the array. canPartition can also take its parameter as a const reference since you do not modify it.

fast way to compare two vector containing strings

I have a vector of strings I that pass to my function and I need to compare it with some pre-defined values. What is the fastest way to do this?
The following code snippet shows what I need to do (This is how I am doing it, but what is the fastest way of doing this):
bool compare(vector<string> input1,vector<string> input2)
{
if(input1.size() != input2.size()
{
return false;
}
for(int i=0;i<input1.siz();i++)
{
if(input1[i] != input2[i])
{
return false;
}
}
return true;
}
int compare(vector<string> inputData)
{
if (compare(inputData,{"Apple","Orange","three"}))
{
return 129;
}
if (compare(inputData,{"A","B","CCC"}))
{
return 189;
}
if (compare(inputData,{"s","O","quick"}))
{
return 126;
}
if (compare(inputData,{"Apple","O123","three","four","five","six"}))
{
return 876;
}
if (compare(inputData,{"Apple","iuyt","asde","qwe","asdr"}))
{
return 234;
}
return 0;
}
Edit1
Can I compare two vector like this:
if(inputData=={"Apple","Orange","three"})
{
return 129;
}
You are asking what is the fastest way to do this, and you are indicating that you are comparing against a set of fixed and known strings. I would argue that you would probably have to implement it as a kind of state machine. Not that this is very beautiful...
if (inputData.size() != 3) return 0;
if (inputData[0].size() == 0) return 0;
const char inputData_0_0 = inputData[0][0];
if (inputData_0_0 == 'A') {
// possibly "Apple" or "A"
...
} else if (inputData_0_0 == 's') {
// possibly "s"
...
} else {
return 0;
}
The weakness of your approach is its linearity. You want a binary search for teh speedz.
By utilising the sortedness of a map, the binaryness of finding in one, and the fact that equivalence between vectors is already defined for you (no need for that first compare function!), you can do this quite easily:
std::map<std::vector<std::string>, int> lookup{
{{"Apple","Orange","three"}, 129},
{{"A","B","CCC"}, 189},
// ...
};
int compare(const std::vector<std::string>& inputData)
{
auto it = lookup.find(inputData);
if (it != lookup.end())
return it->second;
else
return 0;
}
Note also the reference passing for extra teh speedz.
(I haven't tested this for exact syntax-correctness, but you get the idea.)
However! As always, we need to be context-aware in our designs. This sort of approach is more useful at larger scale. At the moment you only have a few options, so the addition of some dynamic allocation and sorting and all that jazz may actually slow things down. Ultimately, you will want to take my solution, and your solution, and measure the results for typical inputs and whatnot.
Once you've done that, if you still need more speed for some reason, consider looking at ways to reduce the dynamic allocations inherent in both the vectors and the strings themselves.
To answer your follow-up question: almost; you do need to specify the type:
// new code is here
// ||||||||||||||||||||||||
if (inputData == std::vector<std::string>{"Apple","Orange","three"})
{
return 129;
}
As explored above, though, let std::map::find do this for you instead. It's better at it.
One key to efficiency is eliminating needless allocation.
Thus, it becomes:
bool compare(
std::vector<std::string> const& a,
std::initializer_list<const char*> b
) noexcept {
return std::equal(begin(a), end(a), begin(b), end(b));
}
Alternatively, make them static const, and accept the slight overhead.
As an aside, using C++17 std::string_view (look at boost), C++20 std::span (look for the Guideline support library (GSL)) also allows a nicer alternative:
bool compare(std::span<std::string> a, std::span<std::string_view> b) noexcept {
return a == b;
}
The other is minimizing the number of comparisons. You can either use hashing, binary search, or manual ordering of comparisons.
Unfortunately, transparent comparators are a C++14 thing, so you cannot use std::map.
If you want a fast way to do it where the vectors to compare to are not known in advance, but are reused so can have a little initial run-time overhead, you can build a tree structure similar to the compile time version Dirk Herrmann has. This will run in O(n) by just iterating over the input and following a tree.
In the simplest case, you might build a tree for each letter/element. A partial implementation could be:
typedef std::vector<std::string> Vector;
typedef Vector::const_iterator Iterator;
typedef std::string::const_iterator StrIterator;
struct Node
{
std::unique_ptr<Node> children[256];
std::unique_ptr<Node> new_str_child;
int result;
bool is_result;
};
Node root;
int compare(Iterator vec_it, Iterator vec_end, StrIterator str_it, StrIterator str_end, const Node *node);
int compare(const Vector &input)
{
return compare(input.begin(), input.end(), input.front().begin(), input.front().end(), &root);
}
int compare(Iterator vec_it, Iterator vec_end, StrIterator str_it, StrIterator str_end, const Node *node)
{
if (str_it != str_end)
{
// Check next character
auto next_child = node->children[(unsigned char)*str_it].get();
if (next_child)
return compare(vec_it, vec_end, str_it + 1, str_end, next_child);
else return -1; // No string matched
}
// At end of input string
++vec_it;
if (vec_it != vec_end)
{
auto next_child = node->new_str_child.get();
if (next_child)
return compare(vec_it, vec_end, vec_it->begin(), vec_it->end(), next_child);
else return -1; // Have another string, but not in tree
}
// At end of input vector
if (node->is_result)
return node->result; // Got a match
else return -1; // Run out of input, but all possible matches were longer
}
Which can also be done without recursion. For use cases like yours you will find most nodes only have a single success value, so you can collapse those into prefix substrings, to use the OP example:
"A"
|-"pple" - new vector - "O" - "range" - new vector - "three" - ret 129
| |- "i" - "uyt" - new vector - "asde" ... - ret 234
| |- "0" - "123" - new vector - "three" ... - ret 876
|- new vector "B" - new vector - "CCC" - ret 189
"s" - new vector "O" - new vector "quick" - ret 126
you could make use of std::equal function like below :
bool compare(vector<string> input1,vector<string> input2)
{
if(input1.size() != input2.size()
{
return false;
}
return std::equal(input1.begin(), input2.end(), input2.begin())
}
Can I compare two vector like this
The answer is No, you need compare a vector with another vector, like this:
vector<string>data = {"ab", "cd", "ef"};
if(data == vector<string>{"ab", "cd", "efg"})
cout << "Equal" << endl;
else
cout << "Not Equal" << endl;
What is the fastest way to do this?
I'm not an expert of asymptotic analysis but:
Using the relational operator equality (==) you have a shortcut to compare two vectors, first validating the size and, second, each element on them. This way provide a linear execution (T(n), where n is the size of vector) which compare each item of the vector, but each string must be compared and, generally, it is another linear comparison (T(m), where m is the size of the string).
Suppose that each string has de same size (m) and you have a vector of size n, each comparison could have a behavior of T(nm).
So:
if you want a shortcut to compare two vector you can use the
relational operator equality.
If you want an program which perform a fast comparison you should look for some algorithm for compare strings.

What is the most efficient way to return results from recursion?

There are 2 possible ways that I am familiar with while returning a boolean/integer value from a recursive function that defines is the operation carried out was a success or not.
Using static variables inside the recursive function. Changing values in the recursive calls and then returning the final value once everything is done.
Passing the result variable by reference to the recursive function and then manipulating its values in the function and then checking if the value corresponds to the result or not.
void Graph::findPath(string from, string to)
{
int result = 0;
if (from == to) cout<<"There is a path!"<<endl;
else
{
findPathHelper(from, to, result);
if (result) cout<<"There is a path!"<<endl;
else cout<<"There is not a path!"<<endl;
}
}
void Graph::findPathHelper(string from, string toFind, int &found)
{
for (vector<string>::iterator i = adjList[from].begin(); i != adjList[from].end(); ++i)
{
if (!(toFind).compare(*i))
{
found = 1;
break;
}
else
findPathHelper(*i, toFind, found);
}
}
Is there a better way to achieve this?
Thank You
I have changed your implementation to use a return value
bool Graph::findPathHelper(const string& from, const string& toFind)
{
for (vector<string>::iterator i = adjList[from].begin(); i != adjList[from].end(); ++i)
{
// I have assumed you comparison was incorrect - i.e. toFind == *i is that you want
// toFind == *i - The two strings are equal - Thus found
// or
// Recurse on *i - Have we found it from recursion
if (toFind == *i || findPathHelper(*i, toFind)) {
return true;
}
}
// We have searched everywhere in the recursion and exhausted the list
// and still have not found it - so return false
return false;
}
You can return a value in the recursive function and use that returned value for checking if it was success or not in subsequent calls.
Using static variable for this purpose may work but it's generally not a good IDEA and many consider it as bad practice.
Look into the below link which explains why we must avoid static or global variables and what kind of problems it could lead to during recursion.
http://www.cs.umd.edu/class/fall2002/cmsc214/Tutorial/recursion2.html
Note: I do not have enough reputation still to make a comment; and therefore i have posted this as answer.

C++ String Length Check

bool fitsKey3(string n) {
int ncheck = str.length(n);
if (ncheck = KEY3) {
return true;
} else {
return false;
}
}
The above function uses a string "n" that is a string given to the function from an input file. I want to write this function that checks the length of this "identifier code" from the input file (it's a drone project), and if the length of the security code is equal to the constant integer "KEY3 (= 50), it returns true. Otherwise, return false.
How do I fix this setup?
= assigns the value of KEY3 to ncheck.
== compares ncheck and KEY3 for equality.
Also, unless you're being paid by lines of code, I'd suggest using the much simpler and clearer form:
return n.length() == KEY3;
(I corrected your usage of the length() member function, since I suppose it was only a typo.)
And as pointed out by Anon Mail, unless you want to make a copy of the string every time you call the function, I'd suggest only passing a reference to it (const because you're not modifying it):
bool fitsKey3(string const& n)
I would write it like this:
bool fitsKey3(string n) {
return n.length() == KEY3;
}
You do two operations:
Get string length by n.length()
Compare the length with a KEY3 (NB: use == to compare)

Is this the right way to use recursion?

Given strings s and t compute recursively, if t is contained in s return true.
Example: bool find("Names Richard", "Richard") == true;
I have written the code below, but I'm not sure if its the right way to use recursion in C++; I just learned recursion today in class.
#include <iostream>
using namespace std;
bool find(string s, string t)
{
if (s.empty() || t.empty())
return false;
int find = static_cast<int>(s.find(t));
if (find > 0)
return true;
}
int main()
{
bool b = find("Mississippi", "sip");
string s;
if (b == 1) s = "true";
else
s = "false";
cout << s;
}
If anyone find an error in my code, please tell me so I can fix it or where I can learn/read more about this topic. I need to get ready for a test on recursion on this Wednesday.
The question has changed since I wrote my answer.
My comments are on the code that looked like this (and could recurse)...
#include <iostream>
using namespace std;
bool find(string s, string t)
{
if (s.empty() || t.empty())
return false;
string start = s.substr(0, 2);
if (start == t && find(s.substr(3), t));
return true;
}
int main()
{
bool b = find("Mississippi", "sip");
string s;
if (b == 1) s = "true";
else
s = "false";
cout << s;
}
Watch out for this:
if (start == t && find(s.substr(3), t));
return true;
This does not do what you think it does.
The ; at the end of the if-statement leaves an empty body. Your find() function will return true regardless of the outcome of that test.
I recommend you turn up the warning levels on your compiler to catch this kind of issue before you have to debug it.
As an aside, I find using braces around every code-block, even one-line blocks, helps me avoid this kind of mistake.
There are other errors in your code, too. Removing the magic numbers 2 and 3 from find() will encourage you to think about what they represent and point you on the right path.
How would you expect start == t && find(s.substr(3), t) to work? If you can express an algorithm in plain English (or your native tongue), you have a much higher chance of being able to express it in C++.
Additionally, I recommend adding test cases that should return false (such as find("satsuma", "onion")) to ensure that your code works as well as calls that should return true.
The last piece of advice is stylistic, laying your code out like this will make the boolean expression that you are testing more obvious without resorting to a temporary and comparing to 1:
int main()
{
std::string s;
if (find("Mississippi", "sip"))
{
s = "true";
}
else
{
s = "false";
}
std::cout << s << std::endl;
}
Good luck with your class!
Your recursive function needs 2 things:
Definite conditions of failure and success (may be more than 1)
a call of itself to process a simpler version of the problem (getting closer to the answer).
Here's a quick analysis:
bool find(string s, string t)
{
if (s.empty() || t.empty()) //definite condition of failure. Good
return false;
string start = s.substr(0, 2);
if (start == t && find(s.substr(3), t)); //mixed up definition of success and recursive call
return true;
}
Try this instead:
bool find(string s, string t)
{
if (s.empty() || t.empty()) //definite condition of failure. Done!
return false;
string start = s.substr(0, 2);
if (start == t) //definite condition of success. Done!
return true;
else
return find(s.substr(3), t) //simply the problem and return whatever it finds
}
You're on the right lines - so long as the function calls itself you can say that it's recursive - but even the most simple testing should tell you that your code doesn't work correctly. Change "sip" to "sipx", for example, and it still outputs true. Have you compiled and run this program? Have you tested it with various different inputs?
You are not using recursion. Using std::string::find in your function feels like cheating (this will most likely not earn points).
The only reasonable interpretation of the task is: Check if t is an infix of s without using loops or string functions.
Let's look at the trivial case: Epsilon (the empty word) is an infix of ever word, so if t.empty() holds, you must return true.
Otherwise you have two choices to make:
t might be a prefix of s which is simple to check using recursion; simply check if the first character of t equals the first character of s and call isPrefix with the remainder of the strings. If this returns true, you return true.
Otherwise you pop the first character of s (and not of t) and proceed recursively (calling find this time).
If you follow this recipe (which btw. is easier to implement with char const* than with std::string if you ask me) you get a recursive function that only uses conditionals and no library support.
Note: this is not at all the most efficient implementation, but you didn't ask for efficiency but for a recursive function.