Searching a string inside a char array using Divide and Conquer - c++

Let's say that I have a struct array and each element has a name. Like:
struct something{
char name[200];
}a[NMAX];
Given a new string (char array), i need to find the correct index for it using divide and conquer. Like:
char choice[200];
cin>>chioce;
int k=myFunction(choice); // will return the index, 0 otherwise
// of course, could be more parameters
if( k )
cout<<k;
I don't know how to create that searching function (I tried, I know how D&C works but i'm still learning! ).
And no, i don't want to use strings !
This is what i tried:
int myFunction(char *choice, int l,int r) // starting with l==0 && r==n-1
{
int m;
if(strcmp(a[m].name,choice)==0)
return m;
else{
m=(l+r)/2;
return myFunction(choice,l,m-1);
return myFunction(choice,m+1,r);
}
}

This is my solution for your above problem. But i have modified a few things in your code.
#include<iostream>
using namespace std;
#define NMAX 10
struct something{
char *name; //replaced with char pointer so that i can save values the way i have done
}a[NMAX];
int myFunction(char *choice, int l,int r) // starting with l==0 && r==NMAX-1
{
if(l>r) //return if l has become greater than r
return -1;
int m=(l+r)/2;
if(strcmp(a[m].name,choice)==0)
return m+1;
else if(l==r) //returned -1 as the value has not matched and further recursion is of no use
return -1;
else{
int left= myFunction(choice,l,m-1);//replaced return
int right= myFunction(choice,m+1,r);//by saving values returned
if(left!=-1) //so that i can check them,
return left; //otherwise returning from here onlywould never allow second satatement to execute
if(right!=-1)
return right;
else
return -1;
}
}
int main(){
a[0].name="abc";
a[1].name="a";
a[2].name="abcd";
a[3].name="abcf";
a[4].name="abcg";
a[5].name="abch";
a[6].name="abcj";
a[7].name="abck";
a[8].name="abcl";
a[9].name="abcr";
char choice[200];
cin>>choice;
int k=myFunction(choice,0,NMAX-1); // will return the index, 0 otherwise
// of course, could be more parameters
if( k !=-1)
cout<<k;
else
cout<<"Not found";
return 0;
}
Hope it will help.

Related

Binary Search Recursion warning

#include <iostream>
using namespace std;
int i = 0;
int binarySearch(int arr[],int left, int right, int item)
{
int midpoint;
bool found{false};
if(left < right && !found)
{
midpoint = left + (right - left)/2;
if(arr[midpoint]<item)
{
binarySearch(arr,midpoint+1,right,item);
}
else if(arr[midpoint]>item)
{
binarySearch(arr,left,midpoint-1,item);
}
else
{
found = true;
return midpoint;
}
}
}
int main()
{
int arr[] = {10,20,30,40};
int x = binarySearch(arr,0,3,40);
cout << x ;
}
How is it returning the correct value of the item searched for although its not even reaching the return statement.
It is reaching the base case when it is only one element in the array, but it should not reach the return statement, thus it should return garbage, but it is returning the correct index every time.
In most cases you don't return any value so you get whatever happens to be in the result register or stack slot at the time. This can work by accident, if you are unlucky.
Turn on compiler warnings and always fix them. Best to turn warnings into errors.

return statement in recursive function

I am trying to write a recursive function for linear search in an array which also returns the first index at which the element is found.
int linearSearch(int *A, int size, int val)
{
if(size>0)
{
if(*A==val)
{
cout<<val<<" is found in the array!";
return i;
}
else
{
linearSearch(A+1,size-1,val);
i++;
}
}
else
{
cout<<val<<" is not there in the array!";
return -1;
}
}
However, when I am trying to catch the valued returned in the main function, value of size is returned instead of -1 in the case when the element is not present in the array. I am not able to figure out why is that happening.
Try this. I added a couple of comments in the code so you can understand it better.
/* i is the initial position. When you are making a call to linearSearch it should be set to 0 */
int linearSearch(int *A, int size, int val, int i)
{
/* When you reach end of the array and havent found value, then return -1 */
/* Every recursive function should have an exit condition */
if(i == size)
return -1;
/* when we found a value return the index */
if (A[i] == val)
return i;
else
/* If not then move to the next value in the array by incrementing index and recurse */
return linearSearch(A, size, val, i + 1);
}

replace all negative value from array using recursion C

I want replace all negative value by zero(recursively). And I have use C and recursion. It's was my homework.
Desired output:
0 4 0 3
What I get:
0 4 -9 3
My code:
#include <stdio.h>
int zeros_value(int n, int tab[])
{
if (n==0) return 0;
if(tab[n-1] < 0){
tab[n-1]=0;
}
else{
return zero_value(n-1,tab);
}
}
int main(void)
{
int tab[4] = {0,4,-9,3};
int number = 0;
int i;
zero_value(4, tab);
for(i=0;i<4;i++)
printf("%d ", tab[i]);
return 0;
}
When you hit the first negative, the recursion doesn't continue anymore and the function returns. You don't really need to return any value from the function. You can rewrite it to make a void function.
#include <stdio.h>
void zero_value(int n, int tab[])
{
if (n==0) return;
if(tab[n-1] < 0) tab[n-1]=0;
zero_value(n-1,tab);
}
int main(void)
{
int tab[4] = {0,4,-9,3};
int number = 0;
int i;
zero_value(4, tab);
for(i=0;i<4;i++)
printf("%d ", tab[i]);
return 0;
}
I see the following problems with your code.
The function zero_values does not have a valid return statement when tab[n-1] is negative. You can see it more clearly if you change the function to:
int zeros_value(int n, int tab[])
{
if (n==0)
{
return 0;
}
if(tab[n-1] < 0)
{
tab[n-1]=0;
// No return here.
}
else
{
return zero_value(n-1,tab);
}
// No return here either.
}
Calling such functions leads undefined behavior.
The printf line in main is not right.
printf("%d%d%d%d", zeros_value(4,tab));
That line needs four arguments of type int after the format string to work correctly. Not providing enough arguments to printf is also cause for undefined behavior.
You can use solution provided in the answer by #usr to solve both problems.
If you have any valid reasons to return an int from zero_value, you need to change the implementation appropriately. It's not clear from your post what that return value is supposed to be.

Binary Search with few modification

While I am trying to compile the code with few modification in binary search recursive function. The program is acting weird. Some time it gives the correct value and some time it goes to infinite loop. Please explain what went wrong with the code. I am using DEV C++ as an IDE.
CODE:
#include<iostream>
#include<sstream>
using namespace std;
//function to compare the two integers
int compare(int low, int high)
{
if (low==high)
return 0;
if (low<high)
return 1;
else
return -1;
}
//Function for binary search using recursion
int *BinarySearch(int *Arr,int Val,int start,int end)
{
int localstart=start;
int localend=end;
int mid=(start+end)/3;
cout<<"MID:"<<mid;
int comp= compare(Val,Arr[mid]);
if(comp==0)
return &(Arr[mid]);
else if (comp>0)
return BinarySearch(Arr,Val,localstart,mid-1);
else
return BinarySearch(Arr,Val,mid+1,localend);
return NULL;
}
main()
{
int *arr;
arr= new int [256];
string str;
getline(cin,str);
stringstream ss;
ss<<str;
int index=0;
while(ss>>arr[index])
{index++;}
//cout<<arr[index-1];
cout<<"Enter Value:";
int value;
cin>>value;
int *final;
final=BinarySearch(arr,value,0,index-1);
if(final!=NULL)
cout<<"Final:"<<*final;
else
cout<<"Not Found";
getchar();
getchar();
return 0;
}
Two ideas:
What should BinarySearch do if Val is not in the array? Trace out what your code does in this case.
(start+end)/3 probably isn't the middle of the current range.

What's the correct approach to solve SPOJ www.spoj.com/problems/PRHYME/?

I have been trying to solve this problem SPOJ www.spoj.com/problems/PRHYME/? for several days, but have had no success.
Here is the problem in brief:
Given is a wordlist L, and a word w. Your task is to find a word in L that forms a perfect rhyme with w. This word u is uniquely determined by these properties:
It is in L.
It is different from w.
Their common suffix is as long as possible.
Out of all words that satisfy the previous points, u is the lexicographically smallest one.
Length of a word will be<=30.
And number of words both in the dictionary and the queries can be 2,50,000.
I am using a trie to store all the words in the dictionary reversed.
Then to solve the queries I proceed in the following fashion:-
If word is present in the trie,delete it from trie.
Now traverse the trie from the root till the point the character from the query string match the trie values.Let this point where last character match was found be P.
Now from this point P onward ,I traverse the trie using DFS,and on encountering a leaf node,push the string formed to the possible results list.
Now I return the lexicographic ally smallest result from this list.
When I submit my solution on SPOJ,my solution gets a Time Limit Exceeded Error.
Can someone please suggest a detailed algorithm or hint to solve this problem ?
I can post my code if required.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<climits>
#include<vector>
#include<string>
#include<algorithm>
#include<cctype>
#include<cstdlib>
#include<utility>
#include<map>
#include<queue>
#include<set>
#define ll long long signed int
#define ull unsigned long long int
const int alpha=26;
using namespace std;
struct node
{
int value;
node * child[alpha];
};
node * newnode()
{
node * newt=new node;
newt->value=0;
for(int i=0;i<alpha;i++)
{
newt->child[i]=NULL;
}
return newt;
}
struct trie
{
node * root;
int count;
trie()
{
count=0;
root=newnode();
}
};
trie * dict=new trie;
string reverse(string s)
{
int l=s.length();
string rev=s;
for(int i=0;i<l;i++)
{
int j=l-1-i;
rev[j]=s[i];
}
return rev;
}
void insert(string s)
{
int l=s.length();
node * ptr=dict->root;
dict->count++;
for(int i=0;i<l;i++)
{
int index=s[i]-'a';
if(ptr->child[index]==NULL)
{
ptr->child[index]=newnode();
}
ptr=ptr->child[index];
}
ptr->value=dict->count;
}
void dfs1(node *ptr,string p)
{
if(ptr==NULL) return;
if(ptr->value) cout<<"word" <<p<<endl;
for(int i=0;i<26;i++)
{
if(ptr->child[i]!=NULL)
dfs1(ptr->child[i],p+char('a'+i));
}
}
vector<string> results;
pair<node *,string> search(string s)
{
int l=s.length();
node * ptr=dict->root;
node *save=ptr;
string match="";
int i=0;
bool no_match=false;
while(i<l and !no_match)
{
int in=s[i]-'a';
if(ptr->child[in]==NULL)
{
save=ptr;
no_match=true;
}
else
{
ptr=ptr->child[in];
save=ptr;
match+=in+'a';
}
i++;
}
//cout<<s<<" matched till here"<<match <<" "<<endl;
return make_pair(save,match);
}
bool find(string s)
{
int l=s.length();
node * ptr=dict->root;
string match="";
for(int i=0;i<l;i++)
{
int in=s[i]-'a';
//cout<<match<<"match"<<endl;
if(ptr->child[in]==NULL)
{
return false;
}
ptr=ptr->child[in];
match+=char(in+'a');
}
//cout<<match<<"match"<<endl;
return true;
}
bool leafNode(node *pNode)
{
return (pNode->value != 0);
}
bool isItFreeNode(node *pNode)
{
int i;
for(i = 0; i < alpha; i++)
{
if( pNode->child[i] )
return false;
}
return true;
}
bool deleteHelper(node *pNode, string key, int level, int len)
{
if( pNode )
{
// Base case
if( level == len )
{
if( pNode->value )
{
// Unmark leaf node
pNode->value = 0;
// If empty, node to be deleted
if( isItFreeNode(pNode) )
{
return true;
}
return false;
}
}
else // Recursive case
{
int index = (key[level])-'a';
if( deleteHelper(pNode->child[index], key, level+1, len) )
{
// last node marked, delete it
free(pNode->child[index]);
pNode->child[index]=NULL;
// recursively climb up, and delete eligible nodes
return ( !leafNode(pNode) && isItFreeNode(pNode) );
}
}
}
return false;
}
void deleteKey(string key)
{
int len = key.length();
if( len > 0 )
{
deleteHelper(dict->root, key, 0, len);
}
}
string result="***";
void dfs(node *ptr,string p)
{
if(ptr==NULL) return;
if(ptr->value )
{
if((result)=="***")
{
result=reverse(p);
}
else
{
result=min(result,reverse(p));
}
}
for(int i=0;i<26;i++)
{
if(ptr->child[i]!=NULL)
dfs(ptr->child[i],p+char('a'+i));
}
}
int main(int argc ,char ** argv)
{
#ifndef ONLINE_JUDGE
freopen("prhyme.in","r",stdin);
#endif
string s;
while(getline(cin,s,'\n'))
{
if(s[0]<'a' and s[0]>'z')
break;
int l=s.length();
if(l==0) break;
string rev;//=new char[l+1];
rev=reverse(s);
insert(rev);
//cout<<"...........traverse..........."<<endl;
//dfs(dict->root);
//cout<<"..............traverse end.............."<<endl;
}
while(getline(cin,s))
{
results.clear();
//cout<<s<<endl;
int l=s.length();
if(!l) break;
string rev;//=new char[l+1];
rev=reverse(s);
//cout<<rev<<endl;
bool del=false;
if(find(rev))
{
del=true;
//cout<<"here found"<<endl;
deleteKey(rev);
}
if(find(rev))
{
del=true;
//cout<<"here found"<<endl;
deleteKey(rev);
}
else
{
//cout<<"not here found"<<endl;
}
// cout<<"...........traverse..........."<<endl;
//dfs1(dict->root,"");
// cout<<"..............traverse end.............."<<endl;
pair<node *,string> pp=search(rev);
result="***";
dfs(pp.first,pp.second);
//cout<<"search results"<<endl;
//dfs1(pp.first,pp.second);
//cout<<"end of search results"<<
for(int i=0;i<results.size();i++)
{
results[i]=reverse(results[i]);
// cout<<s<<" "<<results[i]<<endl;
}
string smin=result;
if(del)
{
insert(rev);
}
cout<<smin<<endl;
}
return 0;
}
Your algorithm (using a trie that stores all reversed words) is a good start. But one issue with it is that for each lookup, you have to enumerate all words with a certain suffix in order to find the lexicographically smallest one. For some cases, this can be a lot of work.
One way to fix this: In each node (corresponding to each suffix), store the two lexicographically smallest words that have that suffix. This is easy to maintain while building the trie by updating all ancestor nodes of each newly added leaf (see pseudo-code below).
Then to perform a lookup of a word w, start at the node corresponding to the word, and go up in the tree until you reach a node which contains a descendant word other than w. Then return the lexicographically smallest word stored in that node, or the second smallest in case the smallest is equal to w.
To create the trie, the following pseudo-code can be used:
for each word:
add word to trie
let n be the node corresponding to the new word.
for each ancestor a of n (including n):
if a.smallest==null or word < a.smallest:
a.second_smallest = a.smallest
a.smallest = word
else if a.second_smallest==null or word < a.second_smallest:
a.second_smallest = word
To lookup a word w:
let n be the node corresponding to longest possible suffix of w.
while ((n.smallest==w || n.smallest==null) &&
(n.second_smallest==w || n.second_smallest==null)):
n = n.parent
if n.smallest==w:
return n.second_smallest
else:
return n.smallest
Another similar possibility is to use a hash table mapping all suffixes to the two lexicographically smallest words instead of using a trie. This is probably easier to implement if you can use std::unordered_map.