Is there an easy way to create a palindrome in C++ given the first half? For example given "abcdef", I want to return "abcdeffedcba", while keeping the input first half unchanged?
I know you could do, but is there a better way to do it in one line? In Java, reverse() returns a value therefore you can do it in one line.
string createPalindrome(string & half)
{
string temp = half;
reverse(temp.begin(), temp.end());
return half + temp;
}
If you want to do this in one line, here is an implementation:
#include <string>
#include <iostream>
std::string createPalindrome(const std::string & half)
{
return half + std::string(half.rbegin(), half.rend());
}
int main()
{
std::cout << createPalindrome("abcdef");
}
Live Example
Note that this basically taking the string and concatenating it with the reverse of itself.
The half.rbegin() and half.rend() are reverse iterators, so the temporary reverse string is constructed using these iterators.
It is not necessary to do this in one line. The code you have written is perfectly clean and understandable. If you want to use the reverse method, which I would recommend since it does exactly what you want, you cannot do it in one line anyway.
Related
For fun and practice, I have tried to solve the following problem (using C++): Given a string, return all the palindromes that can be obtained by rearranging its characters.
I've come up with an algorithm that doesn't work completely. Sometimes, it finds all the palindromes, but other times it finds some but not all.
It works by swapping each adjacent pair of characters N times, where N is the length of the input string. Here is the code:
std::vector<std::string> palindromeGen(std::string charactersSet) {
std::vector<std::string> pals;
for (const auto &c : charactersSet) {
for (auto i = 0, j = 1; i < charactersSet.length() - 1; ++i, ++j) {
std::swap(charactersSet[i], charactersSet[j]);
if (isPalandrome(charactersSet)) {
if (std::find(pals.begin(), pals.end(), charactersSet) == pals.end()) {
// if palindrome is unique
pals.push_back(charactersSet);
}
}
}
}
return pals;
}
What's the fault in this algorithm? I'm mostly concerned about the functionality of the algorithm, rather than the efficiency. Although I'll appreciate tips about efficiency as well. Thanks.
This probably fits a bit better in Code Review but here goes:
Logic Error
You change charactersSet while iterating over it, meaning that your iterator breaks. You need to make a copy of characterSet, and iterate over that.
Things to Change
Since pals holds only unique values, it should be a std::set instead of a std::vector. This will simplify some things. Also, your isPalandrome method spells palindrome wrong!
Alternative Approach
Since palindromes can only take a certain form, consider sorting the input string first, so that you can have a list of characters with an even number of occurrences, and a list of characters with an odd number. You can only have one character with an odd number of occurrences (and this only works for an odd length input). This should let you discard a bunch of possibilities. Then you can work through the different possible combinations of one half of the palindrome (since you can build one half from the other).
Here is another implementation that leverages std::next_permutation:
#include <string>
#include <algorithm>
#include <set>
std::set<std::string> palindromeGen(std::string charactersSet)
{
std::set<std::string> pals;
std::sort(charactersSet.begin(), charactersSet.end());
do
{
// check if the string is the same backwards as forwards
if ( isPalindrome(charactersSet))
pals.insert(charactersSet);
} while (std::next_permutation(charactersSet.begin(), charactersSet.end()));
return pals;
}
We first sort the original string. This is required for std::next_permutation to work correctly. A call to the isPalindrome function with a permutation of the string is done in a loop. Then if the string is a palindrome, it's stored in the set. The subsequent call to std::next_permutation just rearranges the string.
Here is a Live Example. Granted, it uses a reversed copy of the string as the "isPalindrome" function (probably not efficient), but you should get the idea.
I am working on some problems on Hackerrank, where I need to to determine if a string matches a pattern after 1 or 0 elements are removed. If after removing 1 or 0 elements, every character in the string has the same frequency then I want to print "YES". Otherwise I print "NO". The input is a string between 1 and 10^5 characters. What I have works for trivial cases, but times-out on some of the test cases. I should reach some return value, but I think the test cases are just really large input that my code is too inefficient for. Particularly where I use erase, I am copying the string n^2 times where n is the length of the string. Can I work on the string in-place, simply skipping over each element?
#include <iostream>
#include <string>
using namespace std;
long countFreq(char someChar,string someStr){
long count = 0;
for(int i=0;i<someStr.size();i++){
if(someStr[i] == someChar)count += 1;
}
return count;}
bool allSameFreq(string someStr){
long freq = countFreq(someStr[0],someStr);
for(char someChr:someStr){
if(countFreq(someChr,someStr)!=freq)return false;
}
return true;}
int main(){
string pattern;
cin>>pattern;
if(allSameFreq(pattern)==true){cout<<"YES";return 0;}
else {
for(int i=0;i<pattern.size();i++){
string copy = pattern;
copy.erase(i,1);
if(allSameFreq(copy)==true){cout<<"YES";return 0;}
}
cout<<"NO";
}
return 0;
}
Edit: It has been pointed out that this can be solved in another way that is less memory intensive. Still, I am curious about the original question: What is an efficient way to iterate over a string (or whatever) and test the "string minus each value" against a condition WITHOUT making a copy of the string each time?
I found a method that efficiently operates on a sublist without making a copy. You have to be able to access pointers to elements of the string, treating the string as a linked list. So depending on how you want to alter the string, you move a pointer or few, saving the values of the pointers you modified.
I am using visual studio 2012 (windows) and I am trying to write an efficient c++ function to remove some words from a big vector of strings.
I am using stl algorithms. I am a c++ beginner so I am not sure that it is the best way to proceed. This is what I have did :
#include <algorithm>
#include <unordered_set>
using std::vector;
vector<std::string> stripWords(vector<std::string>& input,
std::tr1::unordered_set<std::string>& toRemove){
input.erase(
remove_if(input.begin(), input.end(),
[&toRemove](std::string x) -> bool {
return toRemove.find(x) != toRemove.end();
}));
return input;
}
But this don't work, It doesn't loop over all input vector.
This how I test my code:
vector<std::string> in_tokens;
in_tokens.push_back("removeme");
in_tokens.push_back("keep");
in_tokens.push_back("removeme1");
in_tokens.push_back("removeme1");
std::tr1::unordered_set<std::string> words;
words.insert("removeme");
words.insert("removeme1");
stripWords(in_tokens,words);
You need the two-argument form of erase. Don't outsmart yourself and write it on separate lines:
auto it = std::remove_if(input.begin(), input.end(),
[&toRemove](std::string x) -> bool
{ return toRemove.find(x) != toRemove.end(); });
input.erase(it, input.end()); // erases an entire range
Your approach using std::remove_if() is nearly the correct approach but it erases just one element. You need to use the two argument version of erase():
input.erase(
remove_if(input.begin(), input.end(),
[&toRemove](std::string x) -> bool {
return toRemove.find(x) != toRemove.end();
}), input.end());
std::remove_if() reorders the elements such that the kept elements are in the front of the sequence. It returns an iterator it to the first position which is to be considered the new end of the sequence, i.e., you need to erase the range [it, input.end()).
You've already gotten a couple of answers about how to this correctly.
Now, the question is whether you can make it substantially more efficient. The answer to that will depend on another question: do you care about the order of the strings in the vector?
If you can rearrange the strings in the vector without causing a problem, then you can make the removal substantially more efficient.
Instead of removing strings from the middle of the vector (which requires moving all the other strings over to fill in the hole) you can swap all the unwanted strings to the end of the vector, then remove them.
Especially if you're only removing a few strings from near the beginning of a large vector, this can improve efficiency a lot. Just for example, let's assume a string you want to remove is followed by 1000 other strings. With this, you end up swapping only two strings, then erasing the last one (which is fast). With your current method, you end up moving 1000 strings just to remove one.
Better still, even with fairly old compilers, you can expect swapping strings to be quite fast as a rule--typically faster than moving them would be (unless your compiler is new enough to support move assignment).
Suppose I have a hexadecimal string y of length N of the form y{N}y{N-1}...y{1}.
Then given another hexadecimal string x of length L (L less than N), I want to check how many times (if at all) this string appears inside y... say like y{N}...x{L}x{L-1}...x{1}...y{j}..x{L}x{L-1}...x{1}....y{1}.
Which is the most efficient way to do this in C++ ?...I need a really efficient implementation as I would like to run this for a large database
"Hexadecimal" doesn't mean a thing here. C++ is a computer language, and works on bits. "Hexadecimal" is just a convenient way to group 4 bits together for human consumption.
Similarly, C++ doesn't index strings like y{N}y{N-1}...y{1}. It indexes them as y[0],y[1],y[N-1]. (There's no y[N].)
Under normal circumstances, std::string::find is going to be faster than your disk, which means it's fast enough.
Your request is a simple string search algorithm.
There are many algorithms to do that.
Most of them will give you a good answer in O(L+N) with preprocessing.
You can also use a suffix tree which will provide a faster answer in O(L + Z), where Z is the number of occurrences of x in y .
A suffix tree take a lot of memory space (O(N²)) though , might not be the ideal choice here.
Which is the most efficient way to do this in C++ ?
Try std::search across an std::istream_iterator of your input file, like this:
#include <string>
#include <iterator>
#include <iostream>
#include <algorithm>
int main () {
// std::ifstream input("input.txt");
std::istream& input(std::cin);
std::string search_for("1234");
std::istream_iterator<char> last;
std::istream_iterator<char> it(input);
int count(0);
while((it = std::search(it, last, search_for.begin(), search_for.end())) != last) {
count++;
}
std::cout << count << "\n";
}
If that isn't fast enough, you might try std::istreambuf_iterator.
If that isn't fast enough, you might try memory-mapping the file and using the initial and final pointers as your iterators.
What is the most efficient way to prepend std::string? Is it worth writing out an entire function to do so, or would it take only 1 - 2 lines? I'm not seeing anything related to an std::string::push_front.
There actually is a similar function to the non-existing std::string::push_front, see the below example.
Documentation of std::string::insert
#include <iostream>
#include <string>
int
main (int argc, char *argv[])
{
std::string s1 (" world");
std::string s2 ("ello");
s1.insert (0, s2); // insert the contents of s2 at offset 0 in s1
s1.insert (0, 1, 'h'); // insert one (1) 'h' at offset 0 in s1
std::cout << s1 << std::endl;
}
output:
hello world
Since prepending a string with data might require both reallocation and copy/move of existing data you can get some performance benefits by getting rid of the reallocation part by using std::string::reserve (to allocate more memory before hand).
The copy/move of data is sadly quite inevitable, unless you define your own custom made class that acts like std::string that allocates a large buffer and places the first content in the center of this memory buffer.
Then you can both prepend and append data without reallocation and moving data, if the buffer is large enough that is. Copying from source to destination is still, obviously, required though.
If you have a buffer in which you know you will prepend data more often than you append a good alternative is to store the string backwards, and reversing it when needed (if that is more rare).
myString.insert(0, otherString);
Let the Standard Template Library writers worry about efficiency; make use of all their hours of work rather than re-programming the wheel.
This way does both of those.
As long as the STL implementation you are using was thought through you'll have efficient code. If you're using a badly written STL, you have bigger problems anyway :)
If you're using std::string::append, you should realize the following is equivalent:
std::string lhs1 = "hello ";
std::string lhs2 = "hello ";
std::string rhs = "world!";
lhs1.append(rhs);
lhs2 += rhs; // equivalent to above
// Also the same:
// lhs2 = lhs2 + rhs;
Similarly, a "prepend" would be equivalent to the following:
std::string result = "world";
result = "hello " + result;
// If prepend existed, this would be equivalent to
// result.prepend("hello");
You should note that it's rather inefficient to do the above though.
There is an overloaded string operator+ (char lhs, const string& rhs);, so you can just do your_string 'a' + your_string to mimic push_front.
This is not in-place but creates a new string, so don't expect it to be efficient, though. For a (probably) more efficient solution, use resize to gather space, std::copy_backward to shift the entire string back by one and insert the new character at the beginning.
The problem is efficiency: inserting to the beginning of the string is more expensive as it requires both reallocation and shifting of existing characters.
If you are only prepending to the string, the most efficient way is appending, and then either reverse the string, or even better, go through the string in reverse order.
string s;
for (auto c: "foobar") {
s.push_back(c);
}
for (auto it=s.rbegin(); it!=s.rend(); it++) {
// do something
}
If you need a mix of prepending and appending, I'd suggest using a deque, and then construct a string from it.
The double-ended queue supports O(1) insertion and deletion at the beginning and end.
deque<char> dq;
dq.push_front('f');
dq.push_back('o');
dq.push_front('o');
string s {dq.begin(), dq.end()};