Related
So, the task is to create a string that makes a progression throughout the letters of a string, returning a substring progressively longer.
For example if the input is Book, the answer would be: BBoBooBook . For the input Soup the method would return SSoSouSoup. I want to write it recursively. In my current method I receive no error but at the same time no anwer from the compiler.
public static String stringProgression(String str) {
int index = 1;
String result = "";
if (str.length() == 0) {
return "" ;
} else while (index <= str.length()); {
result = result + stringExplosion(str.substring(0, index));
index++;
}
return result;
}
In your code, you are using two different method names, stringProgression and stringExplosion.
Further, you have a while loop with a semicolon, while (index <= str.length()); which forms an empty loop. Since index doesn’t change in this empty loop, it will be an infinite loop when the condition is fulfilled.
Generally, a while loop contradicts the intent to have a recursive solution.
To find a recursive solution to a problem, you have to find the self-similarity in it. I.e. when you look at the intended result for Book, BBoBooBook, you can recognize that the beginning, BBoBoo is the right result for the string Boo, and BBo is the right result for Bo. So, the original string has to be appended to the result of a recursive evaluation of the substring:
public static String stringProgression(String str) {
if(str.isEmpty()) {
return str;
}
return stringProgression(str.substring(0, str.length() - 1)) + str;
}
An alternative, shorter syntax for the same is:
public static String stringProgression(String str) {
return str.isEmpty()? str: stringProgression(str.substring(0, str.length() - 1)) + str;
}
Check this one:
private static String doStringProgression(String str, String res, int length) {
if(length > str.length()) {
return res;
}
return doStringProgression(str, res + str.substring(0, length), length + 1);
}
And you can call the method with input like in the following example:
public static String stringProgression(String str) {
return doStringProgression(str, "", 1);
}
Given a string, compute recursively (no loops) a new string where all appearances of "pi" have been replaced by "3.14".
changePi("xpix") → "x3.14x"
changePi("pipi") → "3.143.14"
changePi("pip") → "3.14p"
My code worked perfectly but is there any other way (only recursively no loops) to do this problem without having to create a new string str2 ?
Thank you in advance
here is my code :
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);
}
Using the same mechanism you can use a StringBuilder and modify it in-situ. This should be much more memory efficient.
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");
}
You are doing the same mistake as you did in your previous question. Also I would prefer to check if a string starts with, and not ends with a string...I am assuming that you would like something that you can understand and it's easy to explain.
Can you match "pi" or the string is already less than length("pi") symbols -> cant do nothing much so return it.
Does it starts with "pi"? If so return the replacement concatenated with the rest of the string (just the rest starts length("pi") characters away from the 0th index...
If it isn't starting with "pi" than concatenate the first character with what's the output of changePi and the rest of the string as its input.
public static String changePi(String str) {
if (str.length() < "pi".length()) {
return str;
}
if (str.startsWith("pi")) {
return "3.14" + changePi(str.substring("pi".length(), str.length()));
}
return str.charAt(0) + changePi(str.substring(1, str.length()));
}
And still if you like to use the "endsWith" logic then here is the same algorythm applied.
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);
}
public static String changePi(String str) {
int num = str.indexOf("pi");
if (num==-1) return str;
return str.substring(0,num)+"3.14"+changePi(str.substring(num+2));
}
does it, though I guess it depends what you mean by create a new string. In a sense this does, but without naming it.
Your solution is a nice approach (it's a little confusing as you replace twice, I believe) and I would make sth like:
If str <= than 2, check str if equals pi, return 3,14 or str
Else, if ends with pi return Change(str-2)+Change(last2), else return Change(str-1)+Change(lastChar)
Edited: now changes pi for 3,14
Voila! simple and clean:
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);
}
}
Any reason why you have not considered using regular expressions?
The following seems to work fine for all the test cases you mentioned:
public String changePi(String str) {
return str.replaceAll("pi", "3.14");
}
Note that in Java a String is immutable. You cannot modify a String once you initialise it. Each time you are doing str2 = ... you are really creating a completely new String object.
If you need to do it recursively (i.e. it is some coursework), then what you did is perfectly fine (although I would have used indexOf("pi") rather than endsWith("pi") and removing the trailing characters, but anyway.
It is the standard way to perform recursion, with str2 being the accumulator (maybe you want to rename it so that it is clear what it is doing). You might want to consider using StringBuilder instead of a String for the second parameter, and in your base case you call toString() to get the final string... although honestly the difference in computation cost between creating a new String and using a StringBuilder has become very low.
I've never written Java before, but this seems to work:
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);
}
}
Explaination:
This is closer to a true recursive solution, since the function doesn't know about the right portion of the string (no str2), it's the calling function's responsibility to keep track of it.
The terminal case is running on a string shorter than "pi", in which case we return the remainder (0 or 1 chars).
If the string ends in "pi", we take the rest of the string before that and pass that to the new iteration, but keep in mind to append "3.14" when that returns.
If the string doesn't end in that, we just break off a single character and keep it to reattach.
Criticism:
This is horribly inefficient, though, as every .substr call is creating a whole new string object, and we do a lot of these calls.
You would have better luck using something like a linked list of characters.
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 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));
}
}
Hope my answer explains everything :)
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));
}
Here is the answer:
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));
}
This question already has answers here:
Understanding recursion [closed]
(20 answers)
Closed 7 years ago.
public class recursiveReverse {
public static String reverse(String str){
if (str == null) {
return null;
}
if (str.length() <= 1) {
return str;
}
return reverse(str.substring(1)) + str.charAt(0);
}
public static void main(String[] args) {
reverse("car");
}
}
I get to the first time the if (str.length() <= 1) returns true, then I get lost.
Like others have pointed out, you would be well served by stepping through the code under the debugger.
Here's the code with "printf's":
Test.java =>
public class Test {
public static String reverse(String str){
System.out.println("-->str=" + str);
if (str == null) {
System.out.println("<--str=null");
return null;
}
if (str.length() <= 1) {
System.out.println("<--str=str");
return str;
}
String result = reverse(str.substring(1)) + str.charAt(0);
System.out.println("<--result=" + result);
return result;
}
public static void main(String[] args) {
reverse("car");
}
}
Output, java Test =>
-->str=car
-->str=ar
-->str=r
<--str=str;
<--result=ra
<--result=rac
Let's take it one line at a time.
If the string to reverse is null, the method returns null.
If the string to reverse as a length <= 1, it is returned as is.
If the string is longer, the it will return the reversed sub string starting at position 1, concatenated with the first character of the string.
So:
reverse("a") --> a
reverse ("ab") -> reverse("b") + "a" -> "ba"
reverse ("abc") -> reverse("bc") + a -> reverse("c") + "b" + "a"
etc.
It is recursive call to reverse function till the length of string reaches one character.
In above case the string to reverse is CAR.
In first pass it will become { reverse (AR) + C}
In second pass it will Become { reverse(R) +A }
In third pass it get value of reverse(R) as R
Which will become R +A +C =RAC as final answer.
My assignment is to write methods for a class where I test for palindromes that a user enters. The class must have a recursive method and that method must call a helper method that removes spaces, punctuation, and ignores case.
I have two working classes that do these things but I'm wondering which structure works better and which helper method actually fits the description of a helper method.
Here's the first class:
public class RecursivePalindrome
{
public boolean Palindrome(String s)
{
return PalindromeHelper(s);
}
public boolean PalindromeHelper(String s)
{
String a = s.toLowerCase(); //Converts any capital letters to lowercase beforte analyzing the string
a = a.replaceAll(" ", ""); //Removes any and all spaces in the string
for(int i = 0; i < a.length(); i++) //Removes punctuation by using isLetter method from Character Class
{
if(Character.isLetter(a.charAt(i)) == false)
a = a.replace(a.substring(i, i+1), "");
}
if(a.length() == 0 || a.length() == 1)
return true;
else if(a.charAt(0) == (a.charAt(a.length() - 1)))
return PalindromeHelper(a.substring(1, a.length() - 1));
else
return false;
}
}
And the second one:
public class Recurs
{
public boolean Palindrome(String s)
{
String l = PalindromeHelper(s);
if(l.length() == 0 || l.length() == 1)
return true;
else if(l.charAt(0) == (l.charAt(l.length() - 1)))
return Palindrome(l.substring(1, l.length() - 1));
else
return false;
}
public String PalindromeHelper(String s)
{
s = s.toLowerCase(); //Converts any capital letters to lowercase before analyzing the string
s = s.replaceAll(" ", ""); //Removes any and all spaces in the string
for(int i = 0; i < s.length(); i++) //Removes punctuation by using isLetter method from Character Class
{
if(Character.isLetter(s.charAt(i)) == false)
s = s.replace(s.substring(i, i+1), "");
}
return s;
}
}
I would write it this way.
class RecursivePalindrome
{
public boolean Palindrome(String s)
{
//Think about using a stringbuilder instead of a string.
String a = s.toLowerCase(); // Converts any capital letters to lowercase
// beforte analyzing the string
a = a.replaceAll(" ", ""); // Removes any and all spaces in the string
for (int i = 0; i < a.length(); i++) // Removes punctuation by using
// isLetter method from Character
// Class
{
if (Character.isLetter(a.charAt(i)) == false)
a = a.replace(a.substring(i, i + 1), "");
}
return validatePalindrome(a);
}
public boolean validatePalindrome(String s)
{
if (s.length() == 0 || s.length() == 1)
return true;
else if (s.charAt(0) == (s.charAt(s.length() - 1)))
return PalindromeHelper(s.substring(1, s.length() - 1));
else
return false;
}
}
A couple of things before we get to the code...
A "helper" method is more usually called a utility method, which is a stateless piece of code - being stateless:
it should be declared as static
Adhering to java naming conventions is a great idea, so:
method names start with a lowercase letter
boolean methods start with is if reasonable to do so
So, your "helper" method should look like this:
private static String clean(String s) {
return s.toLowerCase().replaceAll("[^a-z]", "");
}
This method does everything your method does, but in a fraction of the code.
Because your main method is also stateless, it too should be static, unless it is required to be an instance method because of class hierarchy or interfaces etc.
Thus, your main method should be:
public static boolean isPalindrome(String s) {
return isPalindromeClean(clean(s));
}
private static boolean isPalindromeClean(String s) {
return s.length() < 2 || a.endsWith(s.charAt(0)) &&
isPalindromeClean(l.substring(1, l.length() - 1));
}
Again, one line of code does it all. Some things to note:
your code calls the "clean" method every recursion, but by creating a second method, I avoid this inefficiency.
the use of endsWith() to both simply and clarify the condition
the use of a single simple return statement that encapsulates the logic
The whole class becomes the following, with just 3 lines of actual code.
public class Recurse {
public static boolean isPalindrome(String s) {
return isPalindromeClean(clean(s));
}
private static boolean isPalindromeClean(String s) {
return s.length() < 2 || a.endsWith(s.charAt(0)) &&
isPalindromeClean(l.substring(1, l.length() - 1));
}
private static String clean(String s) {
return s.toLowerCase().replaceAll("[^a-z]", "");
}
}
I wouldn't bother even having the clean method - I would simply in-line it like this:
public static boolean isPalindrome(String s) {
return isPalindromeClean(s.toLowerCase().replaceAll("[^a-z]", ""));
}
But if you've been set an assignment that says you have to create it then you're stuck with it. I would show this alternative though.
Usually, the more elegant the code, the less there is of it.
I want to remove the last character from a string. I've tried doing this:
public String method(String str) {
if (str.charAt(str.length()-1)=='x'){
str = str.replace(str.substring(str.length()-1), "");
return str;
} else{
return str;
}
}
Getting the length of the string - 1 and replacing the last letter with nothing (deleting it), but every time I run the program, it deletes middle letters that are the same as the last letter.
For example, the word is "admirer"; after I run the method, I get "admie." I want it to return the word admire.
replace will replace all instances of a letter. All you need to do is use substring():
public String method(String str) {
if (str != null && str.length() > 0 && str.charAt(str.length() - 1) == 'x') {
str = str.substring(0, str.length() - 1);
}
return str;
}
Why not just one liner?
public static String removeLastChar(String str) {
return removeLastChars(str, 1);
}
public static String removeLastChars(String str, int chars) {
return str.substring(0, str.length() - chars);
}
Full Code
public class Main {
public static void main (String[] args) throws java.lang.Exception {
String s1 = "Remove Last CharacterY";
String s2 = "Remove Last Character2";
System.out.println("After removing s1==" + removeLastChar(s1) + "==");
System.out.println("After removing s2==" + removeLastChar(s2) + "==");
}
public static String removeLastChar(String str) {
return removeLastChars(str, 1);
}
public static String removeLastChars(String str, int chars) {
return str.substring(0, str.length() - chars);
}
}
Demo
Since we're on a subject, one can use regular expressions too
"aaabcd".replaceFirst(".$",""); //=> aaabc
The described problem and proposed solutions sometimes relate to removing separators. If this is your case, then have a look at Apache Commons StringUtils, it has a method called removeEnd which is very elegant.
Example:
StringUtils.removeEnd("string 1|string 2|string 3|", "|");
Would result in:
"string 1|string 2|string 3"
public String removeLastChar(String s) {
if (s == null || s.length() == 0) {
return s;
}
return s.substring(0, s.length()-1);
}
Don't try to reinvent the wheel, while others have already written libraries to perform string manipulation:
org.apache.commons.lang3.StringUtils.chop()
In Kotlin you can used dropLast() method of the string class.
It will drop the given number from string, return a new string
var string1 = "Some Text"
string1 = string1.dropLast(1)
Use this:
if(string.endsWith("x")) {
string= string.substring(0, string.length() - 1);
}
if (str.endsWith("x")) {
return str.substring(0, str.length() - 1);
}
return str;
For example, the word is "admirer"; after I run the method, I get "admie." I want it to return the word admire.
In case you're trying to stem English words
Stemming is the process for reducing inflected (or sometimes derived) words to their stem, base or root form—generally a written word form.
...
A stemmer for English, for example, should identify the string "cats" (and possibly "catlike", "catty" etc.) as based on the root "cat", and "stemmer", "stemming", "stemmed" as based on "stem". A stemming algorithm reduces the words "fishing", "fished", "fish", and "fisher" to the root word, "fish".
Difference between Lucene stemmers: EnglishStemmer, PorterStemmer, LovinsStemmer outlines some Java options.
As far as the readability is concerned, I find this to be the most concise
StringUtils.substring("string", 0, -1);
The negative indexes can be used in Apache's StringUtils utility.
All negative numbers are treated from offset from the end of the string.
string = string.substring(0, (string.length() - 1));
I'm using this in my code, it's easy and simple.
it only works while the String is > 0.
I have it connected to a button and inside the following if statement
if (string.length() > 0) {
string = string.substring(0, (string.length() - 1));
}
public String removeLastChar(String s) {
if (!Util.isEmpty(s)) {
s = s.substring(0, s.length()-1);
}
return s;
}
removes last occurence of the 'xxx':
System.out.println("aaa xxx aaa xxx ".replaceAll("xxx([^xxx]*)$", "$1"));
removes last occurrence of the 'xxx' if it is last:
System.out.println("aaa xxx aaa ".replaceAll("xxx\\s*$", ""));
you can replace the 'xxx' on what you want but watch out on special chars
Look to StringBuilder Class :
StringBuilder sb=new StringBuilder("toto,");
System.out.println(sb.deleteCharAt(sb.length()-1));//display "toto"
// creating StringBuilder
StringBuilder builder = new StringBuilder(requestString);
// removing last character from String
builder.deleteCharAt(requestString.length() - 1);
How can a simple task be made complicated. My solution is:
public String removeLastChar(String s) {
return s[0..-1]
}
or
public String removeLastChar(String s) {
if (s.length() > 0) {
return s[0..-1]
}
return s
}
// Remove n last characters
// System.out.println(removeLast("Hello!!!333",3));
public String removeLast(String mes, int n) {
return mes != null && !mes.isEmpty() && mes.length()>n
? mes.substring(0, mes.length()-n): mes;
}
// Leave substring before character/string
// System.out.println(leaveBeforeChar("Hello!!!123", "1"));
public String leaveBeforeChar(String mes, String last) {
return mes != null && !mes.isEmpty() && mes.lastIndexOf(last)!=-1
? mes.substring(0, mes.lastIndexOf(last)): mes;
}
A one-liner answer (just a funny alternative - do not try this at home, and great answers already given):
public String removeLastChar(String s){return (s != null && s.length() != 0) ? s.substring(0, s.length() - 1): s;}
Most answers here forgot about surrogate pairs.
For instance, the character 𝕫 (codepoint U+1D56B) does not fit into a single char, so in order to be represented, it must form a surrogate pair of two chars.
If one simply applies the currently accepted answer (using str.substring(0, str.length() - 1), one splices the surrogate pair, leading to unexpected results.
One should also include a check whether the last character is a surrogate pair:
public static String removeLastChar(String str) {
Objects.requireNonNull(str, "The string should not be null");
if (str.isEmpty()) {
return str;
}
char lastChar = str.charAt(str.length() - 1);
int cut = Character.isSurrogate(lastChar) ? 2 : 1;
return str.substring(0, str.length() - cut);
}
Java 8
import java.util.Optional;
public class Test
{
public static void main(String[] args) throws InterruptedException
{
System.out.println(removeLastChar("test-abc"));
}
public static String removeLastChar(String s) {
return Optional.ofNullable(s)
.filter(str -> str.length() != 0)
.map(str -> str.substring(0, str.length() - 1))
.orElse(s);
}
}
Output : test-ab
public String removeLastCharacter(String str){
String result = null;
if ((str != null) && (str.length() > 0)) {
return str.substring(0, str.length() - 1);
}
else{
return "";
}
}
if we want to remove file extension of the given file,
** Sample code
public static String removeNCharactersFromLast(String str,int n){
if (str != null && (str.length() > 0)) {
return str.substring(0, str.length() - n);
}
return "";
}
For kotlin check out
string.dropLast(1)
if you have special character like ; in json just use String.replace(";", "") otherwise you must rewrite all character in string minus the last.
Why not use the escape sequence ... !
System.out.println(str + '\b');
Life is much easier now . XD ! ~ A readable one-liner
How to make the char in the recursion at the end:
public static String removeChar(String word, char charToRemove)
{
String char_toremove=Character.toString(charToRemove);
for(int i = 0; i < word.length(); i++)
{
if(word.charAt(i) == charToRemove)
{
String newWord = word.substring(0, i) + word.substring(i + 1);
return removeChar(newWord,charToRemove);
}
}
System.out.println(word);
return word;
}
for exemple:
removeChar ("hello world, let's go!",'l') → "heo word, et's go!llll"
removeChar("you should not go",'o') → "yu shuld nt goooo"
Here's an answer that works with codepoints outside of the Basic Multilingual Plane (Java 8+).
Using streams:
public String method(String str) {
return str.codePoints()
.limit(str.codePoints().count() - 1)
.mapToObj(i->new String(Character.toChars(i)))
.collect(Collectors.joining());
}
More efficient maybe:
public String method(String str) {
return str.isEmpty()? "": str.substring(0, str.length() - Character.charCount(str.codePointBefore(str.length())));
}
just replace the condition of "if" like this:
if(a.substring(a.length()-1).equals("x"))'
this will do the trick for you.
Suppose total length of my string=24
I want to cut last character after position 14 to end, mean I want starting 14 to be there.
So I apply following solution.
String date = "2019-07-31T22:00:00.000Z";
String result = date.substring(0, date.length() - 14);
I had to write code for a similar problem. One way that I was able to solve it used a recursive method of coding.
static String removeChar(String word, char charToRemove)
{
for(int i = 0; i < word.lenght(); i++)
{
if(word.charAt(i) == charToRemove)
{
String newWord = word.substring(0, i) + word.substring(i + 1);
return removeChar(newWord, charToRemove);
}
}
return word;
}
Most of the code I've seen on this topic doesn't use recursion so hopefully I can help you or someone who has the same problem.