java.lang.OutOfMemoryError: Java heap space and HashMap - java

Sorry to post this code again. Previously the issue was I got a stack overflow error which was fixed by using long instead of int. However for a big value of n, I got a Exception in thread "main" java.lang.OutOfMemoryError: Java heap space.
Question:
Given a positive integer n, prints out the sum of the lengths of the Syracuse
sequence starting in the range of 1 to n inclusive. So, for example, the call:
lengths(3)
will return the the combined length of the sequences:
1
2 1
3 10 5 16 8 4 2 1
which is the value: 11. lengths must throw an IllegalArgumentException if
its input value is less than one.
My Code:
import java.util.*;
public class Test {
HashMap<Long,Integer> syraSumHashTable = new HashMap<Long,Integer>();
public Test(){
}
public int lengths(long n)throws IllegalArgumentException{
int sum =0;
if(n < 1){
throw new IllegalArgumentException("Error!! Invalid Input!");
}
else{
for(int i=1;i<=n;i++){
sum+=getStoreValue(i);
}
return sum;
}
}
private int getStoreValue(long index){
int result = 0;
if(!syraSumHashTable.containsKey(index)){
syraSumHashTable.put(index, printSyra(index,1));
}
result = (Integer)syraSumHashTable.get(index);
return result;
}
public static int printSyra(long num, int count) {
if (num == 1) {
return count;
}
if(num%2==0){
return printSyra(num/2, ++count);
}
else{
return printSyra((num*3)+1, ++count) ;
}
}
}
Since I have to add to the sum of the previous numbers, I will end up Exception in thread "main" java.lang.OutOfMemoryError: Java heap space for a huge value of n. I know the hashtable is suppose to assist in speeding up the calculations. How do I make sure that my recursion method, printSyra can return the value early if it has encountered an element that I have calculated before using the HashMap.
Driver Code:
public static void main(String[] args) {
// TODO Auto-generated method stub
Test t1 = new Test();
System.out.println(t1.lengths(90090249));
//System.out.println(t1.lengths(3));
}

you need to use iterative method instead of recursion. that recursive method will make pressure on the stack trace of the thread.
public static int printSyra(long num, int count) {
if (num == 1) {
return count;
}
while (true) {
if (num == 1) break; else if (num%2 == 0) {num /= 2; count++;) else {num = (num*3) + 1; count++;}
}
return count;
}

Related

Finding the Base 2 Logarithm of a number using Recursion in java

I'm trying to write a recursive method in Java to find the base 2 log for multiples of 2.
I've successfully computed the log using this recursive method.
import java.util.*;
class temp
{
static int log(int number)
{
if(number==1)
return 0;
return log(number/2)+1;
}
public static void main(String s[])
{
Scanner input=new Scanner(System.in);
System.out.println("Enter Multiple of 2:");
System.out.println("Log is:"+log(input.nextInt())); //calling log with return value of nextInt()
}
}
Where I've run aground is trying to implement the same program using a different method , a method where i start multiplying from 2 in recursive calls until it becomes equal to the given number. Here's what i've tried:
class logarithmrecursion
{
static int step=1;
static int log(int number)
{
final int temp=number;
if(number>=temp && step!=1)
return 0;
step++;
return log(number*2)+1;
}
}
During the first call, number is equal to temp so i use a step variable to prevent the execution of the termination condition.If i don't use "number" variable in the recursive call, i don't have a way to accumulate the previous product but number variable is already equal to temp and will trigger the termination condition in the next recursive call , thus always giving output 1.
What can i do to make this program work?
The first, reducing, version has a fixed termination value of 1.
But the second version's termination depends on the number, so you have to pass that into the recursive call. So, your main function calls a private recursive version:
static int log(int number) {
return log(number, 1);
}
private static int log(int number, int current) {
return current < number ? log(number, current * 2) + 1 : 0;
}
Note: Your algorithm rounds the value up. To give the (more expected) rounded down result, which agrees with (int)(Math.log(i) / Math.log(2)), use this variation:
private static int log(int number, int current) {
return current <= number / 2 ? log(number, current * 2) + 1 : 0;
}
This kind of pattern - using a wrapper function - is common where initial state of the recursion needs to setup once, but we don't want to burden the caller with having to know about what is an implementation choice.
Your first method may also be coded as one line:
static int log(int number) {
return number == 1 ? 0 log(number/2) + 1;
}
try this:
import java.util.Scanner;
public class LogTest
{
static int calLog(final int number)
{
if(number < 2) {
return 0;
}
return log(number, 2, 1);
}
static int log(final int number, final int accumulated, final int step)
{
if(accumulated >= number) {
return step;
}
return log(number, accumulated * 2, step+1);
}
public static void main(String s[])
{
Scanner input=new Scanner(System.in);
System.out.println("Enter Multiple of 2:");
System.out.println("Log is:"+calLog(input.nextInt())); //calling log with return value of nextInt()
}
}

CountZeroes in java

I don't know where am I going wrong. I want to count zeroes via recursion but I am not getting it:
public class countzeroes {
public static int countZerosRec(int input){
int count=0;
return countZerosRec(input,count);
}
private static int countZerosRec(int input ,int count){
if (input<0) {
return -1;
}
if(input==0) {
return 1;
}
int m = input%10;
input = input/10;
if(m==0){
count++;
}
countZerosRec(input,count);
return count;
}
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int n = s.nextInt();
System.out.println(countZerosRec(n));
}
}
Put return count in if(input == 0) statement and instead of
countZerosRec(input, count); return count; put return countZerosRec(input, count);.
The correct method would be:
public class countzeroes {
private static int countZerosRec(int input){
if (input<0) {
return -1;
}
if (input==0) {
return 1;
}
if(input < 10) {
return 0;
}
int m = (input%10 == 0)? 1: 0;
input = input/10;
return m + countZerosRec(input);
}
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int n = s.nextInt();
System.out.println(countZerosRec(n));
}
}
Let me explain 2 problems in your code:
1- First of all, your second if statement (if(input == 0)) ruin everything. Consider 1200100 as an example. In the 6th round of recursion the input would be 1, and if you divide it on 10 the result is 0 (which is the input of next recursion round) and therefore all the answers would be 1.
2- Secondly, it would be nice if you don't change the input parameter in your code. because it's completely error-prone (In complicated codes, you can not trace the changes happen on a parameter and it makes debugging hard). So, I just removed the count parameter from the input.
And finally, It is better to name your classes in CamelCase form. (CountZeroes)
Change your method as below. Return count always
private static int countZerosRec(int input ,int count){
if (input <= 0) { // check if input is negative or zero
return count;
}
int m = input % 10;
input = input / 10;
if (m == 0) {
count++; // increment if current digit is zero
}
return countZerosRec(input,count);
}
public static int zeroCount(int num)
{
if(num == 0)
return 0;
if(num %10 ==0)
return 1 + zeroCount(num / 10);
else
return zeroCount(num/10);
}
this would work
You can use Streams:
System.out.println("11020304".chars().filter(c -> c == '0').count());
Result: 3
Your count logic is excellent.
in below line ... you are making logic mistake.. just fix it.
private static int countZerosRec(int input, int count) {
if (input < 0) {
return -1;
}
if (input == 0) {
return count;
//return 1; /// you need to change your code here, in last its getting zero as (num < 10 )/10 is 0
// its entering here everytime, and returning one.
// since its the base condition to exit the recursion.
// for special case of 0 (zero) count, handle your logic when it is //returned.
//...... rest of your code
}

how to count many times a character occurs in a string without using s loop

the code below is meant to count each time character 'x' occurs in a string but it only counts once ..
I do not want to use a loop.
public class recursionJava
{
public static void main(String args[])
{
String names = "xxhixx";
int result = number(names);
System.out.println("number of x: " + result);
}
public static int number (String name)
{
int index = 0, result = 0;
if(name.charAt(index) == 'x')
{
result++;
}
else
{
result = result;
}
index++;
if (name.trim().length() != 0)
{
number(name);
}
return result;
}
}
You could do a replacement/removal of the character and then compare the length of the resulting string:
String names = "xxhixx";
int numX = names.length() - names.replace("x", "").length(); // numX == 4
If you don't want to use a loop, you can use recursion:
public static int number (String name)
{
if (name.length () == 0)
return 0;
int count = name.charAt(0)=='x' ? 1 : 0;
return count + number(name.substring(1));
}
As of Java 8 you can use streams:
"xxhixx".chars().filter(c -> ((char)c)=='x').count()
Previous recursive answer (from Eran) is correct, although it has quadratic complexity in new java versions (substring copies string internally). It can be linear one:
public static int number(String names, int position) {
if (position >= names.length()) {
return 0;
}
int count = number(names, position + 1);
if ('x' == names.charAt(position)) {
count++;
}
return count;
}
Your code does not work because of two things:
Every time you're calling your recursive method number(), you're setting your variables index and result back to zero. So, the program will always be stuck on the first letter and also reset the record of the number of x's it has found so far.
Also, name.trim() is pretty much useless here, because this method only removes whitespace characters such as space, tab etc.
You can solve both of these problems by
making index and result global variables and
using index to check whether or not you have reached the end of the String.
So in the end, a slightly modified (and working) Version of your code would look like this:
public class recursionJava {
private static int index = 0;
private static int result = 0;
public static void main(String[] args) {
String names = "xxhixx";
int result = number(names);
System.out.println("number of x: " + result);
}
public static int number (String name){
if(name.charAt(index) == 'x')
result++;
index++;
if(name.length() - index > 0)
number(name);
return result;
}
}
You can use StringUtils.countMatches
StringUtils.countMatches(name, "x");

What size does of stack does java -xss16M allocate 16 MegaBytes or 16Megabits

I am attempting to prove that I am using tail recursion properly by restricting the size allocated to the thread stack using the java -Xss160M command. I am writing a simple tail recursion algorithm for finding the factorial of a really big numbers:
/*
*
*my Program
*
*/
import java.math.BigInteger;
public class TailFactorial {
private BigInteger factorial(BigInteger n, BigInteger acc) {
if (n.equals(BigInteger.ONE)) return acc;
else return factorial(n.subtract(BigInteger.ONE), n.multiply(acc));
}
public static void main(String[] args) {
// TODO Auto-generated method stub
TailFactorial classs = new TailFactorial();
int num;
BigInteger bigNum = BigInteger.ONE;
boolean gTG = false;
String finalNumString = "";
String msg = "";
try {
num = Integer.parseInt(args[0]);
bigNum = BigInteger.valueOf(num);
msg = "fact("+String.valueOf(num)+") = ";
gTG = true;
}catch(Exception e) {
System.out.println("Could not get arguments, please make sure you are passing an integer");
gTG = false;
}
try {
if(gTG) {
BigInteger finalNum = classs.factorial(bigNum ,BigInteger.ONE);
System.out.println(String.valueOf(finalNum.bitCount()));
finalNumString = finalNum.toString();
//System.out.println( msg + finalNumString);
}
else {
System.out.print("Exiting");
}
}catch(StackOverflowError e) {
System.out.print("Not enough memory allocated to stack, try exicuting with java -Xss$bigger memory inserted here$ TrailFactorial");
}
catch(Exception e) {
System.out.print("Unrecoginzed error in finding factorial");
}
}
}
The code runs just fine, but I have to allocate 50M to the stack. When I run the current program, it displays the bit count of the result. When I find the factorial of one-hundred-thousand the bit count is 708,218, and I still have to use 50M. Can someone explain to me the meaning of the M? is it megabytes or bits? Am I not implementing tail-recursion properly?
As noted; Java doesn't support tail call recursion optimisation so for a large n value you will always run out of stack.
I suggest you use a simple loop if you want to avoid this.
public static BigInteger factorial(int n) {
BigInteger acc = BigInteger.ONE;
for (int i = 2; i <= n; i++)
acc = acc.multiply(BigInteger.valueOf(i));
return acc;
}
If you really, really want to use recursion, you can use divide and conquer
public static BigInteger factorial(int n) {
return product(1, n);
}
public static BigInteger product(int from, int to) {
if (from == to) return BigInteger.valueOf(from);
int mid = (from + to) >>> 1;
return product(from, mid).multiply(product(mid + 1, to));
}
This has a stack depth of log2(n) or a maximum of ~32.
BTW The following code
System.out.println(String.valueOf(finalNum.bitCount()));
finalNumString = finalNum.toString();
System.out.println( msg + finalNumString);
is the same as
System.out.println(finalNum.bitCount());
System.out.println(msg + finalNum);

A number is defined 3Den if it is a multiple of 3 or has the digit 3 in it. Given a number num as input, count the number of 3Den between 1 and num

public int count(int num){
//write your code here
int i;
int counter=0;
for(i=2;i<=num;i++){
if((i%3==0)||(i%10==3)||(i/10==3||(i/100==3)))
counter++;
}
return counter;
}
Sample Input #1
count(15)
Sample Output #1
6 (3,6,9,12,13,15)
Sample Input #2
count(40)
Sample Output #2
21 (3,6,9,12,13,15,18,21,23,24,27,30,31,32,33,34,35,36,37,38,39)
my code passes all test cases within 100 input but fails after 100.what to do?
if((i%3==0) || (i%10==3) || (i/10==3) || (i/100==3) ))
Bad if condition. For example number: 134 is number 3Den, but it will not return true in Your if statement
Hint: You need (for example) to create while loop and use exponent like: ((i / (10^a)) % 10)==3
Approach 2: (less neat) would be changing int i to String and then using String.contains() or String.indexOf()
public class NextMultiple37 {
public static void main(String[] args) {
NextMultiple37 obj = new NextMultiple37();
int result = obj.findNextMultiple(1024);
System.out.println(result);
}
public int findNextMultiple (int num) {
//write your code here
int i=0;
for(i=num+1;i>=num;i++){
if(i%3==0&&i%7==0){
return i;
}
}
return i;
}
}

Categories

Resources