使用递归比较字符串

时间:2013-04-05 04:43:24

标签: java recursion

我有一份我无法弄清楚的家庭作业。我必须编写一个静态方法匹配(String x,String y),它返回一个布尔值,表示字符串x和字符串y是否匹配。匹配过程应该允许“通配符”,例如“@”字符,它将与任何单个字符匹配,“*”字符将匹配任何类型的0或更多字符。我不允许使用任何循环,我必须使用递归。 到目前为止我写的是......

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
}

}

主要方法是作业给出的测试程序。我意识到我的代码有点凌乱 - 我有点争吵 - 但我似乎可以让它的大部分工作。唯一没有返回正确值的示例是数字11.当它应该为真时我得到错误。我认为这种情况发生的原因是因为字符串y以''开头,我的方法所做的就是将x和y字符串分成最后3个字符,即使第一个''在y中应该代表2个字符。如何才能使这样的案例返回匹配?

2 个答案:

答案 0 :(得分:1)

基本上你需要理解递归的概念(这是你作业的目标)。递归的工作方式是每次函数调用自身时,当前执行(变量/执行信息)进入堆栈并在那里休眠直到新的调用结束。

为了解决你提到的问题,让我们举一个简单的例子,你好和h @ llo。解决问题的基本方法是一次又一次地匹配服务调用,直到

  1. 找到完美匹配 - 返回true

  2. 发现失败情况 - 返回错误

  3. 如果没有2以上,匹配就会将自己的一个字符小于上一个字符

  4. 这样的东西

    致电1:你好&amp; h @ llo //再次呼叫匹配并将呼叫移动到堆栈,等待回复

    致电2:ello&amp; @llo //匹配特殊字符

    调用3:llo和llo //完美匹配返回true以调用2

    返回呼叫2:从prv呼叫收到true并返回呼叫1

    返回调用1:收到true并返回main。

    一旦理解了递归堆栈的概念,解决这个问题就很简单了

    您的最终匹配方法看起来像

    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;
    }
    

答案 1 :(得分:0)

本着recursion(你的一个标签)而不是Java的精神,这里有一个Scheme实现,可以让你的所有测试用例都正确。

(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

注意,对于"*l*"的测试用例,上面的答案是正确答案,但出于错误的原因。还有其他人认为上述错误(与"*"相关)但不在您的测试用例中。