Typo searching for at least 1 character - c++

The original prompt was:
Write a program that keeps track of a speakers bureau. The program should use a
structure to store the following data about a speaker:
Name
Telephone Number
Speaking Topic
Fee Required
The program should use an array of at least 10 structures. It should let the user enter
data into the array, change the contents of any element, and display all the data stored
in the array. The program should have a menu-driven user interface.
Input Validation: When the data for a new speaker is entered, be sure the user enters
data for all the fields. No negative amounts should be entered for a speaker s fee.
The added prompt was:
I need this to expand the search pattern with the potential one character of letter or digit typos. Only one character maybe a typo, in any position Try these test patterns should get the following results:
0-9 is 0x30-0x39
a-z is 0x41-0x5A
A-Z is 0x61-0x7A (or lower case it)
And I can't get the added prompt to work with my current program.
No other characters in the search pattern may be changed.
#include <iostream>
#include <cstring>
#include<string>
using namespace std;
bool print_one_typo(string input, string people[11], bool is_found[11])
{
bool found = false;
if (input[0] == '?')
{
char *strPtr = NULL;
for (int i = 0; i < 11; i++)
{
strPtr = strstr(people[i].c_str(), input.substr(1).c_str());
if (strPtr != NULL)
{
cout << "\t" << people[i] << endl;
found = true;
is_found[i] = true;
}
}
}
else
{
for (int i = 0; i < 11; i++)
{
bool match = true;
string str = people[i];
int value = str.find(input[0]);
for (int k = 0; k < input.length(); k++)
{
if (input[k] != '?' && input[k] != str[value++])
{
match = false;
break;
}
}
if (match && !is_found[i])
{
found = true;
cout << "\t" << people[i] << endl;
}
}
}
return found;
}
int main()
{
string people[11] = { "Becky Warren, 555-1223",
"Joe Looney, 555-0097",
"Geri Palmer, 555-8787",
"Lynn Presnell, 555-1225",
"Holly Gaddis, 555-8878",
"Sam Wiggins, 555-0998",
"Bob Kain, 555-8712",
"Tim Haynes, 555-7676",
"Warren Gaddis, 555-9037",
"Jean James, 555-9223",
"Ron Palmer, 555-7227" };
bool is_found[11] = { false };
string lookUp;
int i;
cout << "\t People and Phone numbers" << endl;
cout << "Enter name or phone number: ";
cin >> lookUp;
cout << "result: " << endl;
bool found = false;
bool output = false;
for (int i = 0; i < lookUp.length(); i++)
{
string local = lookUp;
found = print_one_typo(local.replace(i, 1, 1, '?'), people, is_found);
if (found) output = true;
}
if (!output)
cout << "No matching product was found" << endl;
return 0;
}

I think your code overthinks the problem. Also, you didn't specify if "typo" just means "wrong character", or a fuller range that includes dropped characters or inserted characters.
If you are only looking for matches with zero or one incorrect characters, but otherwise the same length, I think this code should do:
bool print_one_typo(string input, string people[11], bool is_found[11])
{
for (int i = 0; i < 11; i++)
{
if ( is_found[i] ) // Skip if it had already been found?
continue;
if ( input.length() != people[i].length() ) // Are they same length?
continue; // No: Skip it.
int typos = 0;
size_t len = input.length();
for (size_t j = 0; j != len && typos < 2; j++)
if ( input[j] != people[i][j] )
typos++;
if (typos < 2) // Fewer than 2 typos: We have a winner! Return it.
{
is_found[i] = true;
return true;
}
}
return false;
}
This code skips strings that differ in length, or which you're filtering out via the is_found[] array. Not sure why you're doing that, but I preserved that bit of your original code.
If it finds two strings that are the same length, it just compares them character by character, counting up typos. If it sees 2 or more typos, it skips to the next one. Otherwise, it takes the first string that's the same length but fewer than 2 typos.

Related

Why is my array always giving a true answer?

My code here says that all values are true even if they aren't in the array. What am I doing wrong? For instance, I could input Chicago, and it will say "City found." I have tried to change the order around and change the "if(foundIt) to if(foundIt = true). It will still do the same.
// MichiganCities.cpp - This program prints a message for invalid cities in Michigan.
// Input: Interactive
// Output: Error message or nothing
#include <iostream>
#include <string>
using namespace std;
int main()
{
// Declare variables
string inCity; // name of city to look up in array
const int NUM_CITIES = 10;
// Initialized array of cities
string citiesInMichigan[] = {"Acme", "Albion", "Detroit", "Watervliet", "Coloma", "Saginaw", "Richland", "Glenn", "Midland", "Brooklyn"};
bool foundIt = false; // Flag variable
int x; // Loop control variable
// Get user input
cout << "Enter name of city: ";
cin >> inCity;
// Write your loop here
for(int i = 0; i < NUM_CITIES; i++){
if (x = i)
foundIt = true;
}
// Write your test statement here to see if there is
// a match. Set the flag to true if city is found.
if (foundIt)
cout << "City found." << endl;
else cout << "Not a city in Michigan." << endl;
// Test to see if city was not found to determine if
// "Not a city in Michigan" message should be printed.
return 0;
} // End of main()
This loop
for(int i = 0; i < NUM_CITIES; i++){
if (x = i)
foundIt = true;
}
does not make sense. There is used an assignment in the if statement of the control variable i to the variable x.
if (x = i)
It seems you mean at least
for(int i = 0; !foundIt && i < NUM_CITIES; i++){
if ( inCity == citiesInMichigan[i] )
foundIt = true;
}
If you need the index of the found city then the loop can look like
size_t i = 0;
while ( i < NUM_CITIES && inCity != citiesInMichigan[i] ) i++;
if ( i != NUM_CITIES )
{
// the city is found at position i
}
else
{
// the sity is not found
}

Connecting n pipes linux

I was studying about pipes recently and saw this answer:
Connecting n commands with pipes in a shell?
I was intrigued about it and tried to make like a "dynamic" one, in which I introduce a string with n process and then execute the n process (i.e ls | sort). I was trying to tokenize, save in an array, but it did not work. Here is my code of my "tokenizer":
int main()
{
char str[] = "ls | sort";
int length = (sizeof(str) / sizeof(*str))-1;
int sizeCMD = 1; //If the string has zero pipe, it means it has at least 1 process
vector<char> tempV;
for (int i = 0; i < length; i++)
{
if (str[i] == '|')
{//If the string has one |, it means it has at least 2 process.
sizeCMD++;
}
tempV.push_back(str[i]);//I was going to do something else with this, but I forgot.
//cout<<i<<" "<<tempV.at(i)<<endl;
}
int j = 0;//Current position of the cmd
string comLetter = "";//it will save every single letter in certain conditions
string comLine = "";//it will save all the characters of comLetter in certain conditions
struct command cmd[sizeCMD];
const char *ls[2];
const char *sort[2];
const char *toCChar;
for (int i = 0; i < tempV.size(); i++)
{
if (tempV.at(i) != ' ' && tempV.at(i) != '|')
{//comLetter will only save characters that are not equal to blank or |.
//cout<<tempV.at(i);
comLetter += tempV.at(i);
//cout<< comLetter <<endl;
}
if (tempV.at(i) == ' ' || i == tempV.size() - 1)
{//comLine will save everything of comLetter when it detects a blank or the very end
//cout<<comLetter<<endl;
comLine = comLetter;
comLetter = "";
}
if (tempV.at(i) == '|' || i == tempV.size() - 1)
{//cmd will save everything of comLine when it detects a | or the very end.
//cout<<j<<endl;
cout << "." << comLine << "." << endl;
//cout<<i<<endl;
//cout<<toCChar<<endl;
if(comLine == "ls"){
toCChar = comLine.c_str();
ls[0] = toCChar;
ls[1] = 0; //THIS IF
cmd[0] = {ls}; //WORKS
}
if(comLine == "sort"){
sort[0] = "sort";
sort[1] = 0; //THIS IF
cmd[1] = {sort}; //WORKS
}
/*const char *ls[2];
cout<<toCChar<<endl;
ls[0] = toCChar;
ls[1] = 0;
cout<< *ls[0] << " - "<< endl;
cmd[j] = {ls};
//cout << cmd << endl;
comLine = "";*/
j++; //The position will move by one.
}
}
return fork_pipes(sizeCMD, cmd);
}
Everything made sense to me, until I found out that const char* can't be temporal as it needs the data, so I need to create 2 const char* arrays for 2 commands. That's why I've two arrays: *sort[] and *ls[], for sort and ls.
Also, I was wondering, why these lines get "ignored":
toCChar = comLine.c_str();
ls[0] = toCChar;
I'm struggling right now, if someone could please help/guide me on how to do it, I would appreciate that.

What's wrong with my dynamic programming algorithm with memoization?

*Sorry about my poor English. If there is anything that you don't understand, please tell me so that I can give you more information that 'make sence'.
**This is first time asking question in Stackoverflow. I've searched some rules for asking questions correctly here, but there should be something I missed. I welcome all feedback.
I'm currently solving algorithm problems to improve my skill, and I'm struggling with one question for three days. This question is from https://algospot.com/judge/problem/read/RESTORE , but since this page is in KOREAN, I tried to translate it in English.
Question
If there are 'k' pieces of partial strings given, calculate shortest string that includes all partial strings.
All strings consist only lowercase alphabets.
If there are more than 1 result strings that satisfy all conditions with same length, choose any string.
Input
In the first line of input, number of test case 'C'(C<=50) is given.
For each test case, number of partial string 'k'(1<=k<=15) is given in the first line, and in next k lines partial strings are given.
Length of partial string is between 1 to 40.
Output
For each testcase, print shortest string that includes all partial strings.
Sample Input
3
3
geo
oji
jing
2
world
hello
3
abrac
cadabra
dabr
Sample Output
geojing
helloworld
cadabrac
And here is my code. My code seems to work perfect with Sample Inputs, and when I made test inputs for my own and tested, everything worked fine. But when I submit this code, they say my code is 'wrong'.
Please tell me what is wrong with my code. You don't need to tell me whole fixed code, I just need sample inputs that causes error with my code. Added code description to make my code easier to understand.
Code Description
Saved all input partial strings in vector 'stringParts'.
Saved current shortest string result in global variable 'answer'.
Used 'cache' array for memoization - to skip repeated function call.
Algorithm I designed to solve this problem is divided into two function -
restore() & eraseOverlapped().
restore() function calculates shortest string that includes all partial strings in 'stringParts'.
Result of resotre() is saved in 'answer'.
For restore(), there are three parameters - 'curString', 'selected' and 'last'.
'curString' stands for currently selected and overlapped string result.
'selected' stands for currently selected elements of 'stringParts'. Used bitmask to make my algorithm concise.
'last' stands for last selected element of 'stringParts' for making 'curString'.
eraseOverlapped() function does preprocessing - it deletes elements of 'stringParts' that can be completly included to other elements before executing restore().
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#define MAX 15
using namespace std;
int k;
string answer; // save shortest result string
vector<string> stringParts;
bool cache[MAX + 1][(1 << MAX) + 1]; //[last selected string][set of selected strings in Bitmask]
void restore(string curString, int selected=0, int last=0) {
//base case 1
if (selected == (1 << k) - 1) {
if (answer.empty() || curString.length() < answer.length())
answer = curString;
return;
}
//base case 2 - memoization
bool& ret = cache[last][selected];
if (ret != false) return;
for (int next = 0; next < k; next++) {
string checkStr = stringParts[next];
if (selected & (1 << next)) continue;
if (curString.empty())
restore(checkStr, selected + (1 << next), next + 1);
else {
int check = false;
//count max overlapping area of two strings and overlap two strings.
for (int i = (checkStr.length() > curString.length() ? curString.length() : checkStr.length())
; i > 0; i--) {
if (curString.substr(curString.size()-i, i) == checkStr.substr(0, i)) {
restore(curString + checkStr.substr(i, checkStr.length()-i), selected + (1 << next), next + 1);
check = true;
break;
}
}
if (!check) { // if there aren't any overlapping area
restore(curString + checkStr, selected + (1 << next), next + 1);
}
}
}
ret = true;
}
//check if there are strings that can be completely included by other strings, and delete that string.
void eraseOverlapped() {
//arranging string vector in ascending order of string length
int vectorLen = stringParts.size();
for (int i = 0; i < vectorLen - 1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].length() < stringParts[j].length()) {
string temp = stringParts[i];
stringParts[i] = stringParts[j];
stringParts[j] = temp;
}
}
}
//deleting included strings
vector<string>::iterator iter;
for (int i = 0; i < vectorLen-1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].find(stringParts[j]) != string::npos) {
iter = stringParts.begin() + j;
stringParts.erase(iter);
j--;
vectorLen--;
}
}
}
}
int main(void) {
int C;
cin >> C; // testcase
for (int testCase = 0; testCase < C; testCase++) {
cin >> k; // number of partial strings
memset(cache, false, sizeof(cache)); // initializing cache to false
string inputStr;
for (int i = 0; i < k; i++) {
cin >> inputStr;
stringParts.push_back(inputStr);
}
eraseOverlapped();
k = stringParts.size();
restore("");
cout << answer << endl;
answer.clear();
stringParts.clear();
}
}
After determining which string-parts can be removed from the list since they are contained in other string-parts, one way to model this problem might be as the "taxicab ripoff problem" problem (or Max TSP), where each potential length reduction by overlap is given a positive weight. Considering that the input size in the question is very small, it seems likely that they expect a near brute-force solution, with possibly some heuristic and backtracking or other form of memoization.
Thanks Everyone who tried to help me solve this problem. I actually solved this problem with few changes on my previous algorithm. These are main changes.
In my previous algorithm I saved result of restore() in global variable 'answer' since restore() didn't return anything, but in new algorithm since restore() returns mid-process answer string I no longer need to use 'answer'.
Used string type cache instead of bool type cache. I found out using bool cache for memoization in this algorithm was useless.
Deleted 'curString' parameter from restore(). Since what we only need during recursive call is one previously selected partial string, 'last' can replace role of 'curString'.
CODE
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#define MAX 15
using namespace std;
int k;
vector<string> stringParts;
string cache[MAX + 1][(1 << MAX) + 1];
string restore(int selected = 0, int last = -1) {
if (selected == (1 << k) - 1) {
return stringParts[last];
}
if (last == -1) {
string ret = "";
for (int next = 0; next < k; next++) {
string resultStr = restore(selected + (1 << next), next);
if (ret.empty() || ret.length() > resultStr.length())
ret = resultStr;
}
return ret;
}
string& ret = cache[last][selected];
if (!ret.empty()) {
cout << "cache used in [" << last << "][" << selected << "]" << endl;
return ret;
}
string curString = stringParts[last];
for (int next = 0; next < k; next++) {
if (selected & (1 << next)) continue;
string checkStr = restore(selected + (1 << next), next);
int check = false;
string resultStr;
for (int i = (checkStr.length() > curString.length() ? curString.length() : checkStr.length())
; i > 0; i--) {
if (curString.substr(curString.size() - i, i) == checkStr.substr(0, i)) {
resultStr = curString + checkStr.substr(i, checkStr.length() - i);
check = true;
break;
}
}
if (!check)
resultStr = curString + checkStr;
if (ret.empty() || ret.length() > resultStr.length())
ret = resultStr;
}
return ret;
}
void EraseOverlapped() {
int vectorLen = stringParts.size();
for (int i = 0; i < vectorLen - 1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].length() < stringParts[j].length()) {
string temp = stringParts[i];
stringParts[i] = stringParts[j];
stringParts[j] = temp;
}
}
}
vector<string>::iterator iter;
for (int i = 0; i < vectorLen - 1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].find(stringParts[j]) != string::npos) {
iter = stringParts.begin() + j;
stringParts.erase(iter);
j--;
vectorLen--;
}
}
}
}
int main(void) {
int C;
cin >> C;
for (int testCase = 0; testCase < C; testCase++) {
cin >> k;
for (int i = 0; i < MAX + 1; i++) {
for (int j = 0; j < (1 << MAX) + 1; j++)
cache[i][j] = "";
}
string inputStr;
for (int i = 0; i < k; i++) {
cin >> inputStr;
stringParts.push_back(inputStr);
}
EraseOverlapped();
k = stringParts.size();
string resultStr = restore();
cout << resultStr << endl;
stringParts.clear();
}
}
This algorithm is much slower than the 'ideal' algorithm that the book I'm studying suggests, but it was fast enough to pass this question's time limit.

find substring in a string with loops in c++

The code will get two string from user and checks the string , includes substring as the second input or not.
string st1;
string subst1;
string message = " ";
cout << "Enter string and subst:";
cin >> st1;
cin >> subst1;
for (int a=0; a < st1.length(); a++) {
if (st1[a] == subst1[0]) {
for (int k = 0; k < subst1.length(); k++) {
if (st1[a + k] == subst1[k])
message = "True";
else
message = "False";
}
}
}
cout << message;
This code does not work inputs like "alice" and "ba". The output should be false but when I execute the code program directly ended
Because in some cases a + k exceeds the length of the string st1:
if (st1[a + k] == subst1[k]) {
message = "True";
}
before executing this statement, verify if a + k < st1.length()
but another remark:
when message becomes False you must stop comparison else the variable message might be again True.
Why not use find():
string st1, subst1, message=" ";
cout<<"Enter string and subst:";
cin>>st1>>subst1;
if (st1.find(subst)==string::npos)
message="Not found";
else message ="Found";
If you're not allowed to use this approach, then I propose you the following:
string st1, subst1, message=" ";
bool found=false;
cout<<"Enter string and subst:";
cin>>st1 >>subst1;
for (int a=0; !found && a<st1.length();a++) {
if (st1[a]==subst1[0]) {
found = true; // there's some hope
for (int k=0; found && k<subst1.length(); k++) {
if (a+k>=st1.length() || st1[a+k]!=subst1[k]) // oops! might overflow or fail
found = false; // this will also end the inner loop
}
}
}
message = found ? "True":"False";
cout<< message<<endl;
The principle is that for a compare to be successfull, all chars must be equal. But if a single char fails, you shall stop the failed comparison.
Here a live demo

Print duplicates of strings

I am working a code that will find the amount of duplicated words from a imported file.
The input stream represents a file containing a series of lines. The function should
examine each line looking for consecutive occurrences of the same token on the same line and
print each duplicated token along how many times it appears consecutively. Non-repeated
tokens are not printed.
Here is what I have:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
using namespace std;
int main()
{
ifstream in("file.txt");
if (! in)
{
cerr << "Could not open file.txt.";
return EXIT_FAILURE;
}
string str;
int count = 0;
int len=str.length();
while(getline(in,str)){
for(int i = 0; i < len; i++){
if(str.at(i) == str.at(i+1)){
count++;
}
else if(str.at(i) != str.at(i+1)){
i++;
}
}
cout << str << "*" << count << endl;
}
}
The .txt contains:
hello how how are you you you you
I I I am Jack's Jack's smirking smirking smirking smirking smirking revenge
bow wow wow yippee yippee yo yippee yippee yay yay yay
one fish two fish red fish blue fish
It's the Muppet Show, wakka wakka wakka
The output should be:
how*2 you*4
I*3 Jack's*2 smirking*5
wow*2 yippee*2 yippee*2 yay*3
wakka*3
a=list('this is my laptop')
b=list(set(a))
for i in b:
if i==' ':
continue
c=a.count(i)
if c>1:
print('{} is {}'.format(i,c))
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;
int main()
{
ifstream in("file.txt");
if(!in){
cerr << "Could not open file.txt.";
return EXIT_FAILURE;
}
string str;
string str2;
string n;
string tab[100];
string tab3[100];
unsigned int tab2[100];
unsigned int tab4[100];
unsigned int i = 0;
unsigned int k = 0;
unsigned int l = 0;
unsigned int tablenght;
unsigned int tablenght2;
k = 0;
//it reads every line of text in file str2
while(getline(in,str2)){
//it add every line of text str2 to str so you get whole file text
str += str2;
str += ' ';
//you need to add a character to mark where was the new line
str += "0 ";
}
for(i = 0; i < str.length(); i++){
/*you check every single character in string str if that char is not
space than it writes it to string table tab, if that char is space than it
adds one to your index so it will write down the next word in next
index of table tab*/
if(str[i] != ' '){
tab[k] += str[i];
}else{
k++;
//that is for two spaces
if(str[i+1] == ' '){
k--;
}
}
}
//k+1 is actually how many words and indexes you wrote to table tab
tablenght = k+1;
l = 0;
k = 0;
for(i = 0; i < tablenght; i++){
//you need to reset the number of repeats k to zero if you go to another line
if(tab[i] == "0"){
k = 0;
}
//there you get the number k how many times does some word repeats itself
if(tab[i] == tab[i+1]){
k++;
//you need to reset k if tab current is not equal to tab next
}else{
k = 0;
}
//there you store k values into integer table tab2
tab2[l] = k+1;
l++;
}
l = 0;
/*there you need to check if current string of table tab is equal to next string
in table tab and if it is you need to set next string to tab3[l] if you dont do
that you get something like that you*4 you*4 you*4 you*4 instead of only you*4*/
for(i = 0; i < tablenght-1; i++){
if(tab[i] == tab[i+1]){
tab3[l] = tab[i+1];
tab4[l] = tab2[i];
}else{
l++;
}
if(tab[i+1] == "0"){
tab3[l] = tab[i+1];
}
k++;
}
tablenght2 = l;
//there you cout both tables
for(i = 0; i < tablenght2; i++){
/*you need to check if number is bigger than 1 because it need to cout only
the words that repeats itself for more than one time than you need to check
that table tab3 doesnt contain string with zero that we previously added
that we could check later if it needs to go in another line and we
need to check that tab3 index is not empty*/
if(tab4[i] > 1 && tab3[i] != "0" && !tab3[i].empty()){
cout << tab3[i] << "*" << tab4[i] << " ";
}
/*thats the zero that we wrote to table in the begining and that we can now
write a new line*/
if(tab3[i] == "0"){
cout << endl;
}
}
return 0;
}