递归计算以sub开头和结尾并返回其长度的最大子字符串

时间:2016-10-18 08:15:53

标签: java string recursion substring

任务是:给定一个字符串和一个非空的子字符串sub,递归计算最大的子字符串,它以sub开头和结尾并返回其长度。

示例:

strDist("catcowcat", "cat") → 9
strDist("catcowcat", "cow") → 3
strDist("cccatcowcatxx", "cat") → 9

请您查看我的代码并告诉我它的问题是什么?

public int strDist(String str, String sub)
{

  if(str.length()<sub.length())
  return 0;
  if(str.length()==sub.length()&&str.equals(sub))
  return str.length();

  if(str.length()<2)
  {
    if(str.contains(sub))
    {

      return 1;
    }
    return 0;
  }

  if (str.length()==2)
 {
   if (sub.length()==2 && str.equals(sub))
   return 2;
   if (str.contains(sub))
   return 1;
   return 0;
 }

if(str.length()>2)
{
   if(str.startsWith(sub)&&str.endsWith(sub))
   {
     return str.length();
   }
   if(str.substring(0,sub.length()).equals(sub))
   {
    strDist(str.substring(0,str.length()-2),sub);
   }
   if(str.substring(str.length()-sub.length(),str.length()-1).equals(sub))
   strDist(str.substring(1,str.length()-1),sub);
}
  return strDist(str.substring(1,str.length()-1),sub);



}

它不适用于案例strDist("hiHellohihihi", "hih")→5 并返回零。

6 个答案:

答案 0 :(得分:1)

首先,为了回答您的问题,我在您的代码中发现了许多问题。我的更正后的版本随之而来,对我所做的更改发表了评论。

public int strDist(String str, String sub) {

    if (str.length() < sub.length())
        return 0;
    // simplified condition
    if (str.equals(sub))
        return str.length();

    if (str.length() < 2) {
        if (str.contains(sub)) {
            // corrected (if str and sub are both empty strings, you don’t want to return 1)
            return str.length();
        }
        return 0;
    }

    // deleted str.length() == 2 case that didn’t work correctly

    if (str.startsWith(sub) && str.endsWith(sub)) {
        return str.length();
    }
    if (str.startsWith(sub)) { // simplified
        // subtracting only 1 and added return statement
        return strDist(str.substring(0, str.length() - 1), sub);
    }
    // changed completely -- didn’t understand; added return statement, I believe this solved your test case
    if (str.endsWith(sub))
        return strDist(str.substring(1), sub);
    return strDist(str.substring(1, str.length() - 1), sub);

}

现在,如果我这样做:

    System.out.println(strDist("catcowcat", "cat"));
    System.out.println(strDist("catcowcat", "cow"));
    System.out.println(strDist("cccatcowcatxx", "cat"));
    System.out.println(strDist("hiHellohihihi", "hih"));

我明白了:

9
3
9
5

其次,正如我在评论中所说,我认为在这里使用递归没有任何意义(除了练习之外)。您的方法的以下版本没有,它更简单,它的工作方式相同:

public int strDist(String str, String sub) {
    int firstOccurrence = str.indexOf(sub);
    if (firstOccurrence == -1) { // sub not in str
        return 0;
    }
    int lastOccurrence = str.lastIndexOf(sub);
    return lastOccurrence - firstOccurrence + sub.length();
}

最后,这可能有用也可能没用,递归版本不需要像你那样复杂:

public int strDist(String str, String sub) {
    if (sub.isEmpty()) {
        throw new IllegalArgumentException("sub mustn’t be empty");
    }
    if (str.length() <= sub.length()) {
        if (str.equals(sub)) {
            return str.length();
        } else { // sub cannot be in str
            return 0;
        }
    }
    if (str.startsWith(sub)) {
        if (str.endsWith(sub)) {
            return str.length();
        } else {
            return strDist(str.substring(0, str.length() - 1), sub);
        }
    } else {
        return strDist(str.substring(1), sub);
    }
}

如果可以,可以先得到一些工作,即使它不是最简单和最优雅的解决方案。无论是有效还是无效,都是思考简化方法的好时机。它可以更容易地确定错误,并在以后简化维护。特殊情况,例如长度1和长度2,通常是简化的一个很好的选择:看看一般代码是否已经满足它们或者可以很容易地进行。

答案 1 :(得分:1)

这是我解决它的方式,它有点类似,但我发现它更简单(希望它有帮助):

public int strDist(String str, String sub) { 

  if(str.length() < sub.length())
    return 0;

  if(!str.contains(sub))return 0;

  if(str.startsWith(sub)&& str.endsWith(sub))
    return str.length();

  if(str.startsWith(sub) )
    return  strDist(str.substring(0,str.length()-1),sub);

  if(str.endsWith(sub)) 
    return strDist(str.substring(1,str.length()),sub);

  else return strDist(str.substring(1,str.length()-1),sub);
}

答案 2 :(得分:0)

您的实施很难遵循。描述算法而不是提供实现更合适。

根据说明,以下是我的实施。我认为它简洁易懂。

class Example {

    private static int indexOf(String str, int idx, String sub, int res) {

        if (str.length() < sub.length()) return res;

        int tmp = str.indexOf(sub, idx);

        if (tmp < 0) return res;

        return Math.max(tmp, indexOf(str, tmp + 1, sub, res));

    }

    public static int strDist(String str, String sub) {

        if (str.length() < sub.length()) return 0;


        int from = str.indexOf(sub);
        int to = indexOf(str, from + 1, sub, from);


        return to - from + sub.length();
    }

    public static void main(String[] args) {

        System.out.println();
        System.out.println(strDist("catcowcat", "cat"));
        System.out.println(strDist("catcowcat", "cow"));
        System.out.println(strDist("cccatcowcatxx", "cat"));
        System.out.println(strDist("hiHellohihihi", "hih"));
    }
}

结果:

9
3
9
5

答案 3 :(得分:0)

因为,其他人已经回答了递归代码,我已经使用KMP算法包含了一个O(n)解决方案

#include <iostream>
#include <vector>
using namespace std;
vector<int> failureFunction(string a){
    int n= a.length();
    vector<int> f(n+1);
    f[0]=f[1]=0;
    for(int i=2;i<=n;i++){
        int j = f[i-1];
        while(1){
            if( a[j]== a[i-1]){
                f[i]= j+1;
                break;
            }
            else if (j==0){
                f[i]= 0;
                break;
            }
            else j = f[j];
        }
    }
    return f;
}
int strDist(string str , string sub ){
    int n= sub.length();
    int m= str.length();
    vector<int> f = failureFunction(sub);
    vector<int> ff(m+1);

    ff[0]= (str[0]==sub[0]) ? 1 : 0;
    for(int i=1;i<m;i++){
        int j = ff[i-1];
        if(j==n)
            j=f[j];
        while(1){
            if(  sub[j] == str[i] ){
                ff[i]= j+1;
                break;
            }
            else if(j==0){
                ff[i]= 0;
                break;
            }
            else j= f[j];
        }
    }
    int first_occ = -1, last_occ= -1;
    for(int i=0;i<m;i++){
        if( ff[i]==n ){
            if( first_occ == -1 ){
                first_occ = i-n+1;
            }
            last_occ = i;
        }
    }
    if ( first_occ == -1 )
        return 0;
    else    
    return last_occ - first_occ + 1;
}   
int main() {
    // your code goes here
    cout<<strDist("catcowcat", "cat")<<endl;
    cout<<strDist("hiHellohihihi", "hih")<<endl;
    cout<<strDist("catcowcat", "cow")<<endl;
    cout<<strDist("cccatcowcatxx", "cat")<<endl;
    cout<<strDist("xx","y");
    return 0;
}

答案 4 :(得分:0)

一个带有解释的小解决方案

public int strDist(String str, String sub) {
  // base case
  if(str.length() < sub.length() || !str.contains(sub)) return 0;

  // success case      
  if(str.startsWith(sub) && str.endsWith(sub)) {
    return str.length(); 
  }

  // cleaning the end of the string to be able to find the success case if exists
  if(str.startsWith(sub)) {
    return strDist(str.substring(0, str.length() - 1), sub);
  }

  // cleaning the begin of the string to be able to find the success case if exists
  return strDist(str.substring(1), sub);
}

答案 5 :(得分:0)

这是一个更原始的解决方案。

public int strDist(String str, String sub) {

  //first base case to check if the string doesnt have the substring
  if(str.length() < sub.length()) return 0;

  //check if the string starts with the substring
  if(str.substring(0,sub.length()).equals(sub)){

    //check if the string ends with the substring, if so return the length of the string
    if(str.substring(str.length() - sub.length(),str.length()).equals(sub)){
      return str.length();
    }

    //if the above condition fails, shave the last charater of the string and recurse
    return strDist(str.substring(0,str.length()-1),sub);
  }

  //keep searching for the substring to appear in the string
  return strDist(str.substring(1),sub);
}