i am developing high-level petri net editor / simulator. At first, here is a little of vocabulary
circle = place
rectangle = transition
integers in place = tokens
condition in transition = guard
And im stucked at passing the guard of the transition. Guard is a condition, that needs to be true if you want to execute the transition. I know that i should use backtracking somehow, but i dont know number of places entering the transition before the program start, So i cant use for loops since i dont know how many of them i will need.
Here is the picture that illustrates the problem
So, i want to take first token from first place, first token from second place, then try to pass the guard, if passed, then save tokens, and break the loop, if false, continue with second token of second place..etc...
i finally pass guard with last token (4) of first place, and last token(2) of second place.
I would know how to code this, if i had constant number of places entering the transition, it would looks like this
for token in place 1
for token in place 2
try pass guard
if (passed)
save tokens
break;
but as i said before, i dont have constant number of places entering transition, so i cant use this approach.
So, basically, i need to try combinations of tokens, and try to pass the guard - until i passed the guard, or until i tried all combinations.
Do you have any ideas ? pseudocode would be enough.
By the way i use these datastructure
list of places - normal java list, List places = new ArrayList();
and each place has its own list of tokens, List tokens = new ArrayList();
///EDIT:
the guard has following format:
op1 rel op2,
where op1 is variable, and op2 is constant or variable, rel is relation (<,>,=,...)
there can be several conditions in guard connected with the logical operator AND - example:
op1 rel op2 && op3 rel op4 ...
----EDIT:
So i tried to implement Rushil algorithm, but it is quite buggy, so im posting SSCCE so you can try it and maybe help a little.
First , create Place class:
public class Place {
public List<Integer> tokens ;
//constructor
public Place() {
this.tokens = new ArrayList<Integer>();
}
}
And then testing class:
public class TestyParmutace {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
List<Place> places = new ArrayList<Place>();
Place place1 = new Place();
place1.tokens.add(1);
place1.tokens.add(2);
place1.tokens.add(3);
places.add(place1); //add place to the list
Place place2 = new Place();
place2.tokens.add(3);
place2.tokens.add(4);
place2.tokens.add(5);
places.add(place2); //add place to the list
Place place3 = new Place();
place3.tokens.add(6);
place3.tokens.add(7);
place3.tokens.add(8);
places.add(place3); //add place to the list
//so we have
//P1 = {1,2,3}
//P2 = {3,4,5}
//P3 = {6,7,8}
List<Integer> tokens = new ArrayList<Integer>();
Func(places,0,tokens);
}
/**
*
* #param places list of places
* #param index index of current place
* #param tokens list of tokens
* #return true if we passed guard, false if we did not
*/
public static boolean Func( List<Place> places, int index, List<Integer> tokens)
{
if (index >= places.size())
{
// if control reaches here, it means that we've recursed through a particular combination
// ( consisting of exactly 1 token from each place ), and there are no more "places" left
String outputTokens = "";
for (int i = 0; i< tokens.size(); i++) {
outputTokens+= tokens.get(i) +",";
}
System.out.println("Tokens: "+outputTokens);
if (tokens.get(0) == 4 && tokens.get(1) == 5 && tokens.get(2) == 10) {
System.out.println("we passed the guard with 3,5,8");
return true;
}
else {
tokens.remove(tokens.get(tokens.size()-1));
return false;
}
}
Place p = places.get(index);
for (int i = 0; i< p.tokens.size(); i++)
{
tokens.add(p.tokens.get(i));
//System.out.println("Pridali sme token:" + p.tokens.get(i));
if ( Func( places, index+1, tokens ) ) return true;
}
if (tokens.size()>0)
tokens.remove(tokens.get(tokens.size()-1));
return false;
}
}
and here is the output of this code:
Tokens: 1,3,6,
Tokens: 1,3,7,
Tokens: 1,3,8,
Tokens: 3,4,6,
Tokens: 3,4,7,
Tokens: 3,4,8,
Tokens: 4,5,6,
Tokens: 4,5,7,
Tokens: 4,5,8,
Tokens: 2,3,6,
Tokens: 2,3,7,
Tokens: 2,3,8,
Tokens: 3,4,6,
Tokens: 3,4,7,
Tokens: 3,4,8,
Tokens: 4,5,6,
Tokens: 4,5,7,
Tokens: 4,5,8,
Tokens: 3,3,6,
Tokens: 3,3,7,
Tokens: 3,3,8,
Tokens: 3,4,6,
Tokens: 3,4,7,
Tokens: 3,4,8,
Tokens: 4,5,6,
Tokens: 4,5,7,
Tokens: 4,5,8,
So, you see, some combinations are correct, like 1,3,6, and 1,3,7... but 4,5,8 is absolute nonsense, since 4 is not even in the first place... and there are also combinations that are missing ompletely..like 2,4,6 etc... anybody see why is it like this ?
EDIT: Now it's working fine.
A recursive approach would make it easy:
boolean Func( ListOfPlaces places, int index ) // index points to the current "place"
{
If index >= NumberOfTokens (if index points to a place, which doesn't exist)
{
// if control reaches here, it means that we've recursed through a particular combination ( consisting of exactly 1 token from each place ), and there are no more "places" left. You have all the tokens you need, in your stack.
try pass guard; if passed, save tokens and return true
else, remove token last added to the stack & and return false
}
place p = places[index]
foreach token in p
{
add token to your stack
if ( Func( places, index+1 ) ) return true
}
remove last token added to the stack
return false
}
Call the function initially with index = 0.
Hope this helps. :-)
You could do the loop administration yourself. What I mean is: you would need a class to depict the iteration status for each place. Lets call it state_of_place. It would consist of two values: a current_index and a max_index.
Next you would have a class I would name iteration_admin, which consists of an array of state_of_place and a boolean called something like iteration_in_progress. Upon creation, the boolean is set to TRUE. You would create as many state_of_place objects as there are places. Current_index would be 0, max_index would be the number of tokens on that place.
The iteration_admin class needs a method to represent the increment of loop variables. Lets call it increment(). This method would increment the current_index of the state_of_place element with the highest index, if the current_index is still below the max_index.
If the current_index is equal to the max_index, the current index is set to 0 and the current index of the state_of_place with the next lower index needs to be incremented.
If that one has reached its max_index, it will be set to 0 and the next lower one will be incremented, and so on.
Only exception, of course, is state_of_place[0]. If that elements current_index would exceed its max_index, the boolean iteration_in_progress will be set to FALSE. This would mean, that all combinations of tokens have been used.
Now, your code for trying out the guard would
initialize an object of type iteration_admin
while iteration_admin.iteration_in_progress is TRUE
build the argument list for the pass() method by using the current_index values in the state_of_place elements
call pass()
if not passed, call the iteration_admin.increment() method
end while
EDIT:
Trying to express the idea in pseudo code. I fear it looks more like a mix of Java and PL/SQL than abstract pseudo code. Still, it should be somewhat clearer than my text description.
// iteration state for one place
class state_of_a_place
{
integer current_index;
integer max_index;
}
// iteration administration for one transition
class iteration_admin
{
boolean iteration_in_progress
state_of_a_place[] state_of_places
procedure increment
{
// move index through tokens
FOR i IN state_of_places.count-1 .. 0 LOOP
IF state_of_places[i].current_index < state_of_places[i].max_index THEN
state_of_places[i].current_index += 1
return
ELSE
state_of_places[i].current_index = 0
IF i = 0 THEN
iteration_in_progress = FALSE
END IF
END IF
END FOR
}
}
handle_transition (list_of_places)
{
// initialize an object of type iteration_admin
iteration_admin ia
ia.iteration_in_progress = TRUE
FOR i IN 0..list_of_places.count LOOP
ia.state_of_places[i].current_index = 0
ia.state_of_places[i].max_index = list_of_places[i].number_of_tokens
END FOR
WHILE ia.iteration_in_progress LOOP
// build the argument list for the pass() method
token[] arguments
FOR i IN 0..list_of_places.count LOOP
arguments[i] = list_of_places[i].token[ia.state_of_places[i].current_index]
END FOR
// try to pass the guard
call pass(arguments)
IF (passed)
// do whatever you need to do here
ELSE
ia.increment()
END IF
END WHILE
}
What about something like this:
method getPassed(places, tokens):
if places are empty:
try pass guard
if (passed)
save tokens
return true
else return false
else:
for token in places[0]:
if getPassed(places[1:].clone(), tokens.clone().append(token)):
break
Start it with call getPassed(places, []), where places is a list of places and [] is empty list. Note that you need to copy the lists always, so that you don't end up messing them up.
In the end, no need for pairs. If you keep the original places list you pass into the algorithm at the beginning, you know that token[i] was selected for originalPlaces[i].
But if you want to, you can keep tokenPlaces pairs instead of tokens, so something like this:
method getPassed(places, tokenPlacePairs):
if places are empty:
try pass guard
if (passed)
save tokens
return true
else return false
else:
for token in places[0]:
if getPassed(places[1:].clone(), tokens.clone().append((token, places[0]))):
break
EDIT: Still some confusion, hopefully this will make it clear. I am trying to generate the for loops recursively. So if places has only 2 elements, you get as you suggested:
for token in place 1
for token in place 2
try pass guard
if (passed)
save tokens
break;
So what it does is that it takes the first place from the list and creates the "for token in place 1" loop. Then it cuts of that place from the places list and adds the current token to the tokens list. This recursive call now does the "for token in place 2" loop. And so on. Every recursive call we decrease the number of places by 1 and create 1 for loop. Hence, after the places list is empty we have n nested loops, where n is the number of places and as far as I understand, this is what you were looking for.
You can initiate the method in the following way:
originalPlaces = places.clone()
getPassed(places, [])
This way you can keep the originalPlaces unchanged and you can assign tokens[i] to originalPlaces[i] when you get to the base case in the recursion, i.e. when you try to determine the passing the guard. Hence you do not really need the pairs.
Assume Transition has an isEnabled() method as well as input/outputArcs:
public boolean isEnabled() {
// check for some special input/output conditions (no arcs, etc.)
// return false if invalid
// check to see if all input arcs are enabled
for (Arc inputArc : inputArcs)
if (!inputArc.isEnabled())
return false;
// should check if there's a guard first...
return guard.evaluate(); // do the selection of tokens from inputs here and evaluate
}
Related
I have been taking the test on Codility, and trying this exercise:
https://app.codility.com/programmers/trainings/4/disappearing_pairs/
A string S containing only the letters "A", "B" and "C" is given. The string can be transformed by removing one occurrence of "AA", "BB" or "CC".
Transformation of the string is the process of removing letters from it, based on the rules described above. As long as at least one rule can be applied, the process should be repeated. If more than one rule can be used, any one of them could be chosen.
Write a function:
class Solution { public String solution(String S); }
that, given a string S consisting of N characters, returns any string that can result from a sequence of transformations as described above.
For example, given string S = "ACCAABBC" the function may return "AC", because one of the possible sequences of transformations is as follows:
Also, given string S = "ABCBBCBA" the function may return "", because one possible sequence of transformations is:
Finally, for string S = "BABABA" the function must return "BABABA", because no rules can be applied to string S.
Write an efficient algorithm for the following assumptions:
the length of string S is within the range [0..50,000];
string S is made only of the following characters: "A", "B" and/or "C".
Here is the code that I tried with a score of 83:
public String solution(String S) {
boolean notAA = false;
boolean notBB = false;
boolean notCC = false;
while(S.length()==0 || true){
if (S.contains("AA")){
S = S.replace("AA", "");
} else {
notAA = true;
}
if(S.contains("BB")){
S = S.replace("BB", "");
} else {
notBB = true;
}
if(S.contains("CC")){
S = S.replace("CC", "");
} else {
notCC = true;
}
if(notAA && notBB && notCC){
break;
}
}
return S;
}
I could not obtain the 100% score because of this:
even_palindrome1 big palindrome of even length
✘WRONG ANSWER got CACABACABABCBACBACBA.. expected ""
Codility doesn't show me the string example or any other information.
I was reading and reviewing but I still do not understand why I am not getting the right output. My assumption is when I delete the first combination of letters, the string needs to be in a specific state or a specific combination of letters to work correctly and the problem is the palindrome even string.
But, if my assumption is correct, I don't really understand the real cause or root reason for this.
Thanks in advance for your help.
You should reset notAA, notBB and notCC inside your loop.
Consider, for example, ABCCBA. In your first pass, notAA and notBB are set to true, leaving ABBA. In the second pass, notAA and notCC are set to true, leaving AA. Your program would then break out with an available pair because all three conditions are set to true.
You have to set notAA, notBB and notCC to false inside the loop, not before it. The way you are doing it, you find all three, you end the loop.
Say S is ABCCBA.
You set notAA and notBB to true, because AA and BB cannot be found; then you replace CC, giving you ABBA.
Next loop, you set notAA to true again, remove BB, producing AA, and set notCC to true. Now all three are true (since notBB remained true since the first iteration), and you break the loop.
The result is AA, which should have reduced further; but because the program thought there was no AA, but it appeared after notAA was set, you get the wrong value.
In fact, this can be simplified: you just need a single flag changed, which starts before the loop as true; then use while (changed). At the top of the loop, set it to false, and set it to true every time you successfully replace a substring. You do not need three separate ones, since they all do effectively the same job.
I was working on a Java coding problem and encountered the following issue.
Problem:
Given a string, does "xyz" appear in the middle of the string? To define middle, we'll say that the number of chars to the left and right of the "xyz" must differ by at most one
xyzMiddle("AAxyzBB") → true
xyzMiddle("AxyzBBB") → false
My Code:
public boolean xyzMiddle(String str) {
boolean result=false;
if(str.length()<3)result=false;
if(str.length()==3 && str.equals("xyz"))result=true;
for(int j=0;j<str.length()-3;j++){
if(str.substring(j,j+3).equals("xyz")){
String rightSide=str.substring(j+3,str.length());
int rightLength=rightSide.length();
String leftSide=str.substring(0,j);
int leftLength=leftSide.length();
int diff=Math.abs(rightLength-leftLength);
if(diff>=0 && diff<=1)result=true;
else result=false;
}
}
return result;
}
Output I am getting:
Running for most of the test cases but failing for certain edge cases involving more than once occurence of "xyz" in the string
Example:
xyzMiddle("xyzxyzAxyzBxyzxyz")
My present method is taking the "xyz" starting at the index 0. I understood the problem. I want a solution where the condition is using only string manipulation functions.
NOTE: I need to solve this using string manipulations like substrings. I am not considering using list, stringbuffer/builder etc. Would appreciate answers which can build up on my code.
There is no need to loop at all, because you only want to check if xyz is in the middle.
The string is of the form
prefix + "xyz" + suffix
The content of the prefix and suffix is irrelevant; the only thing that matters is they differ in length by at most 1.
Depending on the length of the string (and assuming it is at least 3):
Prefix and suffix must have the same length if the (string's length - the length of xyz) is even. In this case:
int prefixLen = (str.length()-3)/2;
result = str.substring(prefixLen, prefixLen+3).equals("xyz");
Otherwise, prefix and suffix differ in length by 1. In this case:
int minPrefixLen = (str.length()-3)/2;
int maxPrefixLen = minPrefixLen+1;
result = str.substring(minPrefixLen, minPrefixLen+3).equals("xyz") || str.substring(maxPrefixLen, maxPrefixLen+3).equals("xyz");
In fact, you don't even need the substring here. You can do it with str.regionMatches instead, and avoid creating the substrings, e.g. for the first case:
result = str.regionMatches(prefixLen, "xyz", 0, 3);
Super easy solution:
Use Apache StringUtils to split the string.
Specifically, splitByWholeSeparatorPreserveAllTokens.
Think about the problem.
Specifically, if the token is in the middle of the string then there must be an even number of tokens returned by the split call (see step 1 above).
Zero counts as an even number here.
If the number of tokens is even, add the lengths of the first group (first half of the tokens) and compare it to the lengths of the second group.
Pay attention to details,
an empty token indicates an occurrence of the token itself.
You can count this as zero length, count as the length of the token, or count it as literally any number as long as you always count it as the same number.
if (lengthFirstHalf == lengthSecondHalf) token is in middle.
Managing your code, I left unchanged the cases str.lengt<3 and str.lengt==3.
Taking inspiration from #Andy's answer, I considered the pattern
prefix+'xyz'+suffix
and, while looking for matches I controlled also if they respect the rule IsMiddle, as you defined it. If a match that respect the rule is found, the loop breaks and return a success, else the loop continue.
public boolean xyzMiddle(String str) {
boolean result=false;
if(str.length()<3)
result=false;
else if(str.length()==3 && str.equals("xyz"))
result=true;
else{
int preLen=-1;
int sufLen=-2;
int k=0;
while(k<str.lenght){
if(str.indexOf('xyz',k)!=-1){
count++;
k=str.indexOf('xyz',k);
//check if match is in the middle
preLen=str.substring(0,k).lenght;
sufLen=str.substring(k+3,str.lenght-1).lenght;
if(preLen==sufLen || preLen==sufLen-1 || preLen==sufLen+1){
result=true;
k=str.length; //breaks the while loop
}
else
result=false;
}
else
k++;
}
}
return result;
}
I am currently a early CS student and have begun to start projects outside of class just to gain more experience. I thought I would try and design a calculator.
However, instead of using prompts like "Input a number" etc. I wanted to design one that would take an input of for example "1+2+3" and then output the answer.
I have made some progress, but I am stuck on how to make the calculator more flexible.
Scanner userInput = new Scanner(System.in);
String tempString = userInput.nextLine();
String calcString[] = tempString.split("");
Here, I take the user's input, 1+2+3 as a String that is then stored in tempString. I then split it and put it into the calcString array.
This works out fine, I get "1+2+3" when printing out all elements of calcString[].
for (i = 0; i <= calcString.length; i += 2) {
calcIntegers[i] = Integer.parseInt(calcString[i]);
}
I then convert the integer parts of calcString[] to actual integers by putting them into a integer array.
This gives me "1 0 2 0 3", where the zeroes are where the operators should eventually be.
if (calcString[1].equals("+") && calcString[3].equals("+")) {
int retVal = calcIntegers[0] + calcIntegers[2] + calcIntegers[4];
System.out.print(retVal);
}
This is where I am kind of stuck. This works out fine, but obviously isn't very flexible, as it doesn't account for multiple operators at the same like 1 / 2 * 3 - 4.
Furthermore, I'm not sure how to expand the calculator to take in longer lines. I have noticed a pattern where the even elements will contain numbers, and then odd elements contain the operators. However, I'm not sure how to implement this so that it will convert all even elements to their integer counterparts, and all the odd elements to their actual operators, then combine the two.
Hopefully you guys can throw me some tips or hints to help me with this! Thanks for your time, sorry for the somewhat long question.
Create the string to hold the expression :
String expr = "1 + 2 / 3 * 4"; //or something else
Use the String method .split() :
String tokens = expr.split(" ");
for loop through the tokens array and if you encounter a number add it to a stack. If you encounter an operator AND there are two numbers on the stack, pop them off and operate on them and then push back to the stack. Keep looping until no more tokens are available. At the end, there will only be one number left on the stack and that is the answer.
The "stack" in java can be represented by an ArrayList and you can add() to push items onto the stack and then you can use list.get(list.size()-1); list.remove(list.size()-1) as the pop.
You are taking input from user and it can be 2 digit number too.
so
for (i = 0; i <= calcString.length; i += 2) {
calcIntegers[i] = Integer.parseInt(calcString[i]);
}
will not work for 2 digit number as your modification is i+=2.
Better way to check for range of number for each char present in string. You can use condition based ASCII values.
Since you have separated your entire input into strings, what you should do is check where the operations appear in your calcString array.
You can use this regex to check if any particular String is an operation:
Pattern.matches("[+-[*/]]",operation )
where operation is a String value in calcString
Use this check to seperate values and operations, by first checking if any elements qualify this check. Then club together the values that do not qualify.
For example,
If user inputs
4*51/6-3
You should find that calcString[1],calcString[4] and calcString[6] are operations.
Then you should find the values you need to perform operations on by consolidating neighboring digits that are not separated by operations. In the above example, you must consolidate calcString[2] and calcString[3]
To consolidate such digits you can use a function like the following:
public int consolidate(int startPosition, int endPosition, ArrayList list)
{
int number = list.get(endPosition);
int power = 10;
for(int i=endPosition-1; i>=startPosition; i--)
{
number = number + (power*(list.get(i)));
power*=10;
}
return number;
}
where startPosition is the position where you encounter the first digit in the list, or immediately following an operation,
and endPosition is the last position in the list till which you have not encountered another operation.
Your ArrayList containing user input must also be passed as an input here!
In the example above you can consolidate calcString[2] and calcString[3] by calling:
consolidate(2,3,calcString)
Remember to verify that only integers exist between the mentioned positions in calcString!
REMEMBER!
You should account for a situation where the user enters multiple operations consecutively.
You need a priority processing algorithm based on the BODMAS (Bracket of, Division, Multiplication, Addition and Subtraction) or other mathematical rule of your preference.
Remember to specify that your program handles only +, -, * and /. And not power, root, etc. functions.
Take care of the data structures you are using according to the range of inputs you are expecting. A Java int will handle values in the range of +/- 2,147,483,647!
First of all I am not asking for people to "do my homework" like I have seen others on here ask for. I have managed to code a working iterative version of a program that determines if a string is a palindrome or not. Spaces, punctuation and special characters are ignored while determining if the string is a palindrome. This version does work but when I try and apply recursive statements in the "isPalindrome()" method I get Stack Overflow errors. I know what these errors are, it's just that applying a recursive method in a program like this is quite hard for me to get my head around (I only got taught about them 2 weeks ago). Anyway here is the code I have managed to compile (and run) so far:
/** Palindrome.java: A sigle application class that determines if a word or a string
* is a palindrome or not. This application is designed to ignore spaces between
* chars, punctuation marks and special characters while determining if the word or
* string is a palindrome or not.
*
**/
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.regex.*;
public class Palindrome{
static String palindrome, str, str2, str3;
/** The main method of the Palindrome application. Takes input from the
* user, removes spaces from their input, turns their string input into
* lowercase and then all non letter characters are taken out of the user's
* input. Finally the recursive method determines if the string entered in
* by the user is a palindrome.
*
* #param args Takes in a string array of arguements
**/
public static void main(String[] args){
Scanner input = new Scanner(System.in);
while(input.hasNext()){
str = removeSpaces(input.nextLine());
str2 = str.toLowerCase();
str3 = normalise(str2);
}
System.out.println(isPalindrome(str3));
}
/** The default constructor
**/
public Palindrome(){
}
/** isPalindrome(): A boolean method that is passed through a String input
* and uses a for loop, two inner while loops and an if-else to determine
* whether the users input is a palindrome.
*
* #param s The string input to be tested
* #return true The users input is a palindrome
* #return false The users input isn't a palindrome
**/
public static boolean isPalindrome(String s){
int first, last;
for(first = 0, last = s.length()-1 ; first < last ; first++ , last-- ){
while( (int)s.charAt(first) < 'a' || (int)s.charAt(first) > 'z' ){
first++;
}
while( (int)s.charAt(last ) < 'a' || (int)s.charAt(last ) > 'z' ){
last--;
}
}
if( first > last || s.charAt(first) != s.charAt(last) ){
//return isPalindrome(s.substring(0, s.length()-1)) == false;
return false;
}
else{
//return isPalindrome(s.substring(0, s.length()-1)) == true;
return true;
}
}
/**
* This method takes out punctuation marks in the string parsed
* through, using Java's regular expressions (regex) and Java's
* inbuilt method replaceAll(). The regex expression is passed
* through the replaceAll() method to remove all non alpha-numeric
* characters from the string passed through the method's parameter.
*
* #param t The string that will have punctuation stripped from it.
*
* #return t The string has had all non alpha-numeric characters
* removed and the new string is then returned.
*/
public static String normalise(String t){
t = t.replaceAll("[^a-zA-Z0-9]", "");
return t;
}
/** removeSpaces(): A method that deletes spaces from the users input
* and then decrements the string length count so any indexes aren't missed
* when it is incremented.
*
* #param s The string which is going to have it's spaces removed.
* #return temp The new string is then returned after the spaces have been taken out.
**/
public static String removeSpaces(String s){
StringBuilder temp = new StringBuilder(s); //creates a new StringBuilder with the inputted String
for(int i = 0; i < temp.length(); i++){ //do this for the entire length of the StringBuilder
if(temp.charAt(i) == ' '){ //if the char at i is a space
temp.deleteCharAt(i); //remove the char
i--; //subtract 1 from the counter so we don't miss an index when we increment it
}
}
return temp.toString(); //return the new String
}
}
I have blanked out the recursive statements in the recursive method for now. If someone can tell me what exactly I have done wrong and also help me in implementing a solution that would be really good. I would rather stick with the iterative version because I understand the mechanics of it, but have been asked to do a recursive version (I have been Java coding since after my mid year break last year but am a relative novice at recursion) which is proving to be quite a challenge. If you alter the code and it ends up working with the recursive version please explain how, when, why etc with your alterations. Am not looking for someone to just do this for me, I'm wanting to learn and it seems that I have learned best by example (I did get a B pass last year by analysing examples and reading explanations of implementations). Many thanks :).
EDIT: I think I have got the recursion going ok now, just the logic is the thing confusing me at the moment. Here is the recoded version of the isPalindrome() method:
public static boolean isPalindrome(String s){
int first, last;
boolean isPalindr = true;
if (s.length() <= 1){
return true; // Base case
}
for(first = 0, last = s.length()-1 ; first < last ; first++ , last-- ){
// while( (int)s.charAt(first) < 'a' || (int)s.charAt(first) > 'z' ){
// first++;
// }
// while( (int)s.charAt(last ) < 'a' || (int)s.charAt(last ) > 'z' ){
// last--;
// }
// }
if( first == last || s.charAt(first) == s.charAt(last) ){
//return isPalindrome(s.substring(first, last));
return isPalindrome(s.substring(first, last)) == true;
//isPalindr = false;
}
else{
return isPalindrome(s.substring(first, last)) == false;
//isPalindr = true;
}
}
return isPalindr;
}
If someone can help me with the logic I think this will be fixed :).
Removing all of the code that has nothing to do with the problem leaves us with this:
public static boolean isPalindrome(String s){
for loop {
isPalindrome();
}
}
isPalindrome calls isPalindrome calls isPalindrome, etc... infinitum.
The difference between this and a proper recursive function is that a recursive function will have some sort of conditional statement, breaking the cycle of the function calling itself. The flow of execution will go like this:
isPalindrome(1) begins execution and calls isPalidrome(2)
isPalindrome(2) begins execution and calls isPalidrome(3)
isPalindrome(3) begins execution and calls isPalidrome(4)
isPalindrome(4) begins execution and calls isPalidrome(5)
isPalindrome(5) begins execution and returns to isPalindrome(4)
isPalindrome(4) resumes execution and returns to isPalindrome(3)
isPalindrome(3) resumes execution and returns to isPalindrome(2)
isPalindrome(2) resumes execution and returns to isPalindrome(1)
isPalindrome(1) resumes execution and returns.
If that explanation doesn't help, think of it like this. Suppose someone was handing you plates, one at a time, to see if you can hold 25 plates at a time. It would go something like this:
Plate 1 is given to you. Are there 25 plates? No. Add another plate.
Plate 2 is stacked on top of Plate 1. Are there 25 plates? No. Add another plate.
Plate 3 is stacked on top of Plate 2. Are there 25 plates? No. Add another plate.
...
Plate 24 is stacked on top of Plate 23. Are there 25 plates? No. Add another plate.
Plate 25 is stacked on top of Plate 24. Are there 25 plates? Yes. Mission Accomplished. Now, let's put the plates back.
Plate 25 is removed.
Plate 24 is removed.
...
Plate 3 is removed.
Plate 2 is removed.
Plate 1 is removed.
Here's how that might be coded:
bool stackPlates(int i){
plateStack.addPlate();
if (plateStack.wasDropped == true) { return false; } // Were the plates dropped? Return FALSE to indicate failure.
else if (i < 25) { return stackPlates(i+1); } // Are there 25 plates yet? If not, add another.
else { return true; } // There are 25 plates stacked. Return TRUE to indicate success.
plateStack.removePlate(i);
}
Here's stackPlates(int i) called from another function:
bool success = stackPlates(1);
if (success==TRUE) { cout << "CONGRATULATIONS! YOU STACKED 25 PLATES!"; }
else { cout << "YOU BROKE THE PLATES! BETTER LUCK NEXT TIME!"; }
What your function needs to do in order to work properly is do this:
bool isPalindrome(string s, int i) {
char first = s[i]; // REPLACE THIS WITH THE CODE TO SKIP SPACES & SPECIAL CHARACTERS
char last = s[(s.length -1) -i]; // REPLACE THIS WITH THE CODE TO SKIP SPACES & SPECIAL CHARACTERS
if ( first != last ) { return false; } // return false if mismatch letter
else if ( i >= (s.length/2) ) { return true; } // return true if string fully checked
else { return isPalindrome(s, i+1); } // string not fully checked; move to next letter
}
You're experiencing stack overflows because the else branch at the bottom of the function is executed when (first <= last && "characters are equals"), so you keep recurring on the case where your string is composed by one character.
By the way, I think your code is not using recursion cleanly: you should preprocess your string only one time before starting recurring on the string, and the code that performs the palindrome recursion should be far simpler.
For any given entry into isPalindrome, it's going to recursively call itself regardless because you have no condition on your else. So, if it meets the criteria "first > last || s.charAt(first) != s.charAt(last)", it's going to recursively call isPalindrome, then the next call is too, even if it hits the else.
I don't know what a Palindrome is or what the real solution to the problem is, but that's why you're getting the stack overflow error. I suspect you need to add another condition to your else such that it will stop recursively calling itself.
When writing a recursive function the best way to go about this is usually to decide on a base case (:like "" is a palindrome, though so is "a" ... ) and then devise a method to take any state and move it to the base case.
So in the case of the palindrome, it's the same basic idea as before, if the first character and the last character are the same you return true and check the rest of the string ( thus moving closer to the base case ) and if they are not then you return false.
Your stack overflow comes from calling isPalindrome in every case rather than when you need to continue solving the problem, don't forget that if two characters mean that something isn't a palindrome, the rest is rendered irrelevant ( and thus needn't be recursed on )
Your recoded version is a bit strange, because it's still using a loop when it doesn't need to. In particular, your code will never go beyond the first iteration in your loop, because in the embedded if-else statement, you're going to return a result no matter what, so your function will always exit during the first iteration (unless there are no iterations at all).
Recursion should be approached by
Identifying a base case, i.e. a simplest case that can be solved
Re-representing a larger problem as a partial solution followed by the same, but smaller problem.
The base case you've handled correctly; any String which is length 1 or less is automatically a Palindrome.
The next step is to consider a larger problem, perhaps some string abcwewe....ba. How can we break this down into a simpler problem? We know that we'd normally check whether something is a palindrome by checking the letters one by one in pairs, starting at the ends, but then we also realise that each time we check the letters, we just repeat the same problem again and solve it the same way.
In the string I gave above, we check and verify that the first letter a is the same as the last letter a, so that's kind of a partial solution. Now we we end up with is the smaller word bcwewe....b, and it's the same problem again: Is this new String a palindrome also?
Thus, all you have to do now is to invoke the recursive call, but this time with the substring beginning with the 2nd character to the 2nd to last character. You can code the answer in just two lines, as below:
public static boolean isPalindrome(String s) {
if (s.length() <= 1) return true; // base case
return s.charAt(0) == s.charAt(s.length()-1) && isPalin(s.substring(1,s.length()-1)); // recursive case
}
One point to note is that I'm using the short circuit &&, so if the first condition fails (checking first and last character), then Java will not invoke the recursion.
I'm working on a predictive text solution and have all the words being retrieved from a Trie based on input for a certain string of characters, i.e. "at" will give all words formed with "at" as a prefix. The problem that I have now, is that we are also supposed to return all other possibilities from pressing these 2 buttons, Button 2 and button 8 on the mobile phone, which would also give words formed with, "au, av, bt, bu, bv, ct, cu, cv" (most of which won't have any actual words.
Can anyone suggest a solution and how I would go about doing this for calculating the different permutations?
(at the moment, I'm prompting the user to enter the prefix (not using a GUI right now)
Welcome to concepts like recursivity and combinatorial-explosion :)
Due to combinatorial explosion, you have to be "smart" about it: if the user wants to enter a legitimate 20 letters word, it is unacceptable for your solution to "hang" trying stupidly tens of millions of possibilities.
So you should only recurse when the trie has at least one entry for your prefix.
Here's a way to generate all prefixes and only recurse when there's a match.
In this example, I faked a trie always saying there's an entry. I made this in five minutes so it can surely be beautified/simplified.
The advantage of such a solution is that it works if the user presses on one, two, three, four or 'n' keys, without needing to change your code.
Note that you probably do not want to add all the words starting with 'x' letters when there are too many. It's up to you to find the strategy that matches best your need (wait for more keypresses to reduce candidates or add most common matches as candidates etc.).
private void append( final String s, final char[][] chars, final Set<String> candidates ) {
if ( s.length() >= 2 && doesTrieContainAnyWordStartingWith( s ) ) {
candidates.add( s + "..." ); // TODO: here add all words starting with 's' instead of adding 's'
}
if ( doesTrieContainAnyWordStartingWith( s ) && chars.length > 0 ) {
final char[][] next = new char[chars.length-1][];
for (int i = 1; i < chars.length; i++) {
next[i-1] = chars[i];
}
// our three recursive calls, one for each possible letter
// (you'll want to adapt for a 'real' keyboard, where some keys may only correspond to two letters)
append( s + chars[0][0], next, candidates );
append( s + chars[0][1], next, candidates );
append( s + chars[0][2], next, candidates );
} else {
// we do nothing, it's our recursive termination condition and
// we are sure to hit it seen that we're decreasing our 'chars'
// length at every pass
}
}
private boolean doesTrieContainAnyWordStartingWith( final String s ) {
// You obviously have to change this
return true;
}
Note the recursive call (only when there's a matching prefix).
Here's how you could call it: I faked the user pressing '1', then '2' and then '3' (I faked this in the chars char[][] array I created):
public void testFindWords() {
// Imagine the user pressed 1 then 2 then 3
final char[][] chars = {
{'a','b','c'},
{'d','e','f'},
{'g','h','i'},
};
final Set<String> set = new HashSet<String>();
append( "", chars, set ); // We enter our recursive method
for (final String s : set ) {
System.out.println( "" + s );
}
System.out.println( "Set size: " + set.size() );
}
That example shall create a set containing 36 matches because I "faked" that every prefix is legit and that every prefix leads to exactly one word (and I only added the "word" when it's made of at least two letters). Hence 3*3*3 + 3*3, which gives 36.
You can try the code, it's fully working but you'll have to adapt it of course.
In my fake example (user pressing 1,2 then 3), it creates this:
cdh...
afi...
adi...
beg...
cf...
adh...
cd...
afg...
adg...
bei...
ceg...
bfi...
cdg...
beh...
aeg...
ce...
aeh...
afh...
bdg...
bdi...
cfh...
ad...
cdi...
ceh...
bfh...
aei...
cfi...
be...
af...
bdh...
bf...
cfg...
bfg...
cei...
ae...
bd...
Set size: 36
Welcome to real coding :)