Java: Simple Recursion Issue - java

I'm extremely new to the whole idea of recursion, and it's blowing my mind a bit to be honest. I'm trying to turn this function I wrote into a recursive one...
public static int to_number(String s)
{
int total = 0;
int n=s.length();
for(int i = 0 ; i < n ; i++) {
char c = s.charAt(i);
if (Character.isDigit(c)){
int value=Character.getNumericValue(c);
total +=value;
}
}
System.out.println(total);
return total;
}
It reads in a string, such as "3aaa6a3", iterates through the string, if the char is a digit, it adds it to total, and so on. What I have so far...
public static int to_number(String s)
{
int total = 0;
int n=s.length();
int i=0;
if (i == n){
return 0; //if gone through the whole string
}
char c = s.charAt(i);
if (Character.isDigit(c)){
int value=Character.getNumericValue(c);
total +=value;
}
System.out.println(total);
i++;
to_number(); //trying to call the same function
return total;
}
I feel like I'm close, but just not getting it. Thanks for your time and effort!

Not gonna give you the code, but as a recursive function, you want to process the first character of the input string, then call yourself with the remaining string, i.e. to_number(s.substring(1)), and combine the result. Recursion ends when input string is empty.

try this
public void intToNum(String s, int total[])
{
if(s.isEmpty())
return;
char c = s.charAt(0);
if (Character.isDigit(c)){
int value=Character.getNumericValue(c);
total[0] +=value;
}
intToNum(s.substring(1),total);
}
and in your main, call the function as
int [] total = new int[1];
intToNum(input,total);
System.out.println(total[0]);
or another approach is
public int intToNum(String s)
{
if(s.isEmpty())
return 0;
char c = s.charAt(0);
if (Character.isDigit(c)){
int value=Character.getNumericValue(c);
return value + intToNum(s.substring(1));
}
return intToNum(s.substring(1));
}

This answer contains the solution. Just look at it when you are stuck. I also encourage you to read and understand the code instead of just copying it. This is one of the most important concepts in programming, so make sure you understand it and are familiar with it. :)
How it works: The method receives a string. If the string is longer than 1 character, the method splits it in half, calls itself on the two substrings and adds the two results. Those calls will do the same thing, until the string fragments are only 1 (or 0) characters long. In that case, it just returns their value (or 0, if there is no value).
public class RecursionVsIteration {
public static void main(String[] args) {
String str = "2.938fyfh0293urhp2398rpod8723uoihr98y";
System.out.println("Iterative: " + toNumberIterative(str));
System.out.println("Recursive: " + toNumberRecursive(str));
}
public static int toNumberIterative(String s) {
int total = 0;
int n = s.length();
for (int i = 0; i < n; i++) {
char c = s.charAt(i);
if (Character.isDigit(c)) {
int value = Character.getNumericValue(c);
total += value;
}
}
return total;
}
public static int toNumberRecursive(String s) {
int n = s.length();
// termination criteria
if (n == 0) { // emtpy string
return 0;
}
if (n == 1) { // on character string
char c = s.charAt(0);
return Character.isDigit(c) ? Character.getNumericValue(c) : 0;
}
// recursive call (split the string in half and call the method on both substrings)
return toNumberRecursive(s.substring(0, n / 2)) + toNumberRecursive(s.substring(n / 2, n));
}
}

Related

The method repeat (int ) is indefined for string type [duplicate]

I'm looking for a simple commons method or operator that allows me to repeat some string n times. I know I could write this using a for loop, but I wish to avoid for loops whenever necessary and a simple direct method should exist somewhere.
String str = "abc";
String repeated = str.repeat(3);
repeated.equals("abcabcabc");
Related to:
repeat string javascript
Create NSString by repeating another string a given number of times
Edited
I try to avoid for loops when they are not completely necessary because:
They add to the number of lines of code even if they are tucked away in another function.
Someone reading my code has to figure out what I am doing in that for loop. Even if it is commented and has meaningful variables names, they still have to make sure it is not doing anything "clever".
Programmers love to put clever things in for loops, even if I write it to "only do what it is intended to do", that does not preclude someone coming along and adding some additional clever "fix".
They are very often easy to get wrong. For loops involving indexes tend to generate off by one bugs.
For loops often reuse the same variables, increasing the chance of really hard to find scoping bugs.
For loops increase the number of places a bug hunter has to look.
Here is the shortest version (Java 1.5+ required):
repeated = new String(new char[n]).replace("\0", s);
Where n is the number of times you want to repeat the string and s is the string to repeat.
No imports or libraries needed.
If you are using Java <= 7, this is as "concise" as it gets:
// create a string made up of n copies of string s
String.format("%0" + n + "d", 0).replace("0", s);
In Java 8 and above there is a more readable way:
// create a string made up of n copies of string s
String.join("", Collections.nCopies(n, s));
Finally, for Java 11 and above, there is a new repeat​(int count) method specifically for this purpose(link)
"abc".repeat(12);
Alternatively, if your project uses java libraries there are more options.
For Apache Commons:
StringUtils.repeat("abc", 12);
For Google Guava:
Strings.repeat("abc", 12);
String::repeat
". ".repeat(7) // Seven period-with-space pairs: . . . . . . .
New in Java 11 is the method String::repeat that does exactly what you asked for:
String str = "abc";
String repeated = str.repeat(3);
repeated.equals("abcabcabc");
Its Javadoc says:
/**
* Returns a string whose value is the concatenation of this
* string repeated {#code count} times.
* <p>
* If this string is empty or count is zero then the empty
* string is returned.
*
* #param count number of times to repeat
*
* #return A string composed of this string repeated
* {#code count} times or the empty string if this
* string is empty or count is zero
*
* #throws IllegalArgumentException if the {#code count} is
* negative.
*
* #since 11
*/
Commons Lang StringUtils.repeat()
Usage:
String str = "abc";
String repeated = StringUtils.repeat(str, 3);
repeated.equals("abcabcabc");
Java 8's String.join provides a tidy way to do this in conjunction with Collections.nCopies:
// say hello 100 times
System.out.println(String.join("", Collections.nCopies(100, "hello")));
Here's a way to do it using only standard String functions and no explicit loops:
// create a string made up of n copies of s
repeated = String.format(String.format("%%%ds", n), " ").replace(" ",s);
If you're like me and want to use Google Guava and not Apache Commons. You can use the repeat method in the Guava Strings class.
Strings.repeat("-", 60);
With java-8, you can also use Stream.generate.
import static java.util.stream.Collectors.joining;
...
String repeated = Stream.generate(() -> "abc").limit(3).collect(joining()); //"abcabcabc"
and you can wrap it in a simple utility method if needed:
public static String repeat(String str, int times) {
return Stream.generate(() -> str).limit(times).collect(joining());
}
So you want to avoid loops?
Here you have it:
public static String repeat(String s, int times) {
if (times <= 0) return "";
else return s + repeat(s, times-1);
}
(of course I know this is ugly and inefficient, but it doesn't have loops :-p)
You want it simpler and prettier? use jython:
s * 3
Edit: let's optimize it a little bit :-D
public static String repeat(String s, int times) {
if (times <= 0) return "";
else if (times % 2 == 0) return repeat(s+s, times/2);
else return s + repeat(s+s, times/2);
}
Edit2: I've done a quick and dirty benchmark for the 4 main alternatives, but I don't have time to run it several times to get the means and plot the times for several inputs... So here's the code if anybody wants to try it:
public class Repeat {
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
String s = args[1];
int l = s.length();
long start, end;
start = System.currentTimeMillis();
for (int i = 0; i < n; i++) {
if(repeatLog2(s,i).length()!=i*l) throw new RuntimeException();
}
end = System.currentTimeMillis();
System.out.println("RecLog2Concat: " + (end-start) + "ms");
start = System.currentTimeMillis();
for (int i = 0; i < n; i++) {
if(repeatR(s,i).length()!=i*l) throw new RuntimeException();
}
end = System.currentTimeMillis();
System.out.println("RecLinConcat: " + (end-start) + "ms");
start = System.currentTimeMillis();
for (int i = 0; i < n; i++) {
if(repeatIc(s,i).length()!=i*l) throw new RuntimeException();
}
end = System.currentTimeMillis();
System.out.println("IterConcat: " + (end-start) + "ms");
start = System.currentTimeMillis();
for (int i = 0; i < n; i++) {
if(repeatSb(s,i).length()!=i*l) throw new RuntimeException();
}
end = System.currentTimeMillis();
System.out.println("IterStrB: " + (end-start) + "ms");
}
public static String repeatLog2(String s, int times) {
if (times <= 0) {
return "";
}
else if (times % 2 == 0) {
return repeatLog2(s+s, times/2);
}
else {
return s + repeatLog2(s+s, times/2);
}
}
public static String repeatR(String s, int times) {
if (times <= 0) {
return "";
}
else {
return s + repeatR(s, times-1);
}
}
public static String repeatIc(String s, int times) {
String tmp = "";
for (int i = 0; i < times; i++) {
tmp += s;
}
return tmp;
}
public static String repeatSb(String s, int n) {
final StringBuilder sb = new StringBuilder();
for(int i = 0; i < n; i++) {
sb.append(s);
}
return sb.toString();
}
}
It takes 2 arguments, the first is the number of iterations (each function run with repeat times arg from 1..n) and the second is the string to repeat.
So far, a quick inspection of the times running with different inputs leaves the ranking something like this (better to worse):
Iterative StringBuilder append (1x).
Recursive concatenation log2 invocations (~3x).
Recursive concatenation linear invocations (~30x).
Iterative concatenation linear (~45x).
I wouldn't ever guessed that the recursive function was faster than the for loop :-o
Have fun(ctional xD).
This contains less characters than your question
public static String repeat(String s, int n) {
if(s == null) {
return null;
}
final StringBuilder sb = new StringBuilder(s.length() * n);
for(int i = 0; i < n; i++) {
sb.append(s);
}
return sb.toString();
}
based on fortran's answer, this is a recusive version that uses a StringBuilder:
public static void repeat(StringBuilder stringBuilder, String s, int times) {
if (times > 0) {
repeat(stringBuilder.append(s), s, times - 1);
}
}
public static String repeat(String s, int times) {
StringBuilder stringBuilder = new StringBuilder(s.length() * times);
repeat(stringBuilder, s, times);
return stringBuilder.toString();
}
using Dollar is simple as typing:
#Test
public void repeatString() {
String string = "abc";
assertThat($(string).repeat(3).toString(), is("abcabcabc"));
}
PS: repeat works also for array, List, Set, etc
I wanted a function to create a comma-delimited list of question marks for JDBC purposes, and found this post. So, I decided to take two variants and see which one performed better. After 1 million iterations, the garden-variety StringBuilder took 2 seconds (fun1), and the cryptic supposedly more optimal version (fun2) took 30 seconds. What's the point of being cryptic again?
private static String fun1(int size) {
StringBuilder sb = new StringBuilder(size * 2);
for (int i = 0; i < size; i++) {
sb.append(",?");
}
return sb.substring(1);
}
private static String fun2(int size) {
return new String(new char[size]).replaceAll("\0", ",?").substring(1);
}
OOP Solution
Nearly every answer proposes a static function as a solution, but thinking Object-Oriented (for reusability-purposes and clarity) I came up with a Solution via Delegation through the CharSequence-Interface (which also opens up usability on mutable CharSequence-Classes).
The following Class can be used either with or without Separator-String/CharSequence and each call to "toString()" builds the final repeated String.
The Input/Separator are not only limited to String-Class, but can be every Class which implements CharSequence (e.g. StringBuilder, StringBuffer, etc)!
Source-Code:
/**
* Helper-Class for Repeating Strings and other CharSequence-Implementations
* #author Maciej Schuttkowski
*/
public class RepeatingCharSequence implements CharSequence {
final int count;
CharSequence internalCharSeq = "";
CharSequence separator = "";
/**
* CONSTRUCTOR - RepeatingCharSequence
* #param input CharSequence to repeat
* #param count Repeat-Count
*/
public RepeatingCharSequence(CharSequence input, int count) {
if(count < 0)
throw new IllegalArgumentException("Can not repeat String \""+input+"\" less than 0 times! count="+count);
if(count > 0)
internalCharSeq = input;
this.count = count;
}
/**
* CONSTRUCTOR - Strings.RepeatingCharSequence
* #param input CharSequence to repeat
* #param count Repeat-Count
* #param separator Separator-Sequence to use
*/
public RepeatingCharSequence(CharSequence input, int count, CharSequence separator) {
this(input, count);
this.separator = separator;
}
#Override
public CharSequence subSequence(int start, int end) {
checkBounds(start);
checkBounds(end);
int subLen = end - start;
if (subLen < 0) {
throw new IndexOutOfBoundsException("Illegal subSequence-Length: "+subLen);
}
return (start == 0 && end == length()) ? this
: toString().substring(start, subLen);
}
#Override
public int length() {
//We return the total length of our CharSequences with the separator 1 time less than amount of repeats:
return count < 1 ? 0
: ( (internalCharSeq.length()*count) + (separator.length()*(count-1)));
}
#Override
public char charAt(int index) {
final int internalIndex = internalIndex(index);
//Delegate to Separator-CharSequence or Input-CharSequence depending on internal index:
if(internalIndex > internalCharSeq.length()-1) {
return separator.charAt(internalIndex-internalCharSeq.length());
}
return internalCharSeq.charAt(internalIndex);
}
#Override
public String toString() {
return count < 1 ? ""
: new StringBuilder(this).toString();
}
private void checkBounds(int index) {
if(index < 0 || index >= length())
throw new IndexOutOfBoundsException("Index out of Bounds: "+index);
}
private int internalIndex(int index) {
// We need to add 1 Separator-Length to total length before dividing,
// as we subtracted one Separator-Length in "length()"
return index % ((length()+separator.length())/count);
}
}
Usage-Example:
public static void main(String[] args) {
//String input = "12345";
//StringBuffer input = new StringBuffer("12345");
StringBuilder input = new StringBuilder("123");
//String separator = "<=>";
StringBuilder separator = new StringBuilder("<=");//.append('>');
int repeatCount = 2;
CharSequence repSeq = new RepeatingCharSequence(input, repeatCount, separator);
String repStr = repSeq.toString();
System.out.println("Repeat="+repeatCount+"\tSeparator="+separator+"\tInput="+input+"\tLength="+input.length());
System.out.println("CharSeq:\tLength="+repSeq.length()+"\tVal="+repSeq);
System.out.println("String :\tLength="+repStr.length()+"\tVal="+repStr);
//Here comes the Magic with a StringBuilder as Input, as you can append to the String-Builder
//and at the same Time your Repeating-Sequence's toString()-Method returns the updated String :)
input.append("ff");
System.out.println(repSeq);
//Same can be done with the Separator:
separator.append("===").append('>');
System.out.println(repSeq);
}
Example-Output:
Repeat=2 Separator=<= Input=123 Length=3
CharSeq: Length=8 Val=123<=123
String : Length=8 Val=123<=123
123ff<=123ff
123ff<====>123ff
using only JRE classes (System.arraycopy) and trying to minimize the number of temp objects you can write something like:
public static String repeat(String toRepeat, int times) {
if (toRepeat == null) {
toRepeat = "";
}
if (times < 0) {
times = 0;
}
final int length = toRepeat.length();
final int total = length * times;
final char[] src = toRepeat.toCharArray();
char[] dst = new char[total];
for (int i = 0; i < total; i += length) {
System.arraycopy(src, 0, dst, i, length);
}
return String.copyValueOf(dst);
}
EDIT
and without loops you can try with:
public static String repeat2(String toRepeat, int times) {
if (toRepeat == null) {
toRepeat = "";
}
if (times < 0) {
times = 0;
}
String[] copies = new String[times];
Arrays.fill(copies, toRepeat);
return Arrays.toString(copies).
replace("[", "").
replace("]", "").
replaceAll(", ", "");
}
EDIT 2
using Collections is even shorter:
public static String repeat3(String toRepeat, int times) {
return Collections.nCopies(times, toRepeat).
toString().
replace("[", "").
replace("]", "").
replaceAll(", ", "");
}
however I still like the first version.
Not the shortest, but (i think) the fastest way is to use the StringBuilder:
/**
* Repeat a String as many times you need.
*
* #param i - Number of Repeating the String.
* #param s - The String wich you want repeated.
* #return The string n - times.
*/
public static String repeate(int i, String s) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < i; j++)
sb.append(s);
return sb.toString();
}
If speed is your concern, then you should use as less memory copying as possible. Thus it is required to work with arrays of chars.
public static String repeatString(String what, int howmany) {
char[] pattern = what.toCharArray();
char[] res = new char[howmany * pattern.length];
int length = pattern.length;
for (int i = 0; i < howmany; i++)
System.arraycopy(pattern, 0, res, i * length, length);
return new String(res);
}
To test speed, a similar optimal method using StirngBuilder is like this:
public static String repeatStringSB(String what, int howmany) {
StringBuilder out = new StringBuilder(what.length() * howmany);
for (int i = 0; i < howmany; i++)
out.append(what);
return out.toString();
}
and the code to test it:
public static void main(String... args) {
String res;
long time;
for (int j = 0; j < 1000; j++) {
res = repeatString("123", 100000);
res = repeatStringSB("123", 100000);
}
time = System.nanoTime();
res = repeatString("123", 1000000);
time = System.nanoTime() - time;
System.out.println("elapsed repeatString: " + time);
time = System.nanoTime();
res = repeatStringSB("123", 1000000);
time = System.nanoTime() - time;
System.out.println("elapsed repeatStringSB: " + time);
}
And here the run results from my system:
elapsed repeatString: 6006571
elapsed repeatStringSB: 9064937
Note that the test for loop is to kick in JIT and have optimal results.
a straightforward one-line solution:
requires Java 8
Collections.nCopies( 3, "abc" ).stream().collect( Collectors.joining() );
for the sake of readability and portability:
public String repeat(String str, int count){
if(count <= 0) {return "";}
return new String(new char[count]).replace("\0", str);
}
If you are worried about performance, just use a StringBuilder inside the loop and do a .toString() on exit of the Loop. Heck, write your own Util Class and reuse it. 5 Lines of code max.
I really enjoy this question. There is a lot of knowledge and styles. So I can't leave it without show my rock and roll ;)
{
String string = repeat("1234567890", 4);
System.out.println(string);
System.out.println("=======");
repeatWithoutCopySample(string, 100000);
System.out.println(string);// This take time, try it without printing
System.out.println(string.length());
}
/**
* The core of the task.
*/
#SuppressWarnings("AssignmentToMethodParameter")
public static char[] repeat(char[] sample, int times) {
char[] r = new char[sample.length * times];
while (--times > -1) {
System.arraycopy(sample, 0, r, times * sample.length, sample.length);
}
return r;
}
/**
* Java classic style.
*/
public static String repeat(String sample, int times) {
return new String(repeat(sample.toCharArray(), times));
}
/**
* Java extreme memory style.
*/
#SuppressWarnings("UseSpecificCatch")
public static void repeatWithoutCopySample(String sample, int times) {
try {
Field valueStringField = String.class.getDeclaredField("value");
valueStringField.setAccessible(true);
valueStringField.set(sample, repeat((char[]) valueStringField.get(sample), times));
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
Do you like it?
public static String repeat(String str, int times) {
int length = str.length();
int size = length * times;
char[] c = new char[size];
for (int i = 0; i < size; i++) {
c[i] = str.charAt(i % length);
}
return new String(c);
}
Simple loop
public static String repeat(String string, int times) {
StringBuilder out = new StringBuilder();
while (times-- > 0) {
out.append(string);
}
return out.toString();
}
Try this out:
public static char[] myABCs = {'a', 'b', 'c'};
public static int numInput;
static Scanner in = new Scanner(System.in);
public static void main(String[] args) {
System.out.print("Enter Number of Times to repeat: ");
numInput = in.nextInt();
repeatArray(numInput);
}
public static int repeatArray(int y) {
for (int a = 0; a < y; a++) {
for (int b = 0; b < myABCs.length; b++) {
System.out.print(myABCs[b]);
}
System.out.print(" ");
}
return y;
}
Using recursion, you can do the following (using ternary operators, one line max):
public static final String repeat(String string, long number) {
return number == 1 ? string : (number % 2 == 0 ? repeat(string + string, number / 2) : string + repeat(string + string, (number - 1) / 2));
}
I know, it's ugly and probably not efficient, but it's one line!
If you only know the length of the output string (and it may be not divisible by the length of the input string), then use this method:
static String repeat(String s, int length) {
return s.length() >= length ? s.substring(0, length) : repeat(s + s, length);
}
Usage demo:
for (int i = 0; i < 50; i++)
System.out.println(repeat("_/‾\\", i));
Don't use with empty s and length > 0, since it's impossible to get the desired result in this case.
Despite your desire not to use loops, I think you should use a loop.
String repeatString(String s, int repetitions)
{
if(repetitions < 0) throw SomeException();
else if(s == null) return null;
StringBuilder stringBuilder = new StringBuilder(s.length() * repetitions);
for(int i = 0; i < repetitions; i++)
stringBuilder.append(s);
return stringBuilder.toString();
}
Your reasons for not using a for loop are not good ones. In response to your criticisms:
Whatever solution you use will almost certainly be longer than this. Using a pre-built function only tucks it under more covers.
Someone reading your code will have to figure out what you're doing in that non-for-loop. Given that a for-loop is the idiomatic way to do this, it would be much easier to figure out if you did it with a for loop.
Yes someone might add something clever, but by avoiding a for loop you are doing something clever. That's like shooting yourself in the foot intentionally to avoid shooting yourself in the foot by accident.
Off-by-one errors are also mind-numbingly easy to catch with a single test. Given that you should be testing your code, an off-by-one error should be easy to fix and catch. And it's worth noting: the code above does not contain an off-by-one error. For loops are equally easy to get right.
So don't reuse variables. That's not the for-loop's fault.
Again, so does whatever solution you use. And as I noted before; a bug hunter will probably be expecting you to do this with a for loop, so they'll have an easier time finding it if you use a for loop.
here is the latest Stringutils.java StringUtils.java
public static String repeat(String str, int repeat) {
// Performance tuned for 2.0 (JDK1.4)
if (str == null) {
return null;
}
if (repeat <= 0) {
return EMPTY;
}
int inputLength = str.length();
if (repeat == 1 || inputLength == 0) {
return str;
}
if (inputLength == 1 && repeat <= PAD_LIMIT) {
return repeat(str.charAt(0), repeat);
}
int outputLength = inputLength * repeat;
switch (inputLength) {
case 1 :
return repeat(str.charAt(0), repeat);
case 2 :
char ch0 = str.charAt(0);
char ch1 = str.charAt(1);
char[] output2 = new char[outputLength];
for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
output2[i] = ch0;
output2[i + 1] = ch1;
}
return new String(output2);
default :
StringBuilder buf = new StringBuilder(outputLength);
for (int i = 0; i < repeat; i++) {
buf.append(str);
}
return buf.toString();
}
}
it doesn't even need to be this big, can be made into this, and can be copied and pasted
into a utility class in your project.
public static String repeat(String str, int num) {
int len = num * str.length();
StringBuilder sb = new StringBuilder(len);
for (int i = 0; i < times; i++) {
sb.append(str);
}
return sb.toString();
}
So e5, I think the best way to do this would be to simply use the above mentioned code,or any of the answers here. but commons lang is just too big if it's a small project
I created a recursive method that do the same thing you want.. feel free to use this...
public String repeat(String str, int count) {
return count > 0 ? repeat(str, count -1) + str: "";
}
i have the same answer on Can I multiply strings in java to repeat sequences?
public static String rep(int a,String k)
{
if(a<=0)
return "";
else
{a--;
return k+rep(a,k);
}
You can use this recursive method for you desired goal.

Recusion - calculating sum of digits in a mixed string. (homework dead end)

I've got into a dead end while trying to fix some lines
in my code.
The task is writing a Recursion function which takes a string and calculating
the sum of the numbers in it.
For example -
input - "5a-f5-11"
output- The numbers are 5, 5 and 11, therefore the sum is 21.
the Catch in this task is to sum numbers that are more than one digit.
(11 in our case)
I have not planned to use Char arrays or anything, but working with strings in some lines made it difficult.
My code doesn't compile so far but i'm sure the logic is in the right spot - (i made a helper function, which means its not the final function but its doing the main work).
public static int sumNumbersInText(String str, int i, String subStr, int sum) {
if(str.length() >= i) return sum;
char[] array = new char[str.length()];
str.getChars(0, str.length(), array, 0);
char oneStr = array[i];
String newSubStr = subStr;
if(Character.isDigit(oneStr)); //if the new index is not a number and the index before IS a number>
{
if(Character.isDigit(subStr));// new index IS a number, therefore will sum up.
{
int num = 0;
sum+=num;
newSubStr = "";
}
}
else
{
newSubStr += oneStr;
}
return sumNumbersInText(str, i+1, subStr, sum);
}
This is how I'd approach it:
public class AddMultipleDigitsInStringRecursive
{
public static void main(String[] args)
{
String input = "5a-f5-11";
System.out.println("Input: " + input);
int sum = sumDigits(input);
System.out.println("Sum: " + sum);
}
public static int sumDigits(String input)
{
return addDigits(input, 0, "");
}
private static int addDigits(String input, int index, String curNumber)
{
if(index < input.length())
{
int curSum = 0;
String curChar = input.substring(index, index + 1); // get the current character (as a String)
if (Character.isDigit(curChar.charAt(0))) // if it's a digit, append it to the current number
{
curNumber = curNumber + curChar;
}
else // it's not a digit, do we have a number pending?
{
if (!curNumber.isEmpty())
{
curSum = Integer.parseInt(curNumber); // convert current number to an Integer
}
curNumber = ""; // reset the current number so we can accumulate more digits when they are found
}
// return the sum of the current number (if any) with any other numbers that are found
return curSum + addDigits(input, index + 1, curNumber);
}
else // reached the end of the string; was there a number pending?
{
int curSum = 0;
if (!curNumber.isEmpty())
{
curSum = Integer.parseInt(curNumber);
}
return curSum;
}
}
}
Somehow managed to figure it out, it actually works:
public static int sum(String str, int i, String subStr, int sum) {
if(str.length() <= i) return sum;
String newSubStr = subStr;
char oneStr = str.charAt(i);
if(!Character.isDigit(oneStr)) //if the new index is not a number and the index before IS a number>
{
if(isNumeric(subStr))// new index IS a number, therefore will sum up.
{
int num = Integer.parseInt(subStr);
sum+=num;
newSubStr = "";
}
}
else
{
String temp = oneStr+"";
newSubStr += temp;
}
System.out.println(sum);
return sum(str, i+1, newSubStr, sum);
}
Well, here is one simple way of using recursion to solve the problem. I used a regular expression to grab the numbers since you didn't indicate that it was not permitted.
public static int sum(String a) {
Matcher m = Pattern.compile("(\\d\\d+)").matcher(a);
if (m.find()) {
return Integer.parseInt(m.group(1)) + sum(a.substring(m.end()));
}
return 0;
}

How to use a recursive method to return the sum of digits in a String?

So I have a question that asks me to write a method that is passed a String consisting of digits, and this method should return the sum of those digits. So if the String is "123" my method should return the value 6. If the null String is passed, my method should return zero. It asks me to use Recursion. Here's what I have so far:
public class Q2 {
public static void main(String[] args) {
String s = "135";
System.out.println(sumDig(s));
}
public static String sumDig(int num)
{
int i = Integer.parseInt(num);
int sum = 0;
if (i == 0)
return sum;
int sum = num%10 + sumDig(num/10);
return sum;
}
}
I'm just having a bit of trouble trying to see if I'm on the right track, I know it's totally wonky and recursion is still really odd to me so any help is really appreciated. Thank you!
Edit: I don't think this is a duplicate of any other problems asking how to find sum of digits using recursion, this is very similar but it's different because it asks to find sum of digits from a String.
The key issue that folks are pointing out is that you've inverted your method signature:
public static String sumDig(int num)
which should be:
public static int sumDig(String num)
Let's also address another issue in that you took data that you could process directly, made it into something else more complicated, and processed that instead. Let's operate directly on what you are handed:
public class Q2 {
public static int sumDig(String digits) {
int sum = 0;
if (! digits.isEmpty()) {
sum += Character.getNumericValue(digits.charAt(0)) + sumDig(digits.substring(1));
}
return sum;
}
public static void main(String[] args) {
System.out.println(sumDig(args[0]));
}
}
USAGE
% java Q2 123
6
%
In the comments below I want you to see the logical and syntactical mistakes you made:
public static String sumDig(int num) {
// the return type should be int and not String
// the parameter num should be String and not int
int i = Integer.parseInt(num);
int sum = 0;
if (i == 0)
return sum;
int sum = num%10 + sumDig(num/10);
// sum has been previously declared as int, so int is not required in the above line
// the number is i and this should be used and not num (which is a String)
// in the calculations
// num/10 cannot be used as a parameter of sumDig because sumDig needs
// a String parameter
return sum;
}
This does not mean that if you make all the proposed corrections that the method will work as expected. For example what happens when the string is null, etc?
// TODO not working with negative numbers
public static int sumDig(String str) {
return str.isEmpty() ? 0 : str.charAt(0) - '0' + sumDig(str.substring(1));
}
public static int sumDig(int num) {
return Math.abs(num) < 10 ? Math.abs(num) : (Math.abs(num) % 10 + sumDig(num / 10));
}
These are three variations of recursive methods, differing by parameter and return type but they all do the same job of adding input number and printing the output.
// Recursive method where parameter is int and return type String
public static String getSumStr(int n) {
n = n < 0 ? -n : n; // takes care of negative numbers
if (n < 10) {
return String.valueOf(n);
}
return String.valueOf(n % 10 + Integer.parseInt(getSumStr(n / 10)));
}
// Recursive method where parameter and return type both are int
public static int getSum(int n) {
n = n < 0 ? -n : n; // takes care of negative numbers
return n < 10 ? n : (n % 10 + getSum(n / 10));
}
// Recursive method where parameter and return type both are String
public static String getSumStr(String s) {
if (s == null || s.length() == 0) {
return "0";
}
if (s.length() == 1) {
return s;
}
return String.valueOf(Integer.parseInt(s.substring(0, 1))
+ Integer.parseInt(getSumStr(s.substring(1, s.length()))));
}
Assuming the String is all digits, the below works with String of length longer than Integer.MAX_VALUE
public static void main(String[] args) {
String s = "123344566777766545";
long i = sumDig(s);
System.out.println(i);
}
public long sumDig(String s) {
return sumDigits(s.toCharArray(), 0);
}
public long sumDigits(char[] chars, int index) {
if (index == chars.length - 1) {
return chars[index] - '0';
}
return sumDigits(chars, index + 1) + (chars[index] - '0');
}
I'll give you a hint: what would happen if you did a for loop over the characters in the string and added the digits up that way? I'd suggest trying to write such a for loop. Here's an example of what I'm talking about (with apologies for it being in C# rather than Java - the syntax is very similar, though):
string s = "123";
int sum = 0;
for (int i = 0; i < s.Length; i++)
{
sum += int.Parse(s[i].ToString());
}
After that, how would you write a recursive function that's equivalent to the for loop?

Java Method to find the occurencies of a certain character

my code should prompt the user to enter a string and a character, and tell where the character is located
for instance
"Welcome" and "e"
returns
"2, 7"
How can my code be fixed? Code is here. Thanks in advance (this is not homework, but some hint could be useful anyway if you don't want to post a solution).
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.println("Please enter a string and a character");
Scanner input = new Scanner(System.in);
String s = input.nextLine();
char ch = input.next().charAt(0);
System.out.println(count(ch));
}
public static int count (String s, char a) {
int count = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == a) {
count++;
}
}
return count;
}
}
Some mistakes:
Your code doesn't compile. Call:
System.out.println(count(s, ch));
instead of
System.out.println(count(ch));
You count the number of appearances. Instead, you should keep the indexes. You can use a String or you can add them to a list / array and convert it later to what you want.
public static String count(String s, char a) {
String result = "";
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == a) {
result += (i+1) + ", ";
}
}
return result.substring(0, result.length() - 2);
}
I used i+1 instead of i because the indexes start at 0 in Java.
I also returned the string result.substring(0, result.length() - 2) without its last 2 characters, because I added , after every character.
Since Java 8, you can do this by using streams:
public static String count(String s, char a) {
return IntStream.range(0, s.length())
.filter(i -> a == s.charAt(i)).mapToObj(i -> i + "")
.collect(Collectors.joining(", "));
}
This code will print indexes of your Character, seprated by comma.
For more about streams, you can read here, in Java 8 documentation.
Just Change the count method :
public static ArrayList<Integer> count(String s, char a) {
ArrayList<Integer> positions = new ArrayList<>();
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == a) {
positions.add(i+1);
}
}
return positions;
}

Count Character Consecutively in Java

I'm trying to write a method that returns the number of times char c first appears consecutively in s, even if it's a single occurrence of the character. Even spaces break the consecutive count. So the string "I'm bad at programming." should only return 1, if char c was 'a'.
The code below compiles but doesn't print the correct answers. Just something to show my general logic when it comes to approaching this problem.
public class WordCount
{
public int countRun( String s, char c )
{
int counter = 0;
for( int i = 0; i < s.length(); i++)
/*There should be other conditions here that checks for first
appearance consecutively. I've tried my fair share, but no
luck on getting correct results.*/
{
if( s.charAt(i) == c )
{
counter += 1;
}
}
return counter;
}
public static void main( String args[] )
{
WordCount x = new WordCount();
System.out.println( x.countRun( "Add dog", 'd' ) ); //should return 2
System.out.println( x.countRun( "Add dog", 'D' ) ); //should return 0
System.out.println( x.countRun( "Hope you're happy", 'p' )); //should return 1
System.out.println( x.countRun( "CCCCCcccC", 'C' )); //should return 5
}
}
I just need a few pointers (logic-wise or code). Maybe there's a method for Strings that I've never seen before that could make my program much simpler. I have very limited knowledge in programming and in Java.
EDIT: For anyone wondering if this is part of some homework assignment or whatnot, this was a question from a very old midterm. I got it wrong but for some reason but never bothered to ask for the correct answer at the time. I looked at it today and wanted to see if I knew the answer. Looks like I don't.
You could do it in one line:
int result = s.replaceFirst(".*?(" + c + "+).*", "$1").length();
This code uses regex to essentially extract the part of s that is the first contiguous occurrences of c, then gets the length of that.
This will also work for no occurrences, yielding zero.
See live demo.
Add a flag, and break out of the loop when you have found one matching character, then find "anything else". Maybe not the most compact or elegant, but true to the original code. Tested, and produces 2,0,1,5 as expected.
public int countRun( String s, char c )
{
int counter = 0;
boolean foundOne = false;
for( int i = 0; i < s.length(); i++)
{
if( s.charAt(i) == c )
{
counter += 1;
foundOne = true;
}
else {
if(foundOne) break;
}
}
return counter;
}
It occurs to me that counter>0 is an equivalent condition to foundOne==true; that would allow you to simplify the code to:
public int countRun( String s, char c )
{
int counter = 0;
for( int i = 0; i < s.length(); i++)
{
if( s.charAt(i) == c ) counter++;
else if(counter>0) break;
}
return counter;
}
The logic is a tiny bit harder to follow this way, as the variable name foundOne is self-documenting. But per other posts, "small is beautiful" too...
Using assci array counter
public static int countRun(String s, char c) {
int[] counts = new int[256];
int count = 0;
char currChar;
for (int i = 0; i < s.length(); i++) {
currChar = s.charAt(i);
if (currChar == c) {// match
counts[c]++;
} else if (Character.isSpaceChar(currChar)) {
counts[c] = 0;// reset counter for c
} else {// no match
if (counts[c] > 0) {// return accumulated counts if you have
count = counts[c];
return count;
}
}
}
return count;
}
public class A3B2C1 {
public static void main(String[] args) {
String s = "AAABBC";
s = s + '#';//dummy char to consider the last char 'C' in the string
//without using charAt()
int count = 1;
String n="";
int i=0;
StringBuffer bf = new StringBuffer();
char c[] = s.toCharArray();
for(i=0;i< c.length-1;i++)
{
if(c[i] == c[i+1])
{
count++;
}
else
{
n = c[i] +""+count;
bf.append(n);
count=1;
}
}
System.out.println("Output: "+bf);//prints-->> Output: A3B2C1
}
}

Categories