C++ recursive permutation algorithm for strings -> not skipping duplicates - c++

I'm having trouble finding a simple statement to skip the duplicates for this recursive permutation code. I've looked everywhere and seem to only find examples using swap or java. From what I gather, I think I need to put a line right after the for-loop.
Thank you!
#include "genlib.h"
#include "simpio.h"
#include <string>
#include <iostream>
void ListPermutations(string prefix, string rest);
int main() {
cout << "Enter some letters to list permutations: ";
string str = GetLine();
cout << endl << "The permutations are: " << endl;
ListPermutations("", str);
return 0;
}
void ListPermutations(string prefix, string rest)
{
if (rest == "")
{
cout << prefix << endl;
}
else
{
for (int i = 0; i < rest.length(); i++)
{
if (prefix != "" && !prefix[i]) continue; // <--- I tried adding this, but it doesn't work
cout << endl<< "prefix: " << prefix << " | rest: " << rest << endl;
string newPrefix = prefix + rest[i];
string newRest = rest.substr(0, i) + rest.substr(i+1);
ListPermutations(newPrefix, newRest);
}
}
}

this should work :
your algoithm is good, i only added a test : if a unique char is already used at a position. if yes, no more permutation is made because all permutations with that char in that position is already made.
void ListPermutations(string prefix, string rest)
{
if (rest == "")
{
cout << prefix << endl;
}
else
{
for (int i = 0; i < rest.length(); i++)
{
//test if rest[i] is unique.
bool found = false;
for (int j = 0; j < i; j++)
{
if (rest[j] == rest[i])
found = true;
}
if(found)
continue;
string newPrefix = prefix + rest[i];
string newRest = rest.substr(0, i) + rest.substr(i+1);
ListPermutations(newPrefix, newRest);
}
}
}
you can also sort the string before making permutations, the result will be the same.

In C++ to generate permutation use std::next_permutation
It will handle duplicate entries just fine and do the right thing

Ignoring the availability of std::next_permutation, because your comment on the previous answer...
If you want to generate all the unique permutations, you're going to need to have them in order at some point. The hackiest way to do this would be to put them all in a vector, sort it and then suppress duplicate adjacent entries when printing it out. But that's a lot slower than it needs to be.
You'll need to start with by sorting your string, so that identical permutations will be generated after each other. Then in your for loop, make sure you skip any duplicate letters in 'rest'. something like:
char lastAdditionToPrefix = '\0';
for (int i = 0; i < rest.length(); i++)
{
if (rest[i] == lastAdditionToPrefix) continue;
lastAdditionToPrefix = rest[i];
cout << endl<< "prefix: " << prefix << " | rest: " << rest << endl;
...
I'm not convinced that this change will completely fix your code, but it's closer than you are at the moment. edit: this, plus sorting the input in main(), will work

Tested and works fine. The idea is for each stack level, at location i, remember whether a character has been at that location already.
using namespace std;
void doPermutation(vector<char> &input, int index) {
bool used[26] = {false};
if(index == input.size()) {
copy(input.begin(), input.end(), ostream_iterator<char>(cout, "") );
cout << endl;
} else {
int i, j;
for(i =index; i < input.size(); i++ ) {
if(used[ input[i]-'a'] == false) {
swap(input[i], input[index]);
doPermutation(input, index+1);
swap(input[i], input[index]);
used[input[i]-'a'] = true;
}
}
}
}
void permutation(vector<char>& input) {
doPermutation(input, 0);
}
int main()
{
cout << "Hello World" << endl;
const char* inp = "alla";
vector<char> input(inp, inp + 4 );
permutation(input);
return 0;
}

The different for algorithms with or without duplicate would be when you swap it, make sure that the character that you want to swap has not been swapped before. Use hash map to keep track of what you have swapped before.
See the C# code below.
private void PermuteUniqueHelper(int[] nums, int index, List<IList<int>> res)
{
var used = new Dictionary<int, bool>();
if (index == nums.Length)
{
res.Add(new List<int>(nums));
return;
}
for (int i = index; i < nums.Length; i++)
{
if (!used.ContainsKey(nums[i]))
{
swap(nums[i], nums[index]);
this.PermuteUniqueHelper(nums, index + 1, res);
swap(nums[i], nums[index]);
used.Add(nums[i], true);
}
}
}

Related

Reversing the Character Case of a string

I'm stuck on a particular problem. I'm trying to take a string, and reverse the character cases in the string.
For Example: "HaVinG FuN" should flip to "hAvINg fUn."
I think it has something to do with my loop or my If/Else statements. What am I missing? All capitalized characters come out capitalized still. All lower case characters also come out capitalized as well... My other two functions are behaving correctly, but not my reverseFunct function... FYI I've omitted the other functions to try to cut-down on clutter and focus on my problem.
#include "stdafx.h"
#include <string>
#include <iostream>
#include <cctype>
#include <cstring>
using namespace std;
// Function Prototypes
void upperFunct(char *);
void lowerFunct(char *);
void reverseFunct(char *);
int main()
{
cout << "Enter a string: " << endl;
char ltrs [300];
cin.getline(ltrs, 300);
char *ptr = nullptr;
ptr = ltrs;
upperFunct(ptr);
lowerFunct(ptr);
reverseFunct(ptr);
return 0;
}
//----------------------------------//
void upperFunct(char *ltrptr)
{
int count = 0;
while (ltrptr[count] != '\0')
{
ltrptr[count] = toupper(ltrptr[count]);
count++;
}
{
cout << "---> toupper function: " << ltrptr << endl;
}
}
//------------------------------------//
void lowerFunct(char *ltrptr)
{
int count = 0;
while (ltrptr[count] != '\0')
{
ltrptr[count] = tolower(ltrptr[count]);
count++;
}
cout << "---> tolower function: " << ltrptr << endl;
}
//------------------------------------//
void reverseFunct(char *ltrptr) // <-----NOT REVERSING CHARACTERS
{
int count = 0;
while (ltrptr[count] != '\0')
{
if (isupper(ltrptr[count]))
{
ltrptr[count] = tolower(ltrptr[count]);
}
else
{
ltrptr[count] = toupper(ltrptr[count]);
}
count++;
}
cout << "---> reverse function: " << ltrptr << endl;
}
Your check for lowercase letters reads as
else if (islower(ltrptr[count]));
Notice the extra semicolon.
This semicolon terminates the if statement, and thus the succeeding conversion to uppercase is not a then-clause to this if statement but rather is executed unconditionally on every character.
Change like this
// Function Prototypes "HaVinG FuN" should flip to "hAvINg fUn."
void reverseFunct(char *);
int main()
{
//cout << "Enter a string: " << endl;
char ltrs[300] = "HaVinG FuN";
//cin.getline(ltrs, 300);
char *ptr = nullptr;
ptr = ltrs;
reverseFunct(ptr);
ptr = nullptr;
return 0;
}
void reverseFunct(char *ltrptr) // <-----NOT REVERSING CHARACTERS
{
int count = 0;
while (ltrptr[count] != '\0')
{
if (isupper(ltrptr[count]))
{
ltrptr[count] = tolower(ltrptr[count]);
}
else
{
ltrptr[count] = toupper(ltrptr[count]);
}
count++;
}
cout << "---> reverse function: " << ltrptr << endl;
}
You're writing C code. Here's a C++ way to do it:
#include <string>
#include <algorithm>
char reverse_case_char(char c) {
const auto uc = static_cast<unsigned char>(c); // Sic.
return ::isupper(uc)? ::tolower(uc): ::toupper(uc);
}
void reverse_case(std::string& str) {
std::transform(str.begin(), str.end(), str.begin(), reverse_case_char);
}
#include <cassert>
int main()
{
std::string fun = "HaVinG FuN";
reverse_case(fun);
assert(fun == "hAvINg fUn");
return 0;
}
Others have already pointed out the mistake in your code so no need to repeat that. Instead this answer will give some alternative ways of implementing the task.
Your code is more C-style than C++ style. C++ has a number of functions/features that will allow you to write this in much shorter forms.
char ltrs[300] = "HaVinG FuN";
for (auto& ch : ltrs) ch = islower(ch) ? toupper(ch) : tolower(ch);
std::cout << ltrs << std::endl;
or
char ltrs[300] = "HaVinG FuN";
std::for_each(ltrs, ltrs + strlen(ltrs), [](char& ch)
{ ch = islower(ch) ? toupper(ch) : tolower(ch); });
std::cout << ltrs << std::endl;
or using the std::string
std::string str("HaVinG FuN");
for (auto& ch : str) ch = islower(ch) ? toupper(ch) : tolower(ch);
std::cout << str << std::endl;
Using these C++ functions/features makes the program shorter, easier to understand and the risk of bugs is lower.
Thanks for the help!!! I ended up figuring out my answer, while being able to maintain my less-than elegant code that is fitting with my class. Bipll ended up giving me what I was after, something to think about in terms that my original array was being modified each time.
I realize that my solution is sloppy and not appropriate for a work environment, but it is in-line with my homework assignment, as our teacher is encouraging us to learn C++ from the ground-up, not getting too much direct answers from places like SO. So I'm glad I learned a bit from here, as well as an indirect way to help me see my issues.
I ended up making a copy of my original array, and just passing that copy to my last reversing function. I was able to use the original array for the first 2 functions because the 1st function capitalized each character in the array, while the 2nd made them all lowercase. The 3rd function, the reverse, therefore had to have access to the original array, but in the 3rd order. The easiest way for a noob like me, given where I am in the class, was to make a copy of the 1st array and use that for the 3rd function.
//Snippet of code I needed
int main()
{
int index = 0;
cout << "Enter a string: " << endl;
const int Size = 300;
char ltrs[Size];
cin.getline(ltrs, Size);
char arrayCopy[Size];
char *ptr = nullptr;
char *ptr2 = nullptr;
ptr = ltrs;
//Copy of ltrs Array
//----------------------------------//
while (ptr[index] != '\0') //
{ //
arrayCopy[index] = ptr[index]; //
index++; //
} //
arrayCopy[index] = '\0'; //
//
ptr2 = arrayCopy; //
//----------------------------------//
return 0;
}
// Function to Reverse
void reverseFunct(char *ltrptr)
{
int count = 0;
while (ltrptr[count] != '\0')
{
if (isupper(ltrptr[count]))
{
ltrptr[count] = tolower(ltrptr[count]);
}
else
{
ltrptr[count] = toupper(ltrptr[count]);
}
count++;
}
cout << "---> reverse function: " << ltrptr << endl;
}

How to add integers and strings in the same vector?

I need help for my university homework. i'm still new to this.
Basically i am doing a run-length encoding and i don't know how to add the letter after the counter:
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
void error(std::string str)
{
throw std::runtime_error(str);
}
int main()
{ int counter = 1;
std::string id;
std::vector<int> v;
std::cout << "Enter the data to be compressed: ";
std::cin >> id;
try
{ for(int i = 0; i < id.size(); i++)
{
if(std::isdigit(id[i]))
error("invalid input");
}
std::cout << "The compressed data is: ";
for(int i = 0; i < id.size(); i++)
{
if(id[i] == id[i+1])
{
counter++;
}
else if(id[i]!= id[i+1])
{
v.push_back(counter);
v.push_back(id[i]);
counter=1;
}
}
for(int j = 0; j < v.size(); j++)
std::cout << v[j];
}
catch(std::runtime_error& str)
{
std::cerr << "error: " << str.what() << std::endl;
return 1;
}
return 0;
}
For example if i input aaabbb, the probram should output 3a3b. The problem is that it outputs 397398 97 and 98 being the ascii code for a and b.
i don't know how to put the letter after the counter and for them to be in the same vector.
If you want to serialize as a string try this :
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
#include <sstream>
void error(std::string str) {
throw std::runtime_error(str);
}
int main() {
std::ostringstream stream;
int counter = 1;
std::string id;
std::cout << "Enter the data to be compressed: ";
std::cin >> id;
try {
for (int i = 0; i < id.size(); i++) {
if (std::isdigit(id[i]))
error("invalid input");
}
std::cout << "The compressed data is: ";
for (int i = 0; i < id.size(); i++) {
if (id[i] == id[i + 1]) {
counter++;
} else if (id[i] != id[i + 1]) {
stream << counter;
stream << (char) id[i];
counter = 1;
}
}
std::cout << stream.str() << std::endl;
} catch (std::runtime_error& str) {
std::cerr << "error: " << str.what() << std::endl;
return 1;
}
}
v[j] from std::cout << v[j] is of type int and that is why std::cout writes a number. To write it as a character, you should cast v[j] to char as follows: std::cout << (char)v[j]. In this way, std::cout will use the char specialization, not the int one.
While the other answers might give you the output you need, I believe the idiomatic way to solve this is using a class to hold both the character and its count. There are two obvious choices.
std::pair
Could also be std::tuple if you prefer it for consistency or whatever reason. Save your results in a std::vector<std::pair<char, int>. This saves the information, but to print it you would need to define an appropriate function. Add elements via
v.emplace_back(character, count);
Wrapper Class
If you want to offer some functionality without outside helper classes, define a custom wrapper class such as the following.
class CharacterCount {
private:
char character;
int count;
public:
CharacterCount(char character, int count):
character(character), count(count) {}
explicit operator std::string() const { return std::to_string(count) + character;
// Other helper functions or constructors you require
}
This simplifies printing
for (auto& character_count : v)
std::cout << static_cast<std::string>(character_count);
I believe because std::ostream::operator<< is templated, you cannot get an implicit conversion to std::string to work. I would advise against implicit conversion anyway.
You can use the same emplace_back syntax as before because we offer an appropriate constructor.
So you take your input in a string and ultimately just need to stream this information out, ultimately meaning there's really no reason to store the information in a vector, just output it! You can use find_if with a lambda to find the non-consecutive character (or find_if_not if you prefer.)
for(string::const_iterator finish, start = cbegin(id); start != cend(id); start = finish) {
finish = find_if(start, cend(id), [value = *start](const auto i) { return i != value; } );
cout << distance(start, finish) << *start;
}
Live Example

String to double conversion without sstream or boost lexical cast

Hey guys I have a question about my code. Here's what we have to do:
"Ask the user to read a file. The file will be in the same format as “items.txt” on the website. There will
always be a list of items with a name and price followed by some amount of recipes. If a recipe for an
item is not present, the only way to make the item is to buy it directly. Make a program that reads all
the items and recipes, then says how much profit can be made by making each item.
If an item has no recipe, you would buy that item then resell it for the same price and make a profit of
0. If an item does have a recipe, you would buy the materials to make this item and subtract this cost
from the price of the final product.
There will only be zero or one recipe per item. The items will always be listed first. The names of
items will always be a single word (using a _ to join names that are normally multiple words). You
may assume there will be less than 50 items and each recipe will use less than 50 other items to create a
final product."
This is the items1.txt we use
Item: Wood 2.5
Item: Metal 5.5
Item: Cat 900
Item: Spear 50.7
Recipe: Spear = Wood + Wood + Metal ;
I have what I think would work but I can't get a certain line to work. I'm trying to use stod but apparently my school's computers don't support it. I also tried boost lexical cast and that wouldn't work either.
It says "stod: was not declared in this scope.
Here's my code:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <algorithm>
#include <sstream>
using namespace std;
string nextstring(string str, int start_index);
int split(string str, string a[], int max_size);
int main()
{
ifstream in_stream;
string fileName;
cout << "Enter the file name : ";
cin >> fileName;
in_stream.open(fileName.c_str());
//error checking
if (in_stream.fail())
{
cout << "File could not be opened." << endl;
exit(1);
}
string items[50];
double items_value[50];
string recipe[50];
string rname = recipe[0];
double profit = 0;
int j = 0;
string lines;
int number_of_lines = 0;
while(getline(in_stream, lines))
{
if(lines.substr(0,5) == "Item:")
{
int beginning = lines.find_first_of(' ') + 1;
int next_space = lines.find(" ", beginning);
items_value[j] = stod(lines.substr(next_space));
items[j] = lines.substr(beginning,lines.find_first_of(' ', beginning) - beginning);
j++;
}
if(lines.substr(0,7) == "Recipe:")
{
int max_size = lines.length();
int cnt = split(lines,recipe,max_size);
double profit1 = 0;
double profit2 = 0;
for(int j = 3; j < cnt; j++)
{
for(int i = 0; i < 4; i++)
{
if((recipe[j] == items[i]) && (recipe[j] != "+")&& (recipe[j] != ";"))
{
cout << "Making " << items[i] << ", " << "profit = 0" << endl;
profit1 += items_value[i];
}
if(recipe[1] != items[i])
{
profit2 = 0;
}
}
}
for(int i = 0; i < cnt; i++)
{
if((recipe[1] == items[i]))
{
profit = items_value[i];
cout << "Making " << items[i] << ", " << "profit = ";
}
}
cout << profit - profit1 << endl;
}
}
in_stream.close();
return 0;
}
string nextstring(string str, int start_index)
{
int y =0;
y = str.find(' ',start_index);
y = y-start_index;
str = str.substr(start_index,y);
return str;
}
int split(string str, string a[], int max_size)
{
int i;
int num = 0;
for (i=0; i<max_size; i++)
{
a[i] = nextstring(str,num);
num = num + a[i].length() + 1;
if(num >= str.length())
{
i++;
break;
}
}
return i;
}
First step is get a decent compiler from this century ;) stod has been available since c++11, which really means that it was available probably a few years before that.
If stod isn't available to you then you can revert to the cstdlib function atof.

Using a tokenizer in C++ from a file?

I am working on an assignment that requires me to read in several lines of text from a file, and at the end use qsort to sort the words used alphabetically and display a count of how many times each word was used. I realized I'm going to have to tokenize the strings as they are read in from the file. The only problem is that the individual tokens kind of disappear after you do it so I have to add them to a list. I'm bad at explaining, so here's my code:
#include<iostream>
#include<string>
#include<algorithm>
#include<stdlib.h>
#include<fstream>
using namespace std;
int compare(const void* , const void*);
const int SIZE = 1000;
const int WORD_SIZE = 256;
void main()
{
cout << "This program is designed to alphabetize words entered from a file." << endl;
cout << "It will then display this list with the number of times " << endl;
cout << "that each word was entered." << endl;
cout << endl;
char *words[SIZE];//[WORD_SIZE];
char temp[100];
char *tokenPtr, *nullPtr= NULL;
char *list[SIZE];
string word;
int i = 0, b = 0;
ifstream from_file;
from_file.open("prob1.txt.txt");
if (!from_file)
{
cout << "Cannot open file - prob1.txt";
exit(1); //exits program
}
while (!from_file.eof())
{
from_file.getline(temp, 99);
tokenPtr = strtok(temp, " ");
while (tokenPtr != NULL)
{
cout << tokenPtr << '\n';
list[b] = tokenPtr;
b++;
tokenPtr = strtok(nullPtr, " ");
}
word = temp;
transform(word.begin(), word.end(), word.begin(), ::tolower);
words[i] = list[i];
i++;
}
from_file.close();
qsort(words, i, WORD_SIZE, compare);
int currentcount = 1 ;
int k;
for( int s = 0; s < i; s++ )
{
for( k = 1; k <= s; k++)
{
if( words[s] == words[k] )
{
currentcount++;
}
currentcount = 1;
words[k] = "";
}
cout << words[s] << " is listed: " << currentcount << " times." << endl;
words[s] = "";
}
}
int compare(const void* p1, const void *p2)
{
char char1, char2;
char1 = *(char *)p1; // cast from pointer to void
char2 = *(char *)p2; // to pointer to int
if(char1 < char2)
return -1;
else
if (char1 == char2)
return 0;
else
return 1;
}
The only thing missing is the compare function, but the program works fine, up until the qsort, wherein it crashes, but it doesn't tell me why. Can anybody shed some insight/help me fix this up?
Again, this IS an assignment. (I was told I need to specify this?)
The array words is an array of pointers to char:
char* words[SIZE]; // SIZE elements of type `char*`
So the third parameter WIDTH should be the width of a pointer to char.
qsort(words, i, sizeof(char*), compare);
Also your implementation of compare is not working as you expect.
You are passing pointers to the compare. But they are pointers at the elements. You need to de-reference the pointers to get the values:
int compare(const void* p1, const void *p2)
{
char const* x = *(char**)p1;
char const* y = *(char**)p2;
This does not compare strings:
if( words[s] == words[k] )
This just compares two pointers. To compare the strings they point at use strcmp()
if( strcmp(words[s], words[k]) == 0)
This should stop the crashes, but there is a lot more improvements to this code we can do:
Once you get it working you should post it here https://codereview.stackexchange.com/ for a review.

How can I modifiy my c++ program to show a word inputted by a user, backwards using a stack?

I want to assign a pointer to every character the user inputs. Then in doing so, I probably can use a loop to store the characters and a second loop rearrange the stack order using the pointers. But I don't know how to write that in a program form, and I'm not sure if it can work. Here is what I have so far:
#include<iostream>
using namespace std;
class Stack{
public:
enum {MaxStack = 50};
void init() {top = -1;}
void push( char n ){
if ( isFull() ) {
cerr << "Full Stack. DON'T PUSH\n";
return;
}
else {
arr[ ++top ] = n;
cout << "Just pushed " << n << endl;
return;}
}
int pop() {
if (isEmpty() ) {
cerr << "\tEmpty Stack. Don't Pop\n\n";
return 1;
}
else
return arr[top--];
}
bool isEmpty() {return top < 0 ? 1 : 0;}
bool isFull() {return top >= MaxStack -1 ? top : 0;}
void dump_stack() {
cout << "The Stack contents, from top to bottom, from a stack dump are: " << endl;
for (int i = top; i >= 0; i--)
cout << "\t\t" << arr[i] << endl;
}
private:
int top;
int arr[MaxStack];
};
int main()
{
Stack a_stack;
int x = 0;
char inputchar;
cout<<"Please enter a word"<<endl;
a_stack.init();
while (inputchar != '.') //terminating char
{
cin >> inputchar;
array[x] = inputchar;
x++;
}
int j = x;
for (int i = 0; i < j; i++)
{
cout << array[x];
x--;
}
a_stack.push();
a_stack.dump_stack();
return 0;
}
A stack, by its very LIFO nature (Last In, First Out), will reverse the order of anything you put in it. Example for string "Hello":
(The top of the stack is to the left)
H push "H"
eH push "e"
leH push "l"
lleH push "l"
olleH push "o"
Now when you pop from the stack, you'll first get "o", then "l", etc. It's whatever you put in but in reverse order. You don't need to do anything special to achive that. Just push to stack in normal order, and when you pop you'll get it reversed:
// while loop
{
cin >> inputchar;
a_stack.push(inputchar);
}
// Display in reverse
while (not a_stack.isEmpty()) {
cout << (char)a_stack.pop();
}
Here's a small example program using std::stack:
(No input error checking is done here.)
#include <iostream>
#include <stack>
int main()
{
std::stack<char> st;
char c = '\0';
while (c != '.') {
c = std::cin.get();
st.push(c);
}
while (not st.empty()) {
std::cout << st.top();
st.pop();
}
std::cout << '\n';
}
Example input and output:
Hello world.
.dlrow olleH
Unless using a stack is a must (i.e. it is a homework), you might be better off with getline(), its parameter delim (cf getline) followed by a reverse loop over the array. It would be faster, cleaner, less prone to errors and basically a two-liner.