Java 递归地将pi替换为字符串中的3.14(无循环)

Java 递归地将pi替换为字符串中的3.14(无循环),java,Java,给定一个字符串,递归地计算一个新字符串,其中pi的所有外观都被3.14替换 changePi("xpix") → "x3.14x" changePi("pipi") → "3.143.14" changePi("pip") → "3.14p" 我的代码工作得很好,但是有没有其他方法可以在不创建新字符串str2的情况下递归地无循环地解决这个问题? 先谢谢你 这是我的密码: public String changePi(String str) { String str2 = ""

给定一个字符串,递归地计算一个新字符串,其中pi的所有外观都被3.14替换

changePi("xpix") → "x3.14x"
changePi("pipi") → "3.143.14"
changePi("pip") → "3.14p"
我的代码工作得很好,但是有没有其他方法可以在不创建新字符串str2的情况下递归地无循环地解决这个问题? 先谢谢你 这是我的密码:

    public  String changePi(String str) {
    String str2 = "";
    return changePi(str, str2);
}

public String changePi(String str, String str2) {
    if (str.length() == 0)
        return str2;

    else {
        if (str.endsWith("pi")) {
            str2 = 3.14 + str2;
            return changePi(str.substring(0, str.length() - 2), str2);
        } else
            str2 = str.charAt(str.length() - 1) + str2;

    }
    return changePi(str.substring(0, str.length() - 1), str2);

}

您的解决方案是一个很好的方法。当您替换两次时,会有点困惑,我相信我会这样做:

如果str
是的,不过我想这取决于你所说的创建一个新字符串是什么意思。从某种意义上讲,这是可以的,但不需要命名。

使用相同的机制,您可以使用StringBuilder并在原位修改它。这应该更节省内存

private static final String PI = "pi";
private static final String THREE_POINT_ONE_FOUR = "3.14";

public String changePi(String s) {
    // Work with a StringBuilder for efficiency.
    StringBuilder sb = new StringBuilder(s);
    // Start replacement at 0.
    return changePi(sb, 0).toString();
}

private StringBuilder changePi(StringBuilder sb, int i) {
    // Long enough?
    if (i + PI.length() <= sb.length()) {
        // Is it there?
        if (sb.subSequence(i, i + PI.length()).equals(PI)) {
            // Yes! - Replace it and recurse.
            sb.replace(i, i + PI.length(), THREE_POINT_ONE_FOUR);
            return changePi(sb, i + THREE_POINT_ONE_FOUR.length());
        } else {
            // Not there - step to next.
            return changePi(sb, i + 1);
        }
    }
    return sb;
}

private void test(String s) {
    System.out.println(s + " -> " + changePi(s));
}

private void test() {
    test("pipi");
    test("xpix");
    test("pip");
}

瞧!简洁明了:

String fun(int i) {
        if(i == s.length()) return "";
        if(i+1 < s.length() && s.charAt(i) == 'p' && s.charAt(i+1) == 'i') {
            return "3.14" + fun(i+2);
        } else {
            return s.charAt(i) + fun(i+1);
        }
}

你犯的错误与你在上一个问题中犯的相同。另外,我更愿意检查字符串是否以字符串开头,而不是以字符串结尾……我假设您希望一些您能够理解且易于解释的内容

你能匹配pi或字符串已经小于长度pi符号->不能做什么所以返回它。 它是以π开头的吗?如果是这样,则返回与字符串其余部分连接的替换项,其余部分仅从第0个索引开始使用lengthpi字符。。。 如果不是以pi开头,则将第一个字符与changePi的输出以及字符串的其余部分连接起来作为输入。 如果你想使用endsWith逻辑,这里是同样的算法

public static String changePi(String str) {
    if (str.length() < "pi".length()) {
        return str;
    }

    if (str.endsWith("pi")) {
        return changePi(str.substring(0, str.length() - "pi".length())) + "3.14";
    }

    return changePi(str.substring(0, str.length() - 1)) + str.charAt(str.length() - 1);
}

我以前从未编写过Java,但这似乎是可行的:

public class HelloWorld {
 public static void main(String[] args) {
  System.out.println(changePi("xpix"));
  System.out.println(changePi("pipi"));
  System.out.println(changePi("pip"));
 }

 public static String changePi(String str) {
  int len = str.length();
  if (len < 2)
   return str;

  if (str.endsWith("pi"))
   return changePi(str.substring(0, len - 2)) + "3.14";
  else
   return changePi(str.substring(0, len - 1)) + str.substring(len - 1, len);
 }
}
解释:

这更接近于真正的递归解决方案,因为函数不知道字符串no str2的正确部分,所以调用函数负责跟踪它

终端case在比pi短的字符串上运行,在这种情况下,我们返回剩余的0或1个字符

如果字符串以pi结尾,我们将在该字符串之前获取该字符串的其余部分,并将其传递给新的迭代,但请记住在返回时追加3.14

如果字符串没有以这个结尾,我们只需断开一个字符并保持它重新连接

批评:

但是,这是非常低效的,因为每个.substr调用都在创建一个全新的字符串对象,我们做了很多这样的调用。
如果您使用字符链表之类的东西,您的运气会更好。

您为什么不考虑使用正则表达式

对于您提到的所有测试用例,以下内容似乎都很好:

public String changePi(String str) {
  return str.replaceAll("pi", "3.14");
}
请注意,在Java中,字符串是不可变的。一旦初始化字符串,就不能修改它。每次执行str2=。。。您实际上是在创建一个全新的字符串对象

如果你需要递归地做,也就是说,这是一些课程,那么你所做的是非常好的,尽管我会使用indexOfpi而不是endsWithpi并删除尾随字符,但无论如何


这是执行递归的标准方法,str2是累加器,您可能想重命名它,以便清楚它在做什么。您可能想考虑使用String Bu建器代替第二个参数的字符串,在您的基本情况下,调用ToString获取最终字符串。尽管老实说,创建新字符串和使用StringBuilder之间的计算成本差异已经非常小。

希望我的答案能够解释一切:

public String changePi(String str) {
  if(str.length() == 0){
    return str;
  }
  if(str.startsWith("pi")){
    return "3.14" + changePi(str.substring(2));
  }

  return str.substring(0,1) + changePi(str.substring(1));
}
public String changePi(String str) {
  if (str.length() < 1) return ""; // return if string length is zero
  String count = str.substring(0,1); // get the string
  int increment = 1; // increment variable to iterate the string
  if (str.length() > 1 && str.substring(0, 2).equals("pi")){
    //string length > 1 and it pi if found
    count = "3.14";
    increment = 2;//increment by 2 characters
  }
  //attach the 3.14 part or substring(0,1) and move forward in the string
  return count + changePi(str.substring(increment));
}
答案如下:

public String changePi(String str) {
     if(str.equals("")){
       return str;
     }
     else if(str.length()>=2 && str.charAt(0)=='p' && str.charAt(1)=='i') {
       return "3.14" + changePi(str.substring(2));
     }
     else{
       return str.charAt(0) + changePi(str.substring(1));
     }
     
    }

A.在返回所有其他流时,我会将最后一个返回行放在else子句中,将其留在外部会创建可读性较差的代码b。你要问的是是否有一个现成的解决方案?很明显,您至少需要一个字符串长度的str,不幸的是,它似乎不太可能,因为3.14比pi长,不过,我建议您改进性能,就是使用一个StringBuilder,这样你就可以用StringBuilder.append替换各种+操作,最后返回StringBuilder.toStringI我想这个人想用3.14代替pi,而不是相反。你没有通过s,如果p是最后一个字母,我猜你会尝试访问s的非法索引,内存方面,这并不比原来的解决方案“编辑”好:我看到您添加了一个检查,以避免非法索引访问字符串在java中是不可变的现在有办法更改原始的,可能是使用字符串生成器,但问题作者没有指定。因为字符串是不可变的,简单的答案是:不,在不创建字符串的情况下无法返回结果。此外,使用+和非final strings 3.14意味着您将创建比必须创建的字符串更多的字符串,对于大多数输入来说,这是一个坏主意。您在每个递归调用中调用子字符串,这在^2上,有一个更简单的On解决方案,此外,将字符串作为参数传递给递归函数也是无效的。@abdenaceurlichehb此答案的目的不是为问题提供最佳递归解决方案,也不是为问题提供最佳方法。它的目标是布林
给OP多点光线,这样他可以改进自己的风格。我可以很容易地实现一种开启的方法,但这并不是OP解决方案的改进,而是我自己的一种……将字符串传递给接收函数既不推荐也不有效。@abdenaceurlicheheb我在这里使用的是StringBuilder!欢迎来到堆栈溢出。对于堆栈溢出,不鼓励使用仅代码的答案,因为它们没有解释堆栈溢出是如何解决问题的。请编辑您的答案,以解释此代码的作用,以及它如何改进这个2年前的问题已有的其他答案,以便对其他有类似问题的用户有用。
public class ChangePi {
    public static String changePi(String str) {
        String pi = "3.14";
        if (str.length() < 2) {
            return str;
        }
            return (str.substring(0, 2).equals("pi")) ? pi + changePi(str.substring(2)) :
                    str.substring(0, 1) + changePi(str.substring(1));
        }


        }
public String changePi(String str) {
  if (str.length() < 1) return ""; // return if string length is zero
  String count = str.substring(0,1); // get the string
  int increment = 1; // increment variable to iterate the string
  if (str.length() > 1 && str.substring(0, 2).equals("pi")){
    //string length > 1 and it pi if found
    count = "3.14";
    increment = 2;//increment by 2 characters
  }
  //attach the 3.14 part or substring(0,1) and move forward in the string
  return count + changePi(str.substring(increment));
}
public String changePi(String str) {
     if(str.equals("")){
       return str;
     }
     else if(str.length()>=2 && str.charAt(0)=='p' && str.charAt(1)=='i') {
       return "3.14" + changePi(str.substring(2));
     }
     else{
       return str.charAt(0) + changePi(str.substring(1));
     }
     
    }
public String changePi(String str) {
  if(str.length() == 0) return str;
  if(str.charAt(0) == 'p' && str.length() >= 2){
    if(str.charAt(1) == 'i'){
      return "3.14" + changePi(str.substring(2));
    }
  }
    return str.charAt(0) + changePi(str.substring(1));
}