I've got a homework assignment that I just can't figure out. I have to write a static method match(String x, String y) that returns a boolean for whether or not string x and string y match. The matching process should allow "wild cards" such as '#' character which will match with any single character and the '*' character which will match with 0 or more characters of any type. I'm not allowed to use any loops and I have to use recursion.
What I've written so far is this...
public class CompareStrings {
public static boolean match(String x, String y) {
if (x.length() <= 1 && y.length() <= 1) {
if (x.equals("*") || y.equals("*")) {
return true;
}
if ((x.length() == 1 && y.length() == 1) && (x.equals("#") || y.equals("#"))) {
return true;
}
return x.equals(y);
}
String x1 = "";
String x2 = "";
String y1 = "";
String y2 = "";
if (x.length() == 0 && y.charAt(0) == '*') {
y2 = y.substring(1, y.length());
}
if (y.length() == 0 && x.charAt(0) == '*') {
x2 = x.substring(1, x.length());
}
if (x.length() > 1 && y.length() > 1) {
if (x.length() != y.length() && !x.contains("*") && !y.contains("*")) {
return false;
}
if (x.charAt(0) == '*') {
x1 = "*";
x2 = x.substring(1, x.length());
y1 = "*";
y2 = y.substring(y.length()-x2.length(), y.length());
}
else if (y.charAt(0) == '*') {
y1 = "*";
y2 = y.substring(1, y.length());
x1 = "*";
x2 = x.substring(x.length()-y2.length(), x.length());
}
else {
x1 = x.substring(0, 1);
x2 = x.substring(1, x.length());
y1 = y.substring(0, 1);
y2 = y.substring(1, y.length());
}
}
return match(x1, y1) && match(x2, y2);
}
public static void main(String[] args) {
System.out.println(match("hello", "hello.") + " 1 false"); // should return false
System.out.println(match("hello", "jello") + " 2 false"); // should return false
System.out.println(match("hello", "h#llo") + " 3 true"); // should return true
System.out.println(match("hello", "h####") + " 4 true"); // should return true
System.out.println(match("hello", "h*") + " 5 true"); // should return true
System.out.println(match("hello", "*l*") + " 6 true"); // should return true
System.out.println(match("anyString", "*") + " 7 true"); // should return true
System.out.println(match("help", "h####") + " 8 false"); // should return false
System.out.println(match("help", "h*") + " 9 true"); // should return true
System.out.println(match("help", "*l*") + " 10 true"); // should return true
System.out.println(match("help", "*l*p") + " 11 true"); // should return true
System.out.println(match("help", "h#llo") + " 12 false"); // should return false
System.out.println(match("", "*") + " 13 true"); // should return true
System.out.println(match("", "***") + " 14 true"); // should return true
System.out.println(match("", "#") + " 15 false"); // should return false
System.out.println(match("", "") + " 16 true"); // should return true
}
}
The main method is the test program given by the assignment. I realize my code is a little messy - I was scrambling a bit - but I can seem to get most of it working. The only example that doesn't return the right value is number 11. I get false when it should be true. The reason I think this is happening is because since the string y starts with a '', the thing my method does is splits both x and y strings into their last 3 characters, even though that first '' in y is supposed to represent 2 characters. How can I make it so that cases like this return a match?
Basically you need to understand the concept of recursion (that is the objective of your homework). The way recursion works is that everytime a function calls itself, the current execution (variables/ execution info) goes onto a stack and sleeps there till the new call finishes.
To solve the problem you have mentioned, lets take a simple example, hello and h#llo. A basic way to solve problem will be that match service call itself again and again till
A perfect match is found - return true
A failure condition is found- return false
In absence of above 2, match calls itself with one character less than the prev call
Something like
Call 1: hello & h#llo// calls match again and present call moves to stack, waits for a reply
Call 2: ello & #llo //matches special character
call 3: llo and llo// perfect match return true to call 2
Back to call 2: receives true from prv call and returns back to call 1
Back to call 1: receives true and returns to main.
Once you understand the concept of recursion stack, solving this problem will be simple
Your final match method will look something like
public static boolean match(String x, String y) {
//if both are empty
if(x.length()==0 && y.length()==0) return true;
//if one is empty
if(x.length()==0 )
{
if(y.charAt(0)!='*')
return false;
if(y.length()!=1)
//border line case
return match(x,y.substring(1));
else
return true;
}
if(y.length()==0 )
{
if(x.charAt(0)!='*')
return false;
if(x.length()!=1)
//border line case
return match(y,x.substring(1));
else
return true;
}
//Base case
if(x.equals(y) || x.equals("*") || y.equals("*"))
{
return true;//we are done as strings are equal
}
//we are here that means strings are not equal yet
if(x.charAt(0)=='#' || y.charAt(0)=='#' ||x.charAt(0)==y.charAt(0))
{
if(x.length()==1 && y.length()==1) return true;//this was the last character
if(x.length()>1 && y.length()>1)
{
//we have single char wild card or char 0 equal, lets remove the char at 0th location and check again
return (match(x.substring(1),y.substring(1)));
}
}
if(x.charAt(0)=='*')
{
//this is interesting now, we will need to skip 0..n number of characters till we find matching pattern
//case 0 chars: he*llo and hello
if(match(x.substring(1),y)==true)
{
return true;
}
else if (match(x.substring(1),y.substring(1))==true)
{
//case 1: he*lo and hello
return true;
}
else
{
//case n chars: h*o and hello
return (match(x, y.substring(1)));
}
}
if(y.charAt(0)=='*')
{
//this is interesting now, we will need to skip 0..n number of characters till we find matching pattern
//case 0 chars: he*llo and hello
if(match(y.substring(1),x)==true)
{
return true;
}
else if (match(x.substring(1),y.substring(1))==true)
{
//case 1: he*lo and hello
return true;
}
else
{
//case n chars: h*o and hello
return (match(y, x.substring(1)));
}
}
//nothing worked out
return false;
}
In the spirit of recursion (one of your tags) but not of Java, here is a Scheme implementation that gets all your test cases correct.
(define (match s1 s2) ; assumes s1 = string, s2 = pattern
(let matching ((l1 (string->list s1)) (l2 (string->list s2)))
(if (null? l1)
(or (null? l2) (eq? (car l2) #\*)) ; every #\*
(let ((c1 (car l1))
(c2 (car l2)))
(or (and (or (eq? c2 c1)
(eq? c2 #\#))
(matching (cdr l1) (cdr l2))) ; take one char from l1 and l2
(and (eq? c2 #\*)
(matching (cdr l1) l2))))))) ; take one char from l1
Note, for test cases with "*l*" the above gets the right answer but for the wrong reason. There are others that the above gets wrong (related to "*") but that are not in your test cases.
Related
I recently got an interview question where I needed to implement regular expression matching in Java without using regex matching.
Given an input string (s) and a pattern (p), implement regular
expression matching with support for '.', '+', '*' and '?'.
// (pattern, match) --> bool does it match
// operators:
// . --> any char
// + --> 1 or more of prev char
// * --> 0 or more of prev char
// ? --> 0 or 1 of prev char
// (abc+c, abcccc) --> True
// (abcd*, abc) --> True
// (abc?c, abc) --> True
// (abc.*, abcsdfsf) --> True
I came up with below code which only implements '.' and '*' but not able to figure out how to implement others:
public static boolean isMatch(String s, String p) {
if (p.length() == 0) {
return s.length() == 0;
}
if (p.length() > 1 && p.charAt(1) == '*') { // second char is '*'
if (isMatch(s, p.substring(2))) {
return true;
}
if (s.length() > 0 && (p.charAt(0) == '.' || s.charAt(0) == p.charAt(0))) {
return isMatch(s.substring(1), p);
}
return false;
} else { // second char is not '*'
if (s.length() > 0 && (p.charAt(0) == '.' || s.charAt(0) == p.charAt(0))) {
return isMatch(s.substring(1), p.substring(1));
}
return false;
}
}
Also what is the best way to implement this problem?
Here is untested code. The idea is that we keep track of where we are in the string and the pattern. This would NOT be a good approach to try to extend to a full RE engine (just consider what adding parentheses would take), but is fine for this case:
public static boolean isMatch (String p, String s, int pos_p, int pos_s) {
if (pos_p == p.length()) {
// We matched the whole pattern.
return true;
}
else if (pos_s == s.length()) {
// We reached the end of the string without matching.
return false;
}
else if (pos_p == -1) {
// Do we match the pattern starting next position?
if (isMatch(p, s, pos_p + 1, pos_s + 1)) {
return true;
}
else {
// Try to match the pattern starting later.
return isMatch(p, s, pos_p, pos_s + 1);
}
}
else {
char thisCharP = p.charAt(pos_p);
char nextCharP = pos_p + 1 < p.length() ? p.charAt(pos_p + 1) : 'x';
// Does this character match at this position?
boolean thisMatch = (thisCharP == s.charAt(pos_s));
if (thisCharP == '.') {
thisMatch = true;
}
if (nextCharP == '*') {
// Try matching no times - we don't need thisMatch to be true!
if (isMatch(p, s, pos_p + 2, pos_s)) {
return true;
}
else {
// Try matching 1+ times, now thisMatch is required.
return thisMatch && isMatch(p, s, pos_p, pos_s + 1);
}
}
else if (nextCharP == '+') {
if (! thisMatch) {
// to match 1+, we have to match here.
return false;
}
else if (isMatch(p, s, pos_p + 2, pos_s + 1)) {
// We matched once.
return true;
}
else {
// Can we match 2+?
return isMatch(p, s, pos_p, pos_s + 1);
}
}
else if (thisMatch) {
// Can we match the rest of the pattern?
return isMatch(p, s, pos_p + 1, pos_s + 1);
}
else {
// We didn't match here, this is a fail.
return false;
}
}
}
public static boolean isMatch (String p, String s) {
// Can we match starting anywhere?
return isMatch(p, s, -1, -1);
}
I am wondering what return str.substring(1,4).equals("bad"); is doing here in the else if(len>=4). I think the if statement is a guard clause but I am not 100%. Can I have an explanation of what exactly is going on here? How is this read to output "false"?
Given a string, return true if "bad" appears starting at index 0 or 1 in the string, such as with "badxxx" or "xbadxx" but not "xxbadxx". The string may be any length, including 0. Note: use .equals() to compare 2 strings.
hasBad("badxx") → true
hasBad("xbadxx") → true
hasBad("xxbadxx") → false
public boolean hasBad(String str)
{
int len = str.length();
if(len == 3 && str.equals("bad"))
return true;
else if(len >= 4)
{
if(str.substring(0, 3).equals("bad"))
return true;
return str.substring(1, 4).equals("bad");
}
else
return false;
}
if(str.substring(0, 3).equals("bad")) is the easy part. "Return true if 'bad' is the beginning of the String.'
return str.substring(1, 4).equals("bad") essentially means, "Return true if 'bad' occurs after the first character, and false otherwise". This is basically a shortcut of
if(str.substring(1, 4).equals("bad")) return true;
else return false;
Because the if already evaluates a boolean (what goes inside of an if results in a boolean value), there's no reason to tell it to return "true if true, else false", you can just return the boolean value directly.
you can try it in other way too, like below one
public static boolean hasBad(String str) {
for (int i = 0; i < str.length() - 1; i++) {
if (str.length()>=3 && str.charAt(0) == 'b' || str.charAt(1) == 'b' ) {
if (str.substring(i).contains("bad")) {
return true;
}
}
}
return false;
}
I'm having a weird issue with if-else statements in java. Below is a recursive method that attempts to find the end of a maze called getPathThroughMaze.
private static String getPathThroughMaze(char[][] maze, Set<Point> visited, Point currentPoint) {
int currentX = currentPoint.x;
int currentY = currentPoint.y;
visited.add(currentPoint);
//end case. append '!' so we know which path leads to the end of the maze
if (currentX == (xLength - 2) && currentY == (yLength - 1)) {
return "!";
}
char left = maze[currentY][currentX - 1];
char right = maze[currentY][currentX + 1];
char up = maze[currentY - 1][currentX];
char down = maze[currentY + 1][currentX];
char current = maze[currentY][currentX];
/* If valid, visit all non-visited adjacent squares.
Only odd numbered columns will be traversed
since even numbered columns represent vertical wall
columns
*/
if (right == '_' || right == ' ') {
Point nextPoint = new Point(currentX + 2, currentY);
if (!visited.contains(nextPoint)) {
String path = "E" + getPathThroughMaze(maze, visited, nextPoint);
if (path.endsWith("!")) {
return path;
} else {
//do nothing.
}
}else {
//do nothing.
}
} else if (up == ' ') {
Point nextPoint = new Point(currentX, currentY - 1);
if (!visited.contains(nextPoint)) {
String path = "N" + getPathThroughMaze(maze, visited, nextPoint);
if (path.endsWith("!")) {
return path;
} else {
//do nothing.
}
} else {
//do nothing.
}
} else if ( current == ' ' && (down == '_' || down == ' ')) {
Point nextPoint = new Point(currentX, currentY + 1);
if (!visited.contains(nextPoint)) {
String path = "S" + getPathThroughMaze(maze, visited, nextPoint);
if (path.endsWith("!")) {
return path;
} else {
//do nothing.
}
} else {
//do nothing.
}
} else if (left == '_' || left == ' ') {
Point nextPoint = new Point(currentX - 2, currentY);
if (!visited.contains(nextPoint)) {
String path = "W" + getPathThroughMaze(maze, visited, nextPoint);
if (path.endsWith("!")) {
return path;
} else {
//do nothing.
}
} else {
//do nothing.
}
} else {
return "";
}
//otherwise...
return "";
}
At the point in the recursion where I run into a problem the variables are:
currentX = 3
currentY = 2
right = '|'
left = '|'
up = ' '
down = '_'
current = ' '
visited contains points (1,1), (3,1), (3,2)
In the first else if statement:
else if (up == ' ')
a new point (3,1) is created which IS already contained in the visited set. What I expect to happen is that
if(!visited.contains(nextPoint))
will evaluate to false and that I will (maybe after a few step over clicks in the debugger) arrive at
else if ( current == ' ' && (down == '_' || down == ' '))
where I can then check that condition (which I expect to be true) and continue traversing the maze. What actually happens is when I click step over on
if(!visited.contains(nextPoint))
the debugger (in both elcipse and intellij) moves all the way to the very last return statement of my method and it wants to return "". I don't understand why all my other if else statements are being skipped. Can anyone enlighten me as to why that might be the case? Please let me know if my explanation isn't clear enough.
If/else statements are exclusive, so you will not arrive to else if ( current == ' ' && (down == '_' || down == ' ')) as you have already entered the else if (up == ' ') branch. As if(!visited.contains(nextPoint)) in the inner if is false, the program goes into its else part with //do nothing comment and does nothing (actually, you don't need to and shouldn't write an empty else statement. At least add a log statement to it to make it easier to debug). Then it exits the if/else block and goes to return.
If you want your code to check every branch of if/else on every method call, just replace it with a number of simple if statements.
I.e. instead of:
if (condition1){
} else if (condition2){
} else if (condition3){
}
write
if (condition1){
}
if (condition2){
}
if (condition3){
}
Compare three boolean values and display the first one that is true.
Hey guys, I am trying to write a program that compares three boolean values and displays the first true one. I am comparing three words for their length, and it will display the longest. The error that I am getting is that my else tags aren't working. Take a look at the code.
//Check which word is bigger
if (len1 > len2)
word1bt2 = true;
if (len2 > len3)
word2bt3 = true;
if (len1 > len3)
word1bt3 = true;
//Check which word is the longest
if (word1bt2 == true && word1bt3 == true);
System.out.println(wor1);
else if (word2bt3 == true);
System.out.println(wor2);
else System.out.println(wor3);
I have set boolean values for word1bt2, word2bt3 and word1bt3. In eclipse, I am getting a syntax error under the elses in my code above. Any help would be great!
if (word1bt2 == true && word1bt3 == true);
Is wrong, you need to remove the semicolon:
if (word1bt2 == true && word1bt3 == true)
Same for the elses
else (word2bt3 == true);
Is wrong too, it should be
else if (word2bt3 == true)
Side note: boolean values can be used as condition, so your if statements should be
if (word1bt2 && word1bt3) // The same as if (word1bt2 == true && word1bt3 == true)
How to compare three boolean values?
Dont!
If you find yourself needing to compare three variable you may as well cater for any number of variables immediately - there's no point hanging around - do it properly straight away.
public String longest(Iterator<String> i) {
// Walk the iterator.
String longest = i.hasNext() ? i.next() : null;
while (i.hasNext()) {
String next = i.next();
if (next.length() > longest.length()) {
longest = next;
}
}
return longest;
}
public String longest(Iterable<String> i) {
// Walk the iterator.
return longest(i.iterator());
}
public String longest(String... ss) {
// An array is iterable.
return longest(ss);
}
Remove the ; and change it with brackets {}.
if (word1bt2 && word1bt3) {
System.out.println(wor1);
} else if (word2bt3) {
System.out.println(wor2);
} else {
System.out.println(wor3);
}
Issue with the else blocks: use {} insteaad of () to enclose instructions...
Remove the ; at the first if!!!!! - Quite common mistake, with very puzzling results!
//Check which word is the longest
if (word1bt2 == true && word1bt3 == true) { //leave ; and always add bracket!
System.out.println(wor1);
}
else if(word2bt3 == true)
{
System.out.println(wor2);
}
else {
System.out.println(wor3);
}
if you need a condition in an else branch, you have to use if again - plain else won't have such a feature...
ALWAYS use brackets for bodies of if statements, loops, etc!!!
Be extremely careful NOT to use ; in the lines that don't behave well with it:
if statements
for loops
while() {...} loops' while statement
try this, if lenght are equal then s1 is considered as Bigger. Also i have not added null check
public class Test {
public static void main(String[] args) {
String word1 = "hi";
String word2 = "Hello";
String word3 = "Hell";
String Bigger = null;
if(word1.length() >= word2.length() && word1.length() >= word3.length() ){
Bigger = word1;
}else if(word2.length() >= word1.length() && word2.length() >= word3.length()){
Bigger = word2;
}else if(word3.length() >= word2.length() && word3.length() >= word1.length()){
Bigger = word3;
}
System.out.println(Bigger);
}
}
I actually try to convert four different Boolean into true/false.
My case is,
True false false false Then true else false
false True false false Then true else false
false false True false Then true else false
false false false True Then true else false
I tried like this,
int a=1;
int b=0;
int c=0;
int d=0;
int cnt=0;
// A block of code will be executed only when any one of the four variables is 1 and
//the rest of them is 0. and another block will be executed when the above mentioned
//condition become false.
if (a==0) { cnt+=1; }
if (b==0) { cnt+=1; }
if (c==0) { cnt+=1; }
if (d==0) { cnt+=1; }
if (cnt==3) { // true block } else { //false block }
The above code is working perfectly fine, But i had taken a challenge to check this condition in a single if statement. Then i tried like this.
if(!((!(a==0) && !(b==0)) && (!(c==0) && !(d==0))))
{
//true block
}
else
{
//false block
}
The above condition is failing in some combinations(a=1 b=0 c=1 d=1). Can anybody point out what the issue is.? or suggest any new ideas.?
My objective is convert (3 false + 1 true) into true other wise into false.
[Note: I just gave the scenario for understanding purpose only. a,b,c,d value may be differ. See my objective. Don't say answers in favor of 1 and 0]
I think I would use the following method, which makes the algorithm reusable and support any number of arguments. It returns true only if exactly one argument was true.
private boolean oneTrue(boolean... args){
boolean found = false;
for (boolean arg : args) {
if(found && arg){
return false;
}
found |= arg;
}
return found;
}
You can test it like this:
private void test(){
boolean a = false;
boolean b = true;
boolean c = false;
boolean d = false;
System.out.println(oneTrue(a,b,c,d));
}
Shortest pure bool solution which I can suggest:
System.out.println((a | b) ^ (c | d)) & ((a ^ b) | (c ^ d));
But in your program already already used 1 and 0, if it variables always 1 and 0, you may not use boolean just use following:
if (a + b + c + d == 1)
{
// true
} else
{
// false
}
if this varibales may have any values. In this case I recommend convert it to 1 and 0 instead of boolean and again can simply calculate sum.
How about this?
boolean a = true;
boolean b = false;
boolean c = false;
boolean d = false;
if ((a ? 1 : 0) + (b ? 1 : 0) + (c ? 1 : 0) + (d ? 1 : 0) == 1) {
System.out.println("You win!");
}
[edit]... or here's another way to do it :
if ((a ^ b ^ c ^ d) & ((a & b) == (c & d))) {
System.out.println("**XOR** You win!");
}
You can use the following expression:
a && !(b || c || d) ||
b && !(a || c || d) ||
c && !(a || b || d) ||
d && !(a || b || c)